summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt15
-rw-r--r--tools/argdumper/CMakeLists.txt2
-rw-r--r--tools/darwin-debug/CMakeLists.txt2
-rw-r--r--tools/darwin-debug/darwin-debug.cpp2
-rw-r--r--tools/debugserver/CMakeLists.txt3
-rw-r--r--tools/debugserver/debugserver.xcodeproj/project.pbxproj95
-rw-r--r--tools/debugserver/source/CMakeLists.txt196
-rw-r--r--tools/debugserver/source/DNBRegisterInfo.cpp1
-rw-r--r--tools/debugserver/source/JSONGenerator.h6
-rw-r--r--tools/debugserver/source/MacOSX/Genealogy.cpp3
-rw-r--r--tools/debugserver/source/MacOSX/MachException.cpp55
-rw-r--r--tools/debugserver/source/MacOSX/MachProcess.mm16
-rw-r--r--tools/debugserver/source/MacOSX/MachTask.h4
-rw-r--r--tools/debugserver/source/MacOSX/MachThread.cpp4
-rw-r--r--tools/debugserver/source/MacOSX/MachVMRegion.cpp5
-rw-r--r--tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp7
-rw-r--r--tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp7
-rw-r--r--tools/debugserver/source/PThreadMutex.cpp4
-rw-r--r--tools/debugserver/source/RNBRemote.cpp141
-rw-r--r--tools/debugserver/source/RNBServices.cpp6
-rw-r--r--tools/debugserver/source/StdStringExtractor.cpp4
-rw-r--r--tools/debugserver/source/StdStringExtractor.h4
-rw-r--r--tools/debugserver/source/TTYState.h2
-rw-r--r--tools/debugserver/source/debugserver-entitlements.plist2
-rw-r--r--tools/debugserver/source/debugserver.cpp4
-rw-r--r--tools/debugserver/source/libdebugserver.cpp2
-rw-r--r--tools/driver/CMakeLists.txt23
-rw-r--r--tools/driver/Driver.cpp1109
-rw-r--r--tools/driver/Driver.h88
-rw-r--r--tools/driver/Options.td229
-rw-r--r--tools/driver/Platform.h3
-rw-r--r--tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp1
-rw-r--r--tools/intel-features/intel-pt/Decoder.cpp2
-rw-r--r--tools/intel-features/intel-pt/Decoder.h1
-rw-r--r--tools/intel-features/intel-pt/PTDecoder.cpp1
-rw-r--r--tools/intel-features/intel-pt/PTDecoder.h1
-rw-r--r--tools/lldb-mi/CMakeLists.txt4
-rw-r--r--tools/lldb-mi/MICmdArgSet.h4
-rw-r--r--tools/lldb-mi/MICmdArgValBase.cpp4
-rw-r--r--tools/lldb-mi/MICmdArgValBase.h4
-rw-r--r--tools/lldb-mi/MICmdArgValConsume.cpp2
-rw-r--r--tools/lldb-mi/MICmdArgValFile.cpp5
-rw-r--r--tools/lldb-mi/MICmdArgValOptionLong.cpp5
-rw-r--r--tools/lldb-mi/MICmdArgValString.cpp7
-rw-r--r--tools/lldb-mi/MICmdArgValThreadGrp.cpp5
-rw-r--r--tools/lldb-mi/MICmdBase.h6
-rw-r--r--tools/lldb-mi/MICmdCmdBreak.cpp9
-rw-r--r--tools/lldb-mi/MICmdCmdData.cpp4
-rw-r--r--tools/lldb-mi/MICmdCmdGdbInfo.cpp2
-rw-r--r--tools/lldb-mi/MICmdCmdGdbSet.cpp53
-rw-r--r--tools/lldb-mi/MICmdCmdGdbSet.h1
-rw-r--r--tools/lldb-mi/MICmdCmdGdbShow.cpp40
-rw-r--r--tools/lldb-mi/MICmdCmdGdbShow.h1
-rw-r--r--tools/lldb-mi/MICmdCmdTarget.cpp59
-rw-r--r--tools/lldb-mi/MICmdFactory.cpp5
-rw-r--r--tools/lldb-mi/MICmnBase.cpp2
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp8
-rw-r--r--tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp30
-rw-r--r--tools/lldb-mi/MICmnLog.cpp5
-rw-r--r--tools/lldb-mi/MICmnResources.cpp10
-rw-r--r--tools/lldb-mi/MICmnResources.h3
-rw-r--r--tools/lldb-mi/MICmnStreamStdin.cpp2
-rw-r--r--tools/lldb-mi/MIDataTypes.h2
-rw-r--r--tools/lldb-mi/MIDriver.cpp17
-rw-r--r--tools/lldb-mi/MIDriverMain.cpp6
-rw-r--r--tools/lldb-mi/MIDriverMgr.cpp20
-rw-r--r--tools/lldb-mi/MIUtilDebug.cpp19
-rw-r--r--tools/lldb-mi/MIUtilDebug.h1
-rw-r--r--tools/lldb-mi/MIUtilFileStd.cpp2
-rw-r--r--tools/lldb-mi/MIUtilMapIdToVariant.cpp5
-rw-r--r--tools/lldb-mi/MIUtilString.cpp32
-rw-r--r--tools/lldb-server/CMakeLists.txt2
-rw-r--r--tools/lldb-server/SystemInitializerLLGS.cpp9
-rw-r--r--tools/lldb-server/SystemInitializerLLGS.h4
-rw-r--r--tools/lldb-server/lldb-gdbserver.cpp31
-rw-r--r--tools/lldb-server/lldb-platform.cpp7
-rw-r--r--tools/lldb-server/lldb-server.cpp5
-rw-r--r--tools/lldb-test/FormatUtil.cpp47
-rw-r--r--tools/lldb-test/FormatUtil.h27
-rw-r--r--tools/lldb-test/SystemInitializerTest.cpp40
-rw-r--r--tools/lldb-test/SystemInitializerTest.h2
-rw-r--r--tools/lldb-test/lldb-test.cpp290
-rw-r--r--tools/lldb-vscode/BreakpointBase.cpp37
-rw-r--r--tools/lldb-vscode/BreakpointBase.h44
-rw-r--r--tools/lldb-vscode/CMakeLists.txt34
-rw-r--r--tools/lldb-vscode/ExceptionBreakpoint.cpp32
-rw-r--r--tools/lldb-vscode/ExceptionBreakpoint.h38
-rw-r--r--tools/lldb-vscode/FunctionBreakpoint.cpp28
-rw-r--r--tools/lldb-vscode/FunctionBreakpoint.h29
-rw-r--r--tools/lldb-vscode/JSONUtils.cpp892
-rw-r--r--tools/lldb-vscode/JSONUtils.h438
-rw-r--r--tools/lldb-vscode/LLDBUtils.cpp98
-rw-r--r--tools/lldb-vscode/LLDBUtils.h170
-rw-r--r--tools/lldb-vscode/README.md195
-rw-r--r--tools/lldb-vscode/SourceBreakpoint.cpp27
-rw-r--r--tools/lldb-vscode/SourceBreakpoint.h39
-rw-r--r--tools/lldb-vscode/SourceReference.h33
-rw-r--r--tools/lldb-vscode/VSCode.cpp349
-rw-r--r--tools/lldb-vscode/VSCode.h146
-rw-r--r--tools/lldb-vscode/VSCodeForward.h47
-rw-r--r--tools/lldb-vscode/lldb-vscode-Info.plist21
-rw-r--r--tools/lldb-vscode/lldb-vscode.cpp2706
-rw-r--r--tools/lldb-vscode/package.json242
103 files changed, 7072 insertions, 1471 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 75c9c15c487d..8be67393bef0 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,12 +1,15 @@
+add_subdirectory(argdumper)
+add_subdirectory(driver)
+add_subdirectory(intel-features)
+add_subdirectory(lldb-mi)
+add_subdirectory(lldb-test)
+add_subdirectory(lldb-vscode)
+
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
add_subdirectory(darwin-debug)
add_subdirectory(debugserver)
endif()
-add_subdirectory(argdumper)
-add_subdirectory(driver)
-add_subdirectory(lldb-mi)
-if (LLDB_CAN_USE_LLDB_SERVER)
+
+if (LLDB_CAN_USE_LLDB_SERVER AND NOT SKIP_LLDB_SERVER_BUILD)
add_subdirectory(lldb-server)
endif()
-add_subdirectory(intel-features)
-add_subdirectory(lldb-test)
diff --git a/tools/argdumper/CMakeLists.txt b/tools/argdumper/CMakeLists.txt
index a59a4e7a8514..71c73cc195c2 100644
--- a/tools/argdumper/CMakeLists.txt
+++ b/tools/argdumper/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_lldb_tool(lldb-argdumper INCLUDE_IN_SUITE
+add_lldb_tool(lldb-argdumper
argdumper.cpp
LINK_LIBS
diff --git a/tools/darwin-debug/CMakeLists.txt b/tools/darwin-debug/CMakeLists.txt
index c2b5cb486483..5be6e4ee4598 100644
--- a/tools/darwin-debug/CMakeLists.txt
+++ b/tools/darwin-debug/CMakeLists.txt
@@ -1,3 +1,3 @@
-add_lldb_tool(darwin-debug INCLUDE_IN_SUITE
+add_lldb_tool(darwin-debug
darwin-debug.cpp
)
diff --git a/tools/darwin-debug/darwin-debug.cpp b/tools/darwin-debug/darwin-debug.cpp
index e754ded474c4..31b04bcde9be 100644
--- a/tools/darwin-debug/darwin-debug.cpp
+++ b/tools/darwin-debug/darwin-debug.cpp
@@ -24,7 +24,7 @@
//----------------------------------------------------------------------
#if defined(__APPLE__)
-#include <crt_externs.h> // for _NSGetEnviron()
+#include <crt_externs.h>
#include <getopt.h>
#include <limits.h>
#include <mach/machine.h>
diff --git a/tools/debugserver/CMakeLists.txt b/tools/debugserver/CMakeLists.txt
index ae436b8f07c3..1dc32434ba40 100644
--- a/tools/debugserver/CMakeLists.txt
+++ b/tools/debugserver/CMakeLists.txt
@@ -8,8 +8,9 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
"${CMAKE_SOURCE_DIR}/../../cmake"
"${CMAKE_SOURCE_DIR}/../../cmake/modules"
)
-
+
include(LLDBStandalone)
+ include(debugserverConfig)
include(AddLLDB)
set(LLDB_SOURCE_DIR "${CMAKE_SOURCE_DIR}/../../")
diff --git a/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/tools/debugserver/debugserver.xcodeproj/project.pbxproj
index 92b41b1873ab..f4267b7633a2 100644
--- a/tools/debugserver/debugserver.xcodeproj/project.pbxproj
+++ b/tools/debugserver/debugserver.xcodeproj/project.pbxproj
@@ -710,12 +710,9 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)";
LLDB_USE_OS_LOG = 0;
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "";
STRIP_INSTALLED_PRODUCT = NO;
@@ -749,13 +746,10 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)";
LLDB_USE_OS_LOG = 0;
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "";
STRIPFLAGS = "-x";
@@ -790,12 +784,9 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)";
LLDB_USE_OS_LOG = 1;
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
OTHER_CFLAGS = "";
STRIPFLAGS = "-x";
STRIP_STYLE = debugging;
@@ -828,20 +819,15 @@
HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
INSTALL_PATH = /usr/bin;
"INSTALL_PATH[sdk=iphoneos*]" = /Developer/usr/bin/;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_DEBUGSERVER = 1;
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=*internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
OTHER_CFLAGS = (
"-Wparentheses",
"$(LLDB_ENERGY_CFLAGS)",
"-DDT_VARIANT_$(DT_VARIANT)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*]" = (
@@ -851,8 +837,6 @@
"-DWITH_BKS",
"-DOS_OBJECT_USE_OBJC=0",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
"-isystem",
"$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
@@ -871,7 +855,6 @@
MobileCoreServices,
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
@@ -880,7 +863,6 @@
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = debugserver;
@@ -916,20 +898,15 @@
GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INSTALL_PATH = /usr/bin;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_DEBUGSERVER = 1;
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=*internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
OTHER_CFLAGS = (
"-Wparentheses",
"-DDT_VARIANT_$(DT_VARIANT)",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
@@ -939,8 +916,6 @@
"-DWITH_FBS",
"-DOS_OBJECT_USE_OBJC=0",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
"-isystem",
"$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
@@ -959,7 +934,6 @@
MobileCoreServices,
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
@@ -967,7 +941,6 @@
__info_plist,
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
@@ -1003,20 +976,15 @@
GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_RELEASE;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INSTALL_PATH = /usr/bin;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_DEBUGSERVER = 1;
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
OTHER_CFLAGS = (
"-Wparentheses",
"-DDT_VARIANT_$(DT_VARIANT)",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
@@ -1026,8 +994,6 @@
"-DWITH_BKS",
"-DOS_OBJECT_USE_OBJC=0",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
"-isystem",
"$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
@@ -1046,7 +1012,6 @@
MobileCoreServices,
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
@@ -1055,7 +1020,6 @@
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = debugserver;
@@ -1107,21 +1071,16 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = /usr/local/bin;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_DEBUGSERVER = 1;
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = (
"-Wparentheses",
"-DDT_VARIANT_$(DT_VARIANT)",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
@@ -1130,7 +1089,6 @@
"-DDEBUGSERVER_PROGRAM_SYMBOL=debugserver_nonui",
"$(LLDB_ENERGY_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
);
"OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = "";
@@ -1191,8 +1149,6 @@
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
OTHER_CFLAGS = (
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
"-Wparentheses",
@@ -1215,7 +1171,6 @@
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = "debugserver-nonui";
@@ -1251,7 +1206,6 @@
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
INSTALL_PATH = /usr/local/bin;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_DEBUGSERVER = 1;
LLDB_ENERGY_CFLAGS = "";
@@ -1259,8 +1213,6 @@
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
OTHER_CFLAGS = (
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"-DDEBUGSERVER_PROGRAM_SYMBOL=debugserver_nonui",
"$(LLDB_OS_LOG_CFLAGS)",
);
@@ -1269,7 +1221,6 @@
"-DOS_OBJECT_USE_OBJC=0",
"-DDEBUGSERVER_PROGRAM_SYMBOL=debugserver_nonui",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
);
"OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)";
@@ -1279,7 +1230,6 @@
Foundation,
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
@@ -1288,7 +1238,6 @@
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = "debugserver-nonui";
@@ -1391,7 +1340,6 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)";
LLDB_USE_OS_LOG = 0;
@@ -1426,20 +1374,15 @@
GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INSTALL_PATH = /usr/bin;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_DEBUGSERVER = 1;
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
OTHER_CFLAGS = (
"-Wparentheses",
"-DDT_VARIANT_$(DT_VARIANT)",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
@@ -1449,8 +1392,6 @@
"-DWITH_BKS",
"-DOS_OBJECT_USE_OBJC=0",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
"-isystem",
"$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
@@ -1468,7 +1409,6 @@
MobileCoreServices,
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
@@ -1477,7 +1417,6 @@
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = debugserver;
@@ -1516,7 +1455,6 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)";
LLDB_USE_OS_LOG = 0;
@@ -1551,19 +1489,14 @@
GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INSTALL_PATH = /usr/bin;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_DEBUGSERVER = 1;
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
OTHER_CFLAGS = (
"-Wparentheses",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
@@ -1573,8 +1506,6 @@
"-DWITH_BKS",
"-DOS_OBJECT_USE_OBJC=0",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
"-isystem",
"$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
@@ -1592,7 +1523,6 @@
MobileCoreServices,
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
@@ -1601,7 +1531,6 @@
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = debugserver;
@@ -1716,7 +1645,6 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)";
LLDB_USE_OS_LOG = 0;
@@ -1751,20 +1679,15 @@
GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INSTALL_PATH = /usr/bin;
- LLDB_COMPRESSION_CFLAGS = "";
- LLDB_COMPRESSION_LDFLAGS = "";
+ LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_DEBUGSERVER = 1;
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
OTHER_CFLAGS = (
"-Wparentheses",
"-DDT_VARIANT_$(DT_VARIANT)",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
@@ -1774,8 +1697,6 @@
"-DWITH_FBS",
"-DOS_OBJECT_USE_OBJC=0",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
"-isystem",
"$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
@@ -1794,7 +1715,6 @@
MobileCoreServices,
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
@@ -1803,7 +1723,6 @@
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = debugserver;
@@ -1841,7 +1760,6 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1";
LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)";
LLDB_USE_OS_LOG = 0;
@@ -1877,20 +1795,15 @@
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
INSTALL_PATH = /usr/bin;
- LLDB_COMPRESSION_CFLAGS = "";
- LLDB_COMPRESSION_LDFLAGS = "";
+ LLDB_COMPRESSION_LDFLAGS = "-lcompression";
LLDB_DEBUGSERVER = 1;
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample";
- LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1";
- LLDB_ZLIB_LDFLAGS = "-lz";
OTHER_CFLAGS = (
"-Wparentheses",
"-DDT_VARIANT_$(DT_VARIANT)",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
@@ -1900,8 +1813,6 @@
"-DWITH_BKS",
"-DOS_OBJECT_USE_OBJC=0",
"$(LLDB_ENERGY_CFLAGS)",
- "$(LLDB_COMPRESSION_CFLAGS)",
- "$(LLDB_ZLIB_CFLAGS)",
"$(LLDB_OS_LOG_CFLAGS)",
"-isystem",
"$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
@@ -1919,7 +1830,6 @@
MobileCoreServices,
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
@@ -1928,7 +1838,6 @@
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LDFLAGS)",
"$(LLDB_COMPRESSION_LDFLAGS)",
- "$(LLDB_ZLIB_LDFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = debugserver;
diff --git a/tools/debugserver/source/CMakeLists.txt b/tools/debugserver/source/CMakeLists.txt
index ec136039d349..860a0289d22c 100644
--- a/tools/debugserver/source/CMakeLists.txt
+++ b/tools/debugserver/source/CMakeLists.txt
@@ -5,7 +5,6 @@ include_directories(${LLDB_SOURCE_DIR}/source)
include_directories(MacOSX/DarwinLog)
include_directories(MacOSX)
-#include_directories(${CMAKE_CURRENT_BINARY_DIR}/MacOSX)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_SOURCE_DIR}/../resources/lldb-debugserver-Info.plist")
@@ -94,32 +93,121 @@ set(lldbDebugserverCommonSources
add_library(lldbDebugserverCommon ${lldbDebugserverCommonSources})
+# LLDB-specific identity, currently used for code signing debugserver.
+set(LLDB_CODESIGN_IDENTITY "" CACHE STRING
+ "Override code sign identity for debugserver and for use in tests; falls back to LLVM_CODESIGNING_IDENTITY if set or lldb_codesign otherwise (Darwin only)")
-set(LLDB_CODESIGN_IDENTITY "lldb_codesign"
- CACHE STRING "Identity used for code signing. Set to empty string to skip the signing step.")
-
-if(NOT LLDB_CODESIGN_IDENTITY STREQUAL "")
- set(DEBUGSERVER_PATH ${LLVM_RUNTIME_OUTPUT_INTDIR}/debugserver${CMAKE_EXECUTABLE_SUFFIX} CACHE PATH "Path to debugserver.")
- set(SKIP_DEBUGSERVER OFF CACHE BOOL "Skip building the in-tree debug server")
+# Determine which identity to use and store it in the separate cache entry.
+# We will query it later for LLDB_TEST_COMMON_ARGS.
+if(LLDB_CODESIGN_IDENTITY)
+ set(LLDB_CODESIGN_IDENTITY_USED ${LLDB_CODESIGN_IDENTITY} CACHE INTERNAL "" FORCE)
+elseif(LLVM_CODESIGNING_IDENTITY)
+ set(LLDB_CODESIGN_IDENTITY_USED ${LLVM_CODESIGNING_IDENTITY} CACHE INTERNAL "" FORCE)
else()
+ set(LLDB_CODESIGN_IDENTITY_USED lldb_codesign CACHE INTERNAL "" FORCE)
+endif()
+
+# Override locally, so the identity is used for targets created in this scope.
+set(LLVM_CODESIGNING_IDENTITY ${LLDB_CODESIGN_IDENTITY_USED})
+
+option(LLDB_NO_DEBUGSERVER "Disable the debugserver target" OFF)
+option(LLDB_USE_SYSTEM_DEBUGSERVER "Use the system's debugserver instead of building it from source (Darwin only)." OFF)
+
+# Incompatible options
+if(LLDB_NO_DEBUGSERVER AND LLDB_USE_SYSTEM_DEBUGSERVER)
+ message(FATAL_ERROR "Inconsistent options: LLDB_NO_DEBUGSERVER and LLDB_USE_SYSTEM_DEBUGSERVER")
+endif()
+
+# Try to locate the system debugserver.
+# Subsequent feasibility checks depend on it.
+if(APPLE AND CMAKE_HOST_APPLE)
execute_process(
COMMAND xcode-select -p
- OUTPUT_VARIABLE XCODE_DEV_DIR)
- string(STRIP ${XCODE_DEV_DIR} XCODE_DEV_DIR)
- if(EXISTS "${XCODE_DEV_DIR}/../SharedFrameworks/LLDB.framework/")
- set(DEBUGSERVER_PATH
- "${XCODE_DEV_DIR}/../SharedFrameworks/LLDB.framework/Resources/debugserver" CACHE PATH "Path to debugserver.")
- elseif(EXISTS "${XCODE_DEV_DIR}/Library/PrivateFrameworks/LLDB.framework/")
- set(DEBUGSERVER_PATH
- "${XCODE_DEV_DIR}/Library/PrivateFrameworks/LLDB.framework/Resources/debugserver" CACHE PATH "Path to debugserver.")
+ OUTPUT_VARIABLE xcode_dev_dir)
+ string(STRIP ${xcode_dev_dir} xcode_dev_dir)
+
+ set(debugserver_rel_path "LLDB.framework/Resources/debugserver")
+ set(debugserver_shared "${xcode_dev_dir}/../SharedFrameworks/${debugserver_rel_path}")
+ set(debugserver_private "${xcode_dev_dir}/Library/PrivateFrameworks/${debugserver_rel_path}")
+
+ if(EXISTS ${debugserver_shared})
+ set(system_debugserver ${debugserver_shared})
+ elseif(EXISTS ${debugserver_private})
+ set(system_debugserver ${debugserver_private})
+ endif()
+endif()
+
+# Handle unavailability
+if(LLDB_USE_SYSTEM_DEBUGSERVER)
+ if(system_debugserver)
+ set(use_system_debugserver ON)
+ elseif(APPLE AND CMAKE_HOST_APPLE)
+ # Binary not found on system. Keep cached variable, to try again on reconfigure.
+ message(SEND_ERROR
+ "LLDB_USE_SYSTEM_DEBUGSERVER option set, but no debugserver found in:\
+ ${debugserver_shared}\
+ ${debugserver_private}")
else()
- message(SEND_ERROR "Cannot find debugserver on system.")
+ # Non-Apple target platform or non-Darwin host. Reset invalid cached variable.
+ message(WARNING "Reverting invalid option LLDB_USE_SYSTEM_DEBUGSERVER (Darwin only)")
+ set(LLDB_USE_SYSTEM_DEBUGSERVER OFF CACHE BOOL "" FORCE)
endif()
- set(SKIP_DEBUGSERVER ON CACHE BOOL "Skip building the in-tree debug server")
+elseif(NOT LLDB_NO_DEBUGSERVER)
+ # Default case: on Darwin we need the right code signing ID.
+ # See lldb/docs/code-signing.txt for details.
+ if(CMAKE_HOST_APPLE AND NOT LLVM_CODESIGNING_IDENTITY STREQUAL "lldb_codesign")
+ set(problem "Cannot code sign debugserver with LLVM_CODESIGNING_IDENTITY '${LLVM_CODESIGNING_IDENTITY}'.")
+ set(advice "Pass -DLLDB_CODESIGN_IDENTITY=lldb_codesign to override the LLVM value for debugserver.")
+ if(system_debugserver)
+ set(effect "Will fall back to system's debugserver.")
+ set(use_system_debugserver ON)
+ else()
+ set(effect "debugserver will not be available.")
+ endif()
+ message(WARNING "${problem} ${effect} ${advice}")
+ else()
+ set(build_and_sign_debugserver ON)
+ endif()
+endif()
+
+# TODO: We don't use the $<TARGET_FILE:debugserver> generator expression here,
+# because the value of DEBUGSERVER_PATH is used to build LLDB_DOTEST_ARGS,
+# which is used for configuring lldb-dotest.in, which does not have a generator
+# step at the moment.
+set(default_debugserver_path "${LLVM_RUNTIME_OUTPUT_INTDIR}/debugserver${CMAKE_EXECUTABLE_SUFFIX}")
+
+# Remember where debugserver binary goes and whether or not we have to test it.
+set(DEBUGSERVER_PATH "" CACHE FILEPATH "Path to debugserver")
+set(SKIP_TEST_DEBUGSERVER OFF CACHE BOOL "Building the in-tree debugserver was skipped")
+
+# Reset values in all cases in order to correctly support reconfigurations.
+if(use_system_debugserver)
+ add_custom_target(debugserver
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${system_debugserver} ${LLVM_RUNTIME_OUTPUT_INTDIR}
+ COMMENT "Copying the system debugserver to LLDB's binaries directory.")
+
+ # Don't test debugserver itself.
+ # Tests that require debugserver will use the copy.
+ set(DEBUGSERVER_PATH ${default_debugserver_path} CACHE FILEPATH "" FORCE)
+ set(SKIP_TEST_DEBUGSERVER ON CACHE BOOL "" FORCE)
+
+ message(STATUS "Copy system debugserver from: ${system_debugserver}")
+elseif(build_and_sign_debugserver)
+ # Build, sign and test debugserver (below)
+ set(DEBUGSERVER_PATH ${default_debugserver_path} CACHE FILEPATH "" FORCE)
+ set(SKIP_TEST_DEBUGSERVER OFF CACHE BOOL "" FORCE)
+
+ message(STATUS "lldb debugserver: ${DEBUGSERVER_PATH}")
+else()
+ # No tests for debugserver, no tests that require it.
+ set(DEBUGSERVER_PATH "" CACHE FILEPATH "" FORCE)
+ set(SKIP_TEST_DEBUGSERVER ON CACHE BOOL "" FORCE)
+
+ message(STATUS "lldb debugserver will not be available.")
endif()
-message(STATUS "Path to the lldb debugserver: ${DEBUGSERVER_PATH}")
-if (APPLE)
+if(APPLE)
if(IOS)
find_library(BACKBOARD_LIBRARY BackBoardServices
PATHS ${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks)
@@ -132,7 +220,7 @@ if (APPLE)
find_library(LOCKDOWN_LIBRARY lockdown)
if(NOT BACKBOARD_LIBRARY)
- set(SKIP_DEBUGSERVER ON CACHE BOOL "Skip building the in-tree debug server" FORCE)
+ set(SKIP_TEST_DEBUGSERVER ON CACHE BOOL "" FORCE)
endif()
else()
find_library(COCOA_LIBRARY Cocoa)
@@ -143,7 +231,16 @@ if(HAVE_LIBCOMPRESSION)
set(LIBCOMPRESSION compression)
endif()
-if(NOT SKIP_DEBUGSERVER)
+if(LLDB_USE_ENTITLEMENTS)
+ if(IOS)
+ set(entitlements ${CMAKE_CURRENT_SOURCE_DIR}/debugserver-entitlements.plist)
+ else()
+ # Same entitlements file as used for lldb-server
+ set(entitlements ${LLDB_SOURCE_DIR}/resources/debugserver-macosx-entitlements.plist)
+ endif()
+endif()
+
+if(build_and_sign_debugserver)
target_link_libraries(lldbDebugserverCommon
INTERFACE ${COCOA_LIBRARY}
${CORE_FOUNDATION_LIBRARY}
@@ -161,11 +258,14 @@ if(NOT SKIP_DEBUGSERVER)
COMPILE_DEFINITIONS HAVE_LIBCOMPRESSION)
endif()
set(LLVM_OPTIONAL_SOURCES ${lldbDebugserverCommonSources})
- add_lldb_tool(debugserver INCLUDE_IN_SUITE
+ add_lldb_tool(debugserver
debugserver.cpp
LINK_LIBS
lldbDebugserverCommon
+
+ ENTITLEMENTS
+ ${entitlements}
)
if(IOS)
set_property(TARGET lldbDebugserverCommon APPEND PROPERTY COMPILE_DEFINITIONS
@@ -203,56 +303,8 @@ if(IOS)
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)
-else()
- set(entitlements_xml ${CMAKE_CURRENT_SOURCE_DIR}/../../../resources/debugserver-macosx-entitlements.plist)
-endif()
-
-set(LLDB_USE_ENTITLEMENTS_Default On)
-option(LLDB_USE_ENTITLEMENTS "Use entitlements when codesigning (Defaults Off when using lldb_codesign identity, otherwise On)" ${LLDB_USE_ENTITLEMENTS_Default})
-if (SKIP_DEBUGSERVER)
- if (CMAKE_HOST_APPLE)
- # If we haven't built a signed debugserver, copy the one from the system.
- add_custom_target(debugserver
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DEBUGSERVER_PATH} ${CMAKE_BINARY_DIR}/bin
- VERBATIM
- COMMENT "Copying the system debugserver to LLDB's binaries directory.")
- endif()
-else()
- if(LLDB_USE_ENTITLEMENTS)
- set(entitlements_flags --entitlements ${entitlements_xml})
- endif()
- execute_process(
- COMMAND xcrun -f codesign_allocate
- OUTPUT_STRIP_TRAILING_WHITESPACE
- OUTPUT_VARIABLE CODESIGN_ALLOCATE
- )
- add_custom_command(TARGET debugserver
- 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
+ ENTITLEMENTS
+ ${entitlements}
)
- endif()
endif()
-
-
-
-
diff --git a/tools/debugserver/source/DNBRegisterInfo.cpp b/tools/debugserver/source/DNBRegisterInfo.cpp
index b85b39378183..d0f6063fbce0 100644
--- a/tools/debugserver/source/DNBRegisterInfo.cpp
+++ b/tools/debugserver/source/DNBRegisterInfo.cpp
@@ -156,6 +156,7 @@ void DNBRegisterValueClass::Dump(const char *pre, const char *post) const {
DNBLogError(
"unsupported vector format %d, defaulting to hex bytes.",
info.format);
+ [[clang::fallthrough]];
case VectorOfUInt8:
snprintf(str, sizeof(str), "%s", "uint8 { ");
pos = str + strlen(str);
diff --git a/tools/debugserver/source/JSONGenerator.h b/tools/debugserver/source/JSONGenerator.h
index 7af6ae60c5f7..0ac5e0bb768c 100644
--- a/tools/debugserver/source/JSONGenerator.h
+++ b/tools/debugserver/source/JSONGenerator.h
@@ -10,8 +10,6 @@
#ifndef __JSONGenerator_h_
#define __JSONGenerator_h_
-// C Includes
-// C++ Includes
#include <iomanip>
#include <sstream>
@@ -184,7 +182,7 @@ public:
void SetValue(bool value) { m_value = value; }
void Dump(std::ostream &s) const override {
- if (m_value == true)
+ if (m_value)
s << "true";
else
s << "false";
@@ -264,7 +262,7 @@ public:
s << "{";
for (collection::const_iterator iter = m_dict.begin();
iter != m_dict.end(); ++iter) {
- if (have_printed_one_elem == false) {
+ if (!have_printed_one_elem) {
have_printed_one_elem = true;
} else {
s << ",";
diff --git a/tools/debugserver/source/MacOSX/Genealogy.cpp b/tools/debugserver/source/MacOSX/Genealogy.cpp
index 22ff52abaa47..1473a53fcbea 100644
--- a/tools/debugserver/source/MacOSX/Genealogy.cpp
+++ b/tools/debugserver/source/MacOSX/Genealogy.cpp
@@ -74,8 +74,7 @@ Genealogy::GetGenealogyInfoForThread(pid_t pid, nub_thread_t tid,
// (else we'll need to hit the timeout for every thread we're asked about.)
// We'll try again at the next public stop.
- if (m_thread_activities.size() == 0 &&
- m_diagnosticd_call_timed_out == false) {
+ if (m_thread_activities.size() == 0 && !m_diagnosticd_call_timed_out) {
GetActivities(pid, thread_list, task);
}
std::map<nub_thread_t, ThreadActivitySP>::const_iterator search;
diff --git a/tools/debugserver/source/MacOSX/MachException.cpp b/tools/debugserver/source/MacOSX/MachException.cpp
index da2b2fe92980..01e5892d487d 100644
--- a/tools/debugserver/source/MacOSX/MachException.cpp
+++ b/tools/debugserver/source/MacOSX/MachException.cpp
@@ -386,24 +386,29 @@ void MachException::Data::Dump() const {
}
}
-#define PREV_EXC_MASK_ALL \
- (EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | \
- EXC_MASK_EMULATION | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT | \
- EXC_MASK_SYSCALL | EXC_MASK_MACH_SYSCALL | EXC_MASK_RPC_ALERT | \
- EXC_MASK_MACHINE)
-
-// Don't listen for EXC_RESOURCE, it should really get handled by the system
-// handler.
-
-#ifndef EXC_RESOURCE
-#define EXC_RESOURCE 11
-#endif
-
-#ifndef EXC_MASK_RESOURCE
-#define EXC_MASK_RESOURCE (1 << EXC_RESOURCE)
-#endif
-
-#define LLDB_EXC_MASK (EXC_MASK_ALL & ~EXC_MASK_RESOURCE)
+// The EXC_MASK_ALL value hard-coded here so that lldb can be built
+// on a new OS with an older deployment target . The new OS may have
+// an addition to its EXC_MASK_ALL that the old OS will not recognize -
+// <mach/exception_types.h> doesn't vary the value based on the deployment
+// target. So we need a known set of masks that can be assumed to be
+// valid when running on an older OS. We'll fall back to trying
+// PREV_EXC_MASK_ALL if the EXC_MASK_ALL value lldb was compiled with is
+// not recognized.
+
+#define PREV_EXC_MASK_ALL (EXC_MASK_BAD_ACCESS | \
+ EXC_MASK_BAD_INSTRUCTION | \
+ EXC_MASK_ARITHMETIC | \
+ EXC_MASK_EMULATION | \
+ EXC_MASK_SOFTWARE | \
+ EXC_MASK_BREAKPOINT | \
+ EXC_MASK_SYSCALL | \
+ EXC_MASK_MACH_SYSCALL | \
+ EXC_MASK_RPC_ALERT | \
+ EXC_MASK_RESOURCE | \
+ EXC_MASK_GUARD | \
+ EXC_MASK_MACHINE)
+
+#define LLDB_EXC_MASK EXC_MASK_ALL
kern_return_t MachException::PortInfo::Save(task_t task) {
DNBLogThreadedIf(LOG_EXCEPTIONS | LOG_VERBOSE,
@@ -485,9 +490,21 @@ const char *MachException::Name(exception_type_t exc_type) {
return "EXC_MACH_SYSCALL";
case EXC_RPC_ALERT:
return "EXC_RPC_ALERT";
-#ifdef EXC_CRASH
case EXC_CRASH:
return "EXC_CRASH";
+ case EXC_RESOURCE:
+ return "EXC_RESOURCE";
+#ifdef EXC_GUARD
+ case EXC_GUARD:
+ return "EXC_GUARD";
+#endif
+#ifdef EXC_CORPSE_NOTIFY
+ case EXC_CORPSE_NOTIFY:
+ return "EXC_CORPSE_NOTIFY";
+#endif
+#ifdef EXC_CORPSE_VARIANT_BIT
+ case EXC_CORPSE_VARIANT_BIT:
+ return "EXC_CORPSE_VARIANT_BIT";
#endif
default:
break;
diff --git a/tools/debugserver/source/MacOSX/MachProcess.mm b/tools/debugserver/source/MacOSX/MachProcess.mm
index 4ddc5f8b10dc..a3b905d05150 100644
--- a/tools/debugserver/source/MacOSX/MachProcess.mm
+++ b/tools/debugserver/source/MacOSX/MachProcess.mm
@@ -783,8 +783,8 @@ JSONGenerator::ObjectSP MachProcess::FormatDynamicLibrariesIntoJSON(
uuid_unparse_upper(image_infos[i].macho_info.uuid, uuidstr);
image_info_dict_sp->AddStringItem("uuid", uuidstr);
- if (image_infos[i].macho_info.min_version_os_name.empty() == false &&
- image_infos[i].macho_info.min_version_os_version.empty() == false) {
+ if (!image_infos[i].macho_info.min_version_os_name.empty() &&
+ !image_infos[i].macho_info.min_version_os_version.empty()) {
image_info_dict_sp->AddStringItem(
"min_version_os_name", image_infos[i].macho_info.min_version_os_name);
image_info_dict_sp->AddStringItem(
@@ -803,6 +803,8 @@ JSONGenerator::ObjectSP MachProcess::FormatDynamicLibrariesIntoJSON(
(uint32_t)image_infos[i].macho_info.mach_header.cpusubtype);
mach_header_dict_sp->AddIntegerItem(
"filetype", image_infos[i].macho_info.mach_header.filetype);
+ mach_header_dict_sp->AddIntegerItem ("flags",
+ image_infos[i].macho_info.mach_header.flags);
// DynamicLoaderMacOSX doesn't currently need these fields, so
// don't send them.
@@ -810,8 +812,6 @@ JSONGenerator::ObjectSP MachProcess::FormatDynamicLibrariesIntoJSON(
// image_infos[i].macho_info.mach_header.ncmds);
// mach_header_dict_sp->AddIntegerItem ("sizeofcmds",
// image_infos[i].macho_info.mach_header.sizeofcmds);
- // mach_header_dict_sp->AddIntegerItem ("flags",
- // image_infos[i].macho_info.mach_header.flags);
image_info_dict_sp->AddItem("mach_header", mach_header_dict_sp);
JSONGenerator::ArraySP segments_sp(new JSONGenerator::Array());
@@ -1602,7 +1602,7 @@ nub_size_t MachProcess::WriteMemory(nub_addr_t addr, nub_size_t size,
void MachProcess::ReplyToAllExceptions() {
PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
- if (m_exception_messages.empty() == false) {
+ if (!m_exception_messages.empty()) {
MachException::Message::iterator pos;
MachException::Message::iterator begin = m_exception_messages.begin();
MachException::Message::iterator end = m_exception_messages.end();
@@ -1774,7 +1774,7 @@ bool MachProcess::DisableBreakpoint(nub_addr_t addr, bool remove) {
if (bp->IsHardware()) {
bool hw_disable_result = m_thread_list.DisableHardwareBreakpoint(bp);
- if (hw_disable_result == true) {
+ if (hw_disable_result) {
bp->SetEnabled(false);
// Let the thread list know that a breakpoint has been modified
if (remove) {
@@ -1909,7 +1909,7 @@ bool MachProcess::DisableWatchpoint(nub_addr_t addr, bool remove) {
if (wp->IsHardware()) {
bool hw_disable_result = m_thread_list.DisableHardwareWatchpoint(wp);
- if (hw_disable_result == true) {
+ if (hw_disable_result) {
wp->SetEnabled(false);
if (remove)
m_watchpoints.Remove(addr);
@@ -2179,7 +2179,7 @@ task_t MachProcess::ExceptionMessageBundleComplete() {
m_thread_list.Dump();
bool step_more = false;
- if (m_thread_list.ShouldStop(step_more) && auto_resume == false) {
+ if (m_thread_list.ShouldStop(step_more) && !auto_resume) {
// Wait for the eEventProcessRunningStateChanged event to be reset
// before changing state to stopped to avoid race condition with
// very fast start/stops
diff --git a/tools/debugserver/source/MacOSX/MachTask.h b/tools/debugserver/source/MacOSX/MachTask.h
index 1e0e2af9a92b..1fe74ddec56c 100644
--- a/tools/debugserver/source/MacOSX/MachTask.h
+++ b/tools/debugserver/source/MacOSX/MachTask.h
@@ -18,14 +18,10 @@
#ifndef __MachTask_h__
#define __MachTask_h__
-// C Includes
#include <mach/mach.h>
#include <sys/socket.h>
-// C++ Includes
#include <map>
#include <string>
-// Other libraries and framework includes
-// Project includes
#include "DNBDefs.h"
#include "MachException.h"
#include "MachVMMemory.h"
diff --git a/tools/debugserver/source/MacOSX/MachThread.cpp b/tools/debugserver/source/MacOSX/MachThread.cpp
index fc97825786a0..062e1c3d9edf 100644
--- a/tools/debugserver/source/MacOSX/MachThread.cpp
+++ b/tools/debugserver/source/MacOSX/MachThread.cpp
@@ -83,7 +83,7 @@ bool MachThread::SetSuspendCountBeforeResume(bool others_stopped) {
DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )",
__FUNCTION__);
DNBError err;
- if (MachPortNumberIsValid(m_mach_port_number) == false)
+ if (!MachPortNumberIsValid(m_mach_port_number))
return false;
integer_t times_to_resume;
@@ -121,7 +121,7 @@ bool MachThread::RestoreSuspendCountAfterStop() {
DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )",
__FUNCTION__);
DNBError err;
- if (MachPortNumberIsValid(m_mach_port_number) == false)
+ if (!MachPortNumberIsValid(m_mach_port_number))
return false;
if (m_suspend_count > 0) {
diff --git a/tools/debugserver/source/MacOSX/MachVMRegion.cpp b/tools/debugserver/source/MacOSX/MachVMRegion.cpp
index c011c133ac38..172fc7867b57 100644
--- a/tools/debugserver/source/MacOSX/MachVMRegion.cpp
+++ b/tools/debugserver/source/MacOSX/MachVMRegion.cpp
@@ -166,10 +166,7 @@ bool MachVMRegion::GetRegionForAddress(nub_addr_t addr) {
// doesn't mean that "addr" is in the range. The data in this object will
// be valid though, so you could see where the next region begins. So we
// return false, yet leave "m_err" with a successfull return code.
- if ((addr < m_start) || (addr >= (m_start + m_size)))
- return false;
-
- return true;
+ return !((addr < m_start) || (addr >= (m_start + m_size)));
}
uint32_t MachVMRegion::GetDNBPermissions() const {
diff --git a/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
index adcd65002191..ba37a328ecf3 100644
--- a/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
+++ b/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
@@ -889,10 +889,7 @@ bool DNBArchImplI386::RollbackTransForHWP() {
LOG_WATCHPOINTS,
"DNBArchImplI386::RollbackTransForHWP() SetDBGState() => 0x%8.8x.", kret);
- if (kret == KERN_SUCCESS)
- return true;
- else
- return false;
+ return kret == KERN_SUCCESS;
}
bool DNBArchImplI386::FinishTransForHWP() {
m_2pc_trans_state = Trans_Done;
@@ -918,7 +915,7 @@ uint32_t DNBArchImplI386::EnableHardwareWatchpoint(nub_addr_t addr,
return INVALID_NUB_HW_INDEX;
// We must watch for either read or write
- if (read == false && write == false)
+ if (!read && !write)
return INVALID_NUB_HW_INDEX;
// Read the debug state
diff --git a/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
index f0a3d2b001b2..2f8ed32fa5d0 100644
--- a/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
+++ b/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
@@ -844,10 +844,7 @@ bool DNBArchImplX86_64::RollbackTransForHWP() {
"DNBArchImplX86_64::RollbackTransForHWP() SetDBGState() => 0x%8.8x.",
kret);
- if (kret == KERN_SUCCESS)
- return true;
- else
- return false;
+ return kret == KERN_SUCCESS;
}
bool DNBArchImplX86_64::FinishTransForHWP() {
m_2pc_trans_state = Trans_Done;
@@ -873,7 +870,7 @@ uint32_t DNBArchImplX86_64::EnableHardwareWatchpoint(nub_addr_t addr,
return INVALID_NUB_HW_INDEX;
// We must watch for either read or write
- if (read == false && write == false)
+ if (!read && !write)
return INVALID_NUB_HW_INDEX;
// Read the debug state
diff --git a/tools/debugserver/source/PThreadMutex.cpp b/tools/debugserver/source/PThreadMutex.cpp
index 32db862f6b42..0e9132e380bf 100644
--- a/tools/debugserver/source/PThreadMutex.cpp
+++ b/tools/debugserver/source/PThreadMutex.cpp
@@ -13,10 +13,6 @@
#include "PThreadMutex.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "DNBTimer.h"
#if defined(DEBUG_PTHREAD_MUTEX_DEADLOCKS)
diff --git a/tools/debugserver/source/RNBRemote.cpp b/tools/debugserver/source/RNBRemote.cpp
index 8ba06be1d6ad..f611ec0d2199 100644
--- a/tools/debugserver/source/RNBRemote.cpp
+++ b/tools/debugserver/source/RNBRemote.cpp
@@ -42,15 +42,9 @@
#include "RNBSocket.h"
#include "StdStringExtractor.h"
-#if defined(HAVE_LIBCOMPRESSION)
#include <compression.h>
-#endif
-
-#if defined(HAVE_LIBZ)
-#include <zlib.h>
-#endif
-#include <TargetConditionals.h> // for endianness predefines
+#include <TargetConditionals.h>
#include <iomanip>
#include <sstream>
#include <unordered_set>
@@ -709,53 +703,73 @@ std::string RNBRemote::CompressString(const std::string &orig) {
std::vector<uint8_t> encoded_data(encoded_data_buf_size);
size_t compressed_size = 0;
-#if defined(HAVE_LIBCOMPRESSION)
+ // Allocate a scratch buffer for libcompression the first
+ // time we see a different compression type; reuse it in
+ // all compression_encode_buffer calls so it doesn't need
+ // to allocate / free its own scratch buffer each time.
+ // This buffer will only be freed when compression type
+ // changes; otherwise it will persist until debugserver
+ // exit.
+
+ static compression_types g_libcompress_scratchbuf_type = compression_types::none;
+ static void *g_libcompress_scratchbuf = nullptr;
+
+ if (g_libcompress_scratchbuf_type != compression_type) {
+ if (g_libcompress_scratchbuf) {
+ free (g_libcompress_scratchbuf);
+ g_libcompress_scratchbuf = nullptr;
+ }
+ size_t scratchbuf_size = 0;
+ switch (compression_type) {
+ case compression_types::lz4:
+ scratchbuf_size = compression_encode_scratch_buffer_size (COMPRESSION_LZ4_RAW);
+ break;
+ case compression_types::zlib_deflate:
+ scratchbuf_size = compression_encode_scratch_buffer_size (COMPRESSION_ZLIB);
+ break;
+ case compression_types::lzma:
+ scratchbuf_size = compression_encode_scratch_buffer_size (COMPRESSION_LZMA);
+ break;
+ case compression_types::lzfse:
+ scratchbuf_size = compression_encode_scratch_buffer_size (COMPRESSION_LZFSE);
+ break;
+ default:
+ break;
+ }
+ if (scratchbuf_size > 0) {
+ g_libcompress_scratchbuf = (void*) malloc (scratchbuf_size);
+ g_libcompress_scratchbuf_type = compression_type;
+ }
+ }
+
if (compression_type == compression_types::lz4) {
compressed_size = compression_encode_buffer(
encoded_data.data(), encoded_data_buf_size,
- (const uint8_t *)orig.c_str(), orig.size(), nullptr,
+ (const uint8_t *)orig.c_str(), orig.size(),
+ g_libcompress_scratchbuf,
COMPRESSION_LZ4_RAW);
}
if (compression_type == compression_types::zlib_deflate) {
compressed_size = compression_encode_buffer(
encoded_data.data(), encoded_data_buf_size,
- (const uint8_t *)orig.c_str(), orig.size(), nullptr,
+ (const uint8_t *)orig.c_str(), orig.size(),
+ g_libcompress_scratchbuf,
COMPRESSION_ZLIB);
}
if (compression_type == compression_types::lzma) {
compressed_size = compression_encode_buffer(
encoded_data.data(), encoded_data_buf_size,
- (const uint8_t *)orig.c_str(), orig.size(), nullptr,
+ (const uint8_t *)orig.c_str(), orig.size(),
+ g_libcompress_scratchbuf,
COMPRESSION_LZMA);
}
if (compression_type == compression_types::lzfse) {
compressed_size = compression_encode_buffer(
encoded_data.data(), encoded_data_buf_size,
- (const uint8_t *)orig.c_str(), orig.size(), nullptr,
+ (const uint8_t *)orig.c_str(), orig.size(),
+ g_libcompress_scratchbuf,
COMPRESSION_LZFSE);
}
-#endif
-
-#if defined(HAVE_LIBZ)
- if (compressed_size == 0 &&
- compression_type == compression_types::zlib_deflate) {
- z_stream stream;
- memset(&stream, 0, sizeof(z_stream));
- stream.next_in = (Bytef *)orig.c_str();
- stream.avail_in = (uInt)orig.size();
- stream.next_out = (Bytef *)encoded_data.data();
- stream.avail_out = (uInt)encoded_data_buf_size;
- stream.zalloc = Z_NULL;
- stream.zfree = Z_NULL;
- stream.opaque = Z_NULL;
- deflateInit2(&stream, 5, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
- int compress_status = deflate(&stream, Z_FINISH);
- deflateEnd(&stream);
- if (compress_status == Z_STREAM_END && stream.total_out > 0) {
- compressed_size = stream.total_out;
- }
- }
-#endif
if (compressed_size > 0) {
compressed.clear();
@@ -1811,18 +1825,18 @@ rnb_err_t RNBRemote::HandlePacket_qRcmd(const char *p) {
}
if (*c == '\0') {
std::string command = get_identifier(line);
- if (command.compare("set") == 0) {
+ if (command == "set") {
std::string variable = get_identifier(line);
std::string op = get_operator(line);
std::string value = get_value(line);
- if (variable.compare("logfile") == 0) {
+ if (variable == "logfile") {
FILE *log_file = fopen(value.c_str(), "w");
if (log_file) {
DNBLogSetLogCallback(FileLogCallback, log_file);
return SendPacket("OK");
}
return SendPacket("E71");
- } else if (variable.compare("logmask") == 0) {
+ } else if (variable == "logmask") {
char *end;
errno = 0;
uint32_t logmask =
@@ -3413,10 +3427,7 @@ static bool RNBRemoteShouldCancelCallback(void *not_used) {
RNBRemoteSP remoteSP(g_remoteSP);
if (remoteSP.get() != NULL) {
RNBRemote *remote = remoteSP.get();
- if (remote->Comm().IsConnected())
- return false;
- else
- return true;
+ return !remote->Comm().IsConnected();
}
return true;
}
@@ -3614,13 +3625,13 @@ rnb_err_t RNBRemote::HandlePacket_qSupported(const char *p) {
bool enable_compression = false;
(void)enable_compression;
-#if (defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1) || (defined (TARGET_OS_IOS) && TARGET_OS_IOS == 1) || (defined (TARGET_OS_TV) && TARGET_OS_TV == 1)
+#if (defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1) \
+ || (defined (TARGET_OS_IOS) && TARGET_OS_IOS == 1) \
+ || (defined (TARGET_OS_TV) && TARGET_OS_TV == 1) \
+ || (defined (TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE == 1)
enable_compression = true;
#endif
-#if defined(HAVE_LIBCOMPRESSION)
- // libcompression is weak linked so test if compression_decode_buffer() is
- // available
if (enable_compression) {
strcat(buf, ";SupportedCompressions=lzfse,zlib-deflate,lz4,lzma;"
"DefaultCompressionMinSize=");
@@ -3628,17 +3639,7 @@ rnb_err_t RNBRemote::HandlePacket_qSupported(const char *p) {
snprintf(numbuf, sizeof(numbuf), "%zu", m_compression_minsize);
numbuf[sizeof(numbuf) - 1] = '\0';
strcat(buf, numbuf);
- }
-#elif defined(HAVE_LIBZ)
- if (enable_compression) {
- strcat(buf,
- ";SupportedCompressions=zlib-deflate;DefaultCompressionMinSize=");
- char numbuf[16];
- snprintf(numbuf, sizeof(numbuf), "%zu", m_compression_minsize);
- numbuf[sizeof(numbuf) - 1] = '\0';
- strcat(buf, numbuf);
- }
-#endif
+ }
return SendPacket(buf);
}
@@ -3690,7 +3691,7 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) {
return HandlePacket_ILLFORMED(
__FILE__, __LINE__, p, "Could not parse signal in vCont packet");
// Fall through to next case...
-
+ [[clang::fallthrough]];
case 'c':
// Continue
thread_action.state = eStateRunning;
@@ -3703,7 +3704,7 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) {
return HandlePacket_ILLFORMED(
__FILE__, __LINE__, p, "Could not parse signal in vCont packet");
// Fall through to next case...
-
+ [[clang::fallthrough]];
case 's':
// Step
thread_action.state = eStateStepping;
@@ -3817,7 +3818,7 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) {
attach_failed_due_to_sip = true;
}
- if (attach_failed_due_to_sip == false) {
+ if (!attach_failed_due_to_sip) {
int csops_flags = 0;
int retval = ::csops(pid_attaching_to, CS_OPS_STATUS, &csops_flags,
sizeof(csops_flags));
@@ -4230,7 +4231,7 @@ rnb_err_t RNBRemote::HandlePacket_GetProfileData(const char *p) {
std::string name;
std::string value;
while (packet.GetNameColonValue(name, value)) {
- if (name.compare("scan_type") == 0) {
+ if (name == "scan_type") {
std::istringstream iss(value);
uint32_t int_value = 0;
if (iss >> std::hex >> int_value) {
@@ -4260,11 +4261,11 @@ rnb_err_t RNBRemote::HandlePacket_SetEnableAsyncProfiling(const char *p) {
std::string name;
std::string value;
while (packet.GetNameColonValue(name, value)) {
- if (name.compare("enable") == 0) {
+ if (name == "enable") {
enable = strtoul(value.c_str(), NULL, 10) > 0;
- } else if (name.compare("interval_usec") == 0) {
+ } else if (name == "interval_usec") {
interval_usec = strtoul(value.c_str(), NULL, 10);
- } else if (name.compare("scan_type") == 0) {
+ } else if (name == "scan_type") {
std::istringstream iss(value);
uint32_t int_value = 0;
if (iss >> std::hex >> int_value) {
@@ -4306,7 +4307,6 @@ rnb_err_t RNBRemote::HandlePacket_QEnableCompression(const char *p) {
}
}
-#if defined(HAVE_LIBCOMPRESSION)
if (strstr(p, "type:zlib-deflate;") != nullptr) {
EnableCompressionNextSendPacket(compression_types::zlib_deflate);
m_compression_minsize = new_compression_minsize;
@@ -4324,15 +4324,6 @@ rnb_err_t RNBRemote::HandlePacket_QEnableCompression(const char *p) {
m_compression_minsize = new_compression_minsize;
return SendPacket("OK");
}
-#endif
-
-#if defined(HAVE_LIBZ)
- if (strstr(p, "type:zlib-deflate;") != nullptr) {
- EnableCompressionNextSendPacket(compression_types::zlib_deflate);
- m_compression_minsize = new_compression_minsize;
- return SendPacket("OK");
- }
-#endif
return SendPacket("E88");
}
@@ -5300,7 +5291,7 @@ RNBRemote::GetJSONThreadsInfo(bool threads_with_valid_stop_info_only) {
thread_dict_sp->AddStringItem("reason", reason_value);
- if (threads_with_valid_stop_info_only == false) {
+ if (!threads_with_valid_stop_info_only) {
const char *thread_name = DNBThreadGetName(pid, tid);
if (thread_name && thread_name[0])
thread_dict_sp->AddStringItem("name", thread_name);
@@ -5488,7 +5479,7 @@ rnb_err_t RNBRemote::HandlePacket_jThreadExtendedInfo(const char *p) {
bool need_to_print_comma = false;
- if (thread_activity_sp && timed_out == false) {
+ if (thread_activity_sp && !timed_out) {
const Genealogy::Activity *activity =
&thread_activity_sp->current_activity;
bool need_vouchers_comma_sep = false;
diff --git a/tools/debugserver/source/RNBServices.cpp b/tools/debugserver/source/RNBServices.cpp
index b2f4910f8855..89c4c27da1dd 100644
--- a/tools/debugserver/source/RNBServices.cpp
+++ b/tools/debugserver/source/RNBServices.cpp
@@ -57,9 +57,9 @@ int GetProcesses(CFMutableArrayRef plistMutableArray, bool all_users) {
const pid_t pid = proc_info.kp_proc.p_pid;
// Skip zombie processes and processes with unset status
- if (kinfo_user_matches == false || // User is acceptable
- pid == our_pid || // Skip this process
- pid == 0 || // Skip kernel (kernel pid is zero)
+ if (!kinfo_user_matches || // User is acceptable
+ pid == our_pid || // Skip this process
+ pid == 0 || // Skip kernel (kernel pid is zero)
proc_info.kp_proc.p_stat ==
SZOMB || // Zombies are bad, they like brains...
proc_info.kp_proc.p_flag & P_TRACED || // Being debugged?
diff --git a/tools/debugserver/source/StdStringExtractor.cpp b/tools/debugserver/source/StdStringExtractor.cpp
index d23f9319fa7b..3b400b2a89d2 100644
--- a/tools/debugserver/source/StdStringExtractor.cpp
+++ b/tools/debugserver/source/StdStringExtractor.cpp
@@ -9,12 +9,8 @@
#include "StdStringExtractor.h"
-// C Includes
#include <stdlib.h>
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
static inline int xdigit_to_sint(char ch) {
if (ch >= 'a' && ch <= 'f')
diff --git a/tools/debugserver/source/StdStringExtractor.h b/tools/debugserver/source/StdStringExtractor.h
index c46978b61f4f..40b57cb08fb5 100644
--- a/tools/debugserver/source/StdStringExtractor.h
+++ b/tools/debugserver/source/StdStringExtractor.h
@@ -10,13 +10,9 @@
#ifndef utility_StdStringExtractor_h_
#define utility_StdStringExtractor_h_
-// C Includes
-// C++ Includes
#include <stdint.h>
#include <string>
-// Other libraries and framework includes
-// Project includes
// Based on StringExtractor, with the added limitation that this file should not
// take a dependency on LLVM, as it is used from debugserver.
diff --git a/tools/debugserver/source/TTYState.h b/tools/debugserver/source/TTYState.h
index ab34015e1a42..88b6d3c2462e 100644
--- a/tools/debugserver/source/TTYState.h
+++ b/tools/debugserver/source/TTYState.h
@@ -56,4 +56,4 @@ protected:
TTYState m_ttystates[2];
};
-#endif \ No newline at end of file
+#endif
diff --git a/tools/debugserver/source/debugserver-entitlements.plist b/tools/debugserver/source/debugserver-entitlements.plist
index 7f1ae4615019..6d9f44536f94 100644
--- a/tools/debugserver/source/debugserver-entitlements.plist
+++ b/tools/debugserver/source/debugserver-entitlements.plist
@@ -12,8 +12,6 @@
<true/>
<key>com.apple.frontboard.debugapplications</key>
<true/>
- <key>run-unsigned-code</key>
- <true/>
<key>seatbelt-profiles</key>
<array>
<string>debugserver</string>
diff --git a/tools/debugserver/source/debugserver.cpp b/tools/debugserver/source/debugserver.cpp
index 7ae321ba431b..8afe17bce37d 100644
--- a/tools/debugserver/source/debugserver.cpp
+++ b/tools/debugserver/source/debugserver.cpp
@@ -9,19 +9,17 @@
#include <arpa/inet.h>
#include <asl.h>
-#include <crt_externs.h> // for _NSGetEnviron()
+#include <crt_externs.h>
#include <errno.h>
#include <getopt.h>
#include <netdb.h>
#include <netinet/in.h>
-#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/types.h>
-#include <sys/types.h>
#include <sys/un.h>
#include <vector>
diff --git a/tools/debugserver/source/libdebugserver.cpp b/tools/debugserver/source/libdebugserver.cpp
index 0d27cfd89a3d..34df67521a7c 100644
--- a/tools/debugserver/source/libdebugserver.cpp
+++ b/tools/debugserver/source/libdebugserver.cpp
@@ -176,7 +176,7 @@ RNBRunLoopMode HandleProcessStateChange(RNBRemoteSP &remote, bool initialize) {
case eStateSuspended:
case eStateCrashed:
case eStateStopped:
- if (initialize == false) {
+ if (!initialize) {
// Compare the last stop count to our current notion of a stop count
// to make sure we don't notify more than once for a given stop.
nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 9e01a6b67ea2..9636e1e2c790 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -1,12 +1,6 @@
-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
- # liblldb. However, getopt is not a part of the liblldb interface, so we have
- # to link against the constituent libraries manually. Note that this is
- # extremely scary as it introduces ODR violations, and it should go away as
- # soon as possible.
- set(host_lib lldbHost)
-endif()
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(LLDBOptionsTableGen)
add_lldb_tool(lldb
Driver.cpp
@@ -14,9 +8,9 @@ add_lldb_tool(lldb
LINK_LIBS
liblldb
- ${host_lib}
LINK_COMPONENTS
+ Option
Support
)
@@ -24,4 +18,11 @@ if ( CMAKE_SYSTEM_NAME MATCHES "Windows" )
add_definitions( -DIMPORT_LIBLLDB )
endif()
-add_dependencies(lldb ${LLDB_SUITE_TARGET})
+add_dependencies(lldb
+ LLDBOptionsTableGen
+ ${tablegen_deps}
+)
+
+if(LLDB_BUILD_FRAMEWORK)
+ lldb_setup_framework_rpaths_in_tool(lldb)
+endif()
diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp
index f3391a55e0d1..71a613afd9bf 100644
--- a/tools/driver/Driver.cpp
+++ b/tools/driver/Driver.cpp
@@ -9,8 +9,31 @@
#include "Driver.h"
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBHostOS.h"
+#include "lldb/API/SBLanguageRuntime.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStringList.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
#include <atomic>
+#include <bitset>
#include <csignal>
+#include <string>
+#include <thread>
+#include <utility>
+
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
@@ -25,39 +48,50 @@
#include <unistd.h>
#endif
-#include <string>
-
-#include "lldb/API/SBBreakpoint.h"
-#include "lldb/API/SBCommandInterpreter.h"
-#include "lldb/API/SBCommandReturnObject.h"
-#include "lldb/API/SBCommunication.h"
-#include "lldb/API/SBDebugger.h"
-#include "lldb/API/SBEvent.h"
-#include "lldb/API/SBHostOS.h"
-#include "lldb/API/SBLanguageRuntime.h"
-#include "lldb/API/SBListener.h"
-#include "lldb/API/SBProcess.h"
-#include "lldb/API/SBStream.h"
-#include "lldb/API/SBStringList.h"
-#include "lldb/API/SBTarget.h"
-#include "lldb/API/SBThread.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Signals.h"
-#include <thread>
-
#if !defined(__APPLE__)
#include "llvm/Support/DataTypes.h"
#endif
using namespace lldb;
+using namespace llvm;
+
+namespace {
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+const opt::OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ { \
+ PREFIX, NAME, HELPTEXT, \
+ METAVAR, OPT_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, \
+ OPT_##ALIAS, ALIASARGS, VALUES},
+#include "Options.inc"
+#undef OPTION
+};
+
+class LLDBOptTable : public opt::OptTable {
+public:
+ LLDBOptTable() : OptTable(InfoTable) {}
+};
+} // namespace
static void reset_stdin_termios();
static bool g_old_stdin_termios_is_valid = false;
static struct termios g_old_stdin_termios;
-static Driver *g_driver = NULL;
+static Driver *g_driver = nullptr;
// In the Driver::MainLoop, we change the terminal settings. This function is
// added as an atexit handler to make sure we clean them up.
@@ -68,402 +102,35 @@ static void reset_stdin_termios() {
}
}
-typedef struct {
- uint32_t usage_mask; // Used to mark options that can be used together. If (1
- // << n & usage_mask) != 0
- // then this option belongs to option set n.
- bool required; // This option is required (in the current usage level)
- const char *long_option; // Full name for this option.
- int short_option; // Single character for this option.
- int option_has_arg; // no_argument, required_argument or optional_argument
- uint32_t completion_type; // Cookie the option class can use to do define the
- // argument completion.
- lldb::CommandArgumentType argument_type; // Type of argument this option takes
- const char *usage_text; // Full text explaining what this options does and
- // what (if any) argument to
- // pass it.
-} OptionDefinition;
-
-#define LLDB_3_TO_5 LLDB_OPT_SET_3 | LLDB_OPT_SET_4 | LLDB_OPT_SET_5
-#define LLDB_4_TO_5 LLDB_OPT_SET_4 | LLDB_OPT_SET_5
-
-static OptionDefinition g_options[] = {
- {LLDB_OPT_SET_1, true, "help", 'h', no_argument, 0, eArgTypeNone,
- "Prints out the usage information for the LLDB debugger."},
- {LLDB_OPT_SET_2, true, "version", 'v', no_argument, 0, eArgTypeNone,
- "Prints out the current version number of the LLDB debugger."},
- {LLDB_OPT_SET_3, true, "arch", 'a', required_argument, 0,
- eArgTypeArchitecture,
- "Tells the debugger to use the specified architecture when starting and "
- "running the program. <architecture> must "
- "be one of the architectures for which the program was compiled."},
- {LLDB_OPT_SET_3, true, "file", 'f', required_argument, 0, eArgTypeFilename,
- "Tells the debugger to use the file <filename> as the program to be "
- "debugged."},
- {LLDB_OPT_SET_3, false, "core", 'c', required_argument, 0, eArgTypeFilename,
- "Tells the debugger to use the fullpath to <path> as the core file."},
- {LLDB_OPT_SET_5, true, "attach-pid", 'p', required_argument, 0, eArgTypePid,
- "Tells the debugger to attach to a process with the given pid."},
- {LLDB_OPT_SET_4, true, "attach-name", 'n', required_argument, 0,
- eArgTypeProcessName,
- "Tells the debugger to attach to a process with the given name."},
- {LLDB_OPT_SET_4, true, "wait-for", 'w', no_argument, 0, eArgTypeNone,
- "Tells the debugger to wait for a process with the given pid or name to "
- "launch before attaching."},
- {LLDB_3_TO_5, false, "source", 's', required_argument, 0, eArgTypeFilename,
- "Tells the debugger to read in and execute the lldb commands in the given "
- "file, after any file provided on the command line has been loaded."},
- {LLDB_3_TO_5, false, "one-line", 'o', required_argument, 0, eArgTypeNone,
- "Tells the debugger to execute this one-line lldb command after any file "
- "provided on the command line has been loaded."},
- {LLDB_3_TO_5, false, "source-before-file", 'S', required_argument, 0,
- eArgTypeFilename, "Tells the debugger to read in and execute the lldb "
- "commands in the given file, before any file provided "
- "on the command line has been loaded."},
- {LLDB_3_TO_5, false, "one-line-before-file", 'O', required_argument, 0,
- eArgTypeNone, "Tells the debugger to execute this one-line lldb command "
- "before any file provided on the command line has been "
- "loaded."},
- {LLDB_3_TO_5, false, "one-line-on-crash", 'k', required_argument, 0,
- eArgTypeNone, "When in batch mode, tells the debugger to execute this "
- "one-line lldb command if the target crashes."},
- {LLDB_3_TO_5, false, "source-on-crash", 'K', required_argument, 0,
- eArgTypeFilename, "When in batch mode, tells the debugger to source this "
- "file of lldb commands if the target crashes."},
- {LLDB_3_TO_5, false, "source-quietly", 'Q', no_argument, 0, eArgTypeNone,
- "Tells the debugger to execute this one-line lldb command before any file "
- "provided on the command line has been loaded."},
- {LLDB_3_TO_5, false, "batch", 'b', no_argument, 0, eArgTypeNone,
- "Tells the debugger to run the commands from -s, -S, -o & -O, and "
- "then quit. However if any run command stopped due to a signal or crash, "
- "the debugger will return to the interactive prompt at the place of the "
- "crash."},
- {LLDB_3_TO_5, false, "editor", 'e', no_argument, 0, eArgTypeNone,
- "Tells the debugger to open source files using the host's \"external "
- "editor\" mechanism."},
- {LLDB_3_TO_5, false, "no-lldbinit", 'x', no_argument, 0, eArgTypeNone,
- "Do not automatically parse any '.lldbinit' files."},
- {LLDB_3_TO_5, false, "no-use-colors", 'X', no_argument, 0, eArgTypeNone,
- "Do not use colors."},
- {LLDB_OPT_SET_6, true, "python-path", 'P', no_argument, 0, eArgTypeNone,
- "Prints out the path to the lldb.py file for this version of lldb."},
- {LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0,
- eArgTypeScriptLang,
- "Tells the debugger to use the specified scripting language for "
- "user-defined scripts, rather than the default. "
- "Valid scripting languages that can be specified include Python, Perl, "
- "Ruby and Tcl. Currently only the Python "
- "extensions have been implemented."},
- {LLDB_3_TO_5, false, "debug", 'd', no_argument, 0, eArgTypeNone,
- "Tells the debugger to print out extra information for debugging itself."},
- {LLDB_OPT_SET_7, true, "repl", 'r', optional_argument, 0, eArgTypeNone,
- "Runs lldb in REPL mode with a stub process."},
- {LLDB_OPT_SET_7, true, "repl-language", 'R', required_argument, 0,
- eArgTypeNone, "Chooses the language for the REPL."},
- {0, false, NULL, 0, 0, 0, eArgTypeNone, NULL}};
-
-static const uint32_t last_option_set_with_args = 2;
-
Driver::Driver()
- : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)),
- m_option_data() {
+ : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)) {
// We want to be able to handle CTRL+D in the terminal to have it terminate
// certain input
m_debugger.SetCloseInputOnEOF(false);
g_driver = this;
}
-Driver::~Driver() { g_driver = NULL; }
-
-// This function takes INDENT, which tells how many spaces to output at the
-// front
-// of each line; TEXT, which is the text that is to be output. It outputs the
-// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the
-// front of each line. It breaks lines on spaces, tabs or newlines, shortening
-// the line if necessary to not break in the middle of a word. It assumes that
-// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
-
-void OutputFormattedUsageText(FILE *out, int indent, const char *text,
- int output_max_columns) {
- int len = strlen(text);
- std::string text_string(text);
-
- // Force indentation to be reasonable.
- if (indent >= output_max_columns)
- indent = 0;
-
- // Will it all fit on one line?
-
- if (len + indent < output_max_columns)
- // Output as a single line
- fprintf(out, "%*s%s\n", indent, "", text);
- else {
- // We need to break it up into multiple lines.
- int text_width = output_max_columns - indent - 1;
- int start = 0;
- int end = start;
- int final_end = len;
- int sub_len;
-
- while (end < final_end) {
- // Dont start the 'text' on a space, since we're already outputting the
- // indentation.
- while ((start < final_end) && (text[start] == ' '))
- start++;
-
- end = start + text_width;
- if (end > final_end)
- end = final_end;
- else {
- // If we're not at the end of the text, make sure we break the line on
- // white space.
- while (end > start && text[end] != ' ' && text[end] != '\t' &&
- text[end] != '\n')
- end--;
- }
- sub_len = end - start;
- std::string substring = text_string.substr(start, sub_len);
- fprintf(out, "%*s%s\n", indent, "", substring.c_str());
- start = end + 1;
- }
- }
-}
-
-void ShowUsage(FILE *out, OptionDefinition *option_table,
- Driver::OptionData data) {
- uint32_t screen_width = 80;
- uint32_t indent_level = 0;
- const char *name = "lldb";
-
- fprintf(out, "\nUsage:\n\n");
-
- indent_level += 2;
-
- // First, show each usage level set of options, e.g. <cmd>
- // [options-for-level-0]
- // <cmd>
- // [options-for-level-1]
- // etc.
-
- uint32_t num_options;
- uint32_t num_option_sets = 0;
+Driver::~Driver() { g_driver = nullptr; }
- for (num_options = 0; option_table[num_options].long_option != NULL;
- ++num_options) {
- uint32_t this_usage_mask = option_table[num_options].usage_mask;
- if (this_usage_mask == LLDB_OPT_SET_ALL) {
- if (num_option_sets == 0)
- num_option_sets = 1;
- } else {
- for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) {
- if (this_usage_mask & 1 << j) {
- if (num_option_sets <= j)
- num_option_sets = j + 1;
- }
- }
- }
- }
-
- for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++) {
- uint32_t opt_set_mask;
-
- opt_set_mask = 1 << opt_set;
-
- if (opt_set > 0)
- fprintf(out, "\n");
- fprintf(out, "%*s%s", indent_level, "", name);
- bool is_help_line = false;
-
- for (uint32_t i = 0; i < num_options; ++i) {
- if (option_table[i].usage_mask & opt_set_mask) {
- CommandArgumentType arg_type = option_table[i].argument_type;
- const char *arg_name =
- SBCommandInterpreter::GetArgumentTypeAsCString(arg_type);
- // This is a bit of a hack, but there's no way to say certain options
- // don't have arguments yet...
- // so we do it by hand here.
- if (option_table[i].short_option == 'h')
- is_help_line = true;
-
- if (option_table[i].required) {
- if (option_table[i].option_has_arg == required_argument)
- fprintf(out, " -%c <%s>", option_table[i].short_option, arg_name);
- else if (option_table[i].option_has_arg == optional_argument)
- fprintf(out, " -%c [<%s>]", option_table[i].short_option, arg_name);
- else
- fprintf(out, " -%c", option_table[i].short_option);
- } else {
- if (option_table[i].option_has_arg == required_argument)
- fprintf(out, " [-%c <%s>]", option_table[i].short_option, arg_name);
- else if (option_table[i].option_has_arg == optional_argument)
- fprintf(out, " [-%c [<%s>]]", option_table[i].short_option,
- arg_name);
- else
- fprintf(out, " [-%c]", option_table[i].short_option);
- }
- }
- }
- if (!is_help_line && (opt_set <= last_option_set_with_args))
- fprintf(out, " [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]");
- }
-
- fprintf(out, "\n\n");
-
- // Now print out all the detailed information about the various options: long
- // form, short form and help text:
- // -- long_name <argument>
- // - short <argument>
- // help text
-
- // This variable is used to keep track of which options' info we've printed
- // out, because some options can be in
- // more than one usage level, but we only want to print the long form of its
- // information once.
-
- Driver::OptionData::OptionSet options_seen;
- Driver::OptionData::OptionSet::iterator pos;
-
- indent_level += 5;
-
- for (uint32_t i = 0; i < num_options; ++i) {
- // Only print this option if we haven't already seen it.
- pos = options_seen.find(option_table[i].short_option);
- if (pos == options_seen.end()) {
- CommandArgumentType arg_type = option_table[i].argument_type;
- const char *arg_name =
- SBCommandInterpreter::GetArgumentTypeAsCString(arg_type);
-
- options_seen.insert(option_table[i].short_option);
- fprintf(out, "%*s-%c ", indent_level, "", option_table[i].short_option);
- if (arg_type != eArgTypeNone)
- fprintf(out, "<%s>", arg_name);
- fprintf(out, "\n");
- fprintf(out, "%*s--%s ", indent_level, "", option_table[i].long_option);
- if (arg_type != eArgTypeNone)
- fprintf(out, "<%s>", arg_name);
- fprintf(out, "\n");
- indent_level += 5;
- OutputFormattedUsageText(out, indent_level, option_table[i].usage_text,
- screen_width);
- indent_level -= 5;
- fprintf(out, "\n");
- }
- }
-
- indent_level -= 5;
-
- fprintf(out, "\n%*sNotes:\n", indent_level, "");
- indent_level += 5;
-
- fprintf(out,
- "\n%*sMultiple \"-s\" and \"-o\" options can be provided. They will "
- "be processed"
- "\n%*sfrom left to right in order, with the source files and commands"
- "\n%*sinterleaved. The same is true of the \"-S\" and \"-O\" "
- "options. The before"
- "\n%*sfile and after file sets can intermixed freely, the command "
- "parser will"
- "\n%*ssort them out. The order of the file specifiers (\"-c\", "
- "\"-f\", etc.) is"
- "\n%*snot significant in this regard.\n\n",
- indent_level, "", indent_level, "", indent_level, "", indent_level,
- "", indent_level, "", indent_level, "");
-
- fprintf(
- out,
- "\n%*sIf you don't provide -f then the first argument will be the file "
- "to be"
- "\n%*sdebugged which means that '%s -- <filename> [<ARG1> [<ARG2>]]' also"
- "\n%*sworks. But remember to end the options with \"--\" if any of your"
- "\n%*sarguments have a \"-\" in them.\n\n",
- indent_level, "", indent_level, "", name, indent_level, "", indent_level,
- "");
-}
-
-void BuildGetOptTable(OptionDefinition *expanded_option_table,
- std::vector<struct option> &getopt_table,
- uint32_t num_options) {
- if (num_options == 0)
- return;
-
- uint32_t i;
- uint32_t j;
- std::bitset<256> option_seen;
-
- getopt_table.resize(num_options + 1);
-
- for (i = 0, j = 0; i < num_options; ++i) {
- char short_opt = expanded_option_table[i].short_option;
-
- if (option_seen.test(short_opt) == false) {
- getopt_table[j].name = expanded_option_table[i].long_option;
- getopt_table[j].has_arg = expanded_option_table[i].option_has_arg;
- getopt_table[j].flag = NULL;
- getopt_table[j].val = expanded_option_table[i].short_option;
- option_seen.set(short_opt);
- ++j;
- }
- }
-
- getopt_table[j].name = NULL;
- getopt_table[j].has_arg = 0;
- getopt_table[j].flag = NULL;
- getopt_table[j].val = 0;
-}
-
-Driver::OptionData::OptionData()
- : m_args(), m_script_lang(lldb::eScriptLanguageDefault), m_core_file(),
- m_crash_log(), m_initial_commands(), m_after_file_commands(),
- m_after_crash_commands(), m_debug_mode(false), m_source_quietly(false),
- m_print_version(false), m_print_python_path(false), m_print_help(false),
- m_wait_for(false), m_repl(false), m_repl_lang(eLanguageTypeUnknown),
- m_repl_options(), m_process_name(),
- m_process_pid(LLDB_INVALID_PROCESS_ID), m_use_external_editor(false),
- m_batch(false), m_seen_options() {}
-
-Driver::OptionData::~OptionData() {}
-
-void Driver::OptionData::Clear() {
- m_args.clear();
- m_script_lang = lldb::eScriptLanguageDefault;
- m_initial_commands.clear();
- m_after_file_commands.clear();
-
- // If there is a local .lldbinit, add that to the
- // list of things to be sourced, if the settings
- // permit it.
+void Driver::OptionData::AddLocalLLDBInit() {
+ // If there is a local .lldbinit, add that to the list of things to be
+ // sourced, if the settings permit it.
SBFileSpec local_lldbinit(".lldbinit", true);
-
SBFileSpec homedir_dot_lldb = SBHostOS::GetUserHomeDirectory();
homedir_dot_lldb.AppendPathComponent(".lldbinit");
- // Only read .lldbinit in the current working directory
- // if it's not the same as the .lldbinit in the home
- // directory (which is already being read in).
- if (local_lldbinit.Exists() &&
- strcmp(local_lldbinit.GetDirectory(), homedir_dot_lldb.GetDirectory()) !=
- 0) {
- char path[2048];
- local_lldbinit.GetPath(path, 2047);
+ // Only read .lldbinit in the current working directory if it's not the same
+ // as the .lldbinit in the home directory (which is already being read in).
+ if (local_lldbinit.Exists() && strcmp(local_lldbinit.GetDirectory(),
+ homedir_dot_lldb.GetDirectory()) != 0) {
+ char path[PATH_MAX];
+ local_lldbinit.GetPath(path, sizeof(path));
InitialCmdEntry entry(path, true, true, true);
m_after_file_commands.push_back(entry);
}
-
- m_debug_mode = false;
- m_source_quietly = false;
- m_print_help = false;
- m_print_version = false;
- m_print_python_path = false;
- m_use_external_editor = false;
- m_wait_for = false;
- m_process_name.erase();
- m_batch = false;
- m_after_crash_commands.clear();
-
- m_process_pid = LLDB_INVALID_PROCESS_ID;
}
-void Driver::OptionData::AddInitialCommand(const char *command,
+void Driver::OptionData::AddInitialCommand(std::string command,
CommandPlacement placement,
bool is_file, SBError &error) {
std::vector<InitialCmdEntry> *command_set;
@@ -480,7 +147,7 @@ void Driver::OptionData::AddInitialCommand(const char *command,
}
if (is_file) {
- SBFileSpec file(command);
+ SBFileSpec file(command.c_str());
if (file.Exists())
command_set->push_back(InitialCmdEntry(command, is_file, false));
else if (file.ResolveExecutableLocation()) {
@@ -489,22 +156,21 @@ void Driver::OptionData::AddInitialCommand(const char *command,
command_set->push_back(InitialCmdEntry(final_path, is_file, false));
} else
error.SetErrorStringWithFormat(
- "file specified in --source (-s) option doesn't exist: '%s'", optarg);
+ "file specified in --source (-s) option doesn't exist: '%s'",
+ command.c_str());
} else
command_set->push_back(InitialCmdEntry(command, is_file, false));
}
-void Driver::ResetOptionValues() { m_option_data.Clear(); }
-
const char *Driver::GetFilename() const {
if (m_option_data.m_args.empty())
- return NULL;
+ return nullptr;
return m_option_data.m_args.front().c_str();
}
const char *Driver::GetCrashLogFilename() const {
if (m_option_data.m_crash_log.empty())
- return NULL;
+ return nullptr;
return m_option_data.m_crash_log.c_str();
}
@@ -535,7 +201,7 @@ void Driver::WriteCommandsForSourcing(CommandPlacement placement,
// file in the current working directory), only read it if
// target.load-cwd-lldbinit is 'true'.
if (command_entry.is_cwd_lldbinit_file_read) {
- SBStringList strlist = m_debugger.GetInternalVariableValue(
+ SBStringList strlist = lldb::SBDebugger::GetInternalVariableValue(
"target.load-cwd-lldbinit", m_debugger.GetInstanceName());
if (strlist.GetSize() == 1 &&
strcmp(strlist.GetStringAtIndex(0), "warn") == 0) {
@@ -562,7 +228,8 @@ void Driver::WriteCommandsForSourcing(CommandPlacement placement,
}
bool source_quietly =
m_option_data.m_source_quietly || command_entry.source_quietly;
- strm.Printf("command source -s %i '%s'\n", source_quietly, command);
+ strm.Printf("command source -s %i '%s'\n",
+ static_cast<int>(source_quietly), command);
} else
strm.Printf("%s\n", command);
}
@@ -571,308 +238,232 @@ void Driver::WriteCommandsForSourcing(CommandPlacement placement,
bool Driver::GetDebugMode() const { return m_option_data.m_debug_mode; }
// Check the arguments that were passed to this program to make sure they are
-// valid and to get their
-// argument values (if any). Return a boolean value indicating whether or not
-// to start up the full
-// debugger (i.e. the Command Interpreter) or not. Return FALSE if the
-// arguments were invalid OR
-// if the user only wanted help or version information.
+// valid and to get their argument values (if any). Return a boolean value
+// indicating whether or not to start up the full debugger (i.e. the Command
+// Interpreter) or not. Return FALSE if the arguments were invalid OR if the
+// user only wanted help or version information.
+SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
+ SBError error;
+ m_option_data.AddLocalLLDBInit();
-SBError Driver::ParseArgs(int argc, const char *argv[], FILE *out_fh,
- bool &exiting) {
- ResetOptionValues();
+ // This is kind of a pain, but since we make the debugger in the Driver's
+ // constructor, we can't know at that point whether we should read in init
+ // files yet. So we don't read them in in the Driver constructor, then set
+ // the flags back to "read them in" here, and then if we see the "-n" flag,
+ // we'll turn it off again. Finally we have to read them in by hand later in
+ // the main loop.
+ m_debugger.SkipLLDBInitFiles(false);
+ m_debugger.SkipAppInitFiles(false);
- SBCommandReturnObject result;
+ if (args.hasArg(OPT_version)) {
+ m_option_data.m_print_version = true;
+ }
- SBError error;
- std::string option_string;
- struct option *long_options = NULL;
- std::vector<struct option> long_options_vector;
- uint32_t num_options;
-
- for (num_options = 0; g_options[num_options].long_option != NULL;
- ++num_options)
- /* Do Nothing. */;
-
- if (num_options == 0) {
- if (argc > 1)
- error.SetErrorStringWithFormat("invalid number of options");
- return error;
+ if (args.hasArg(OPT_python_path)) {
+ m_option_data.m_print_python_path = true;
+ }
+
+ if (args.hasArg(OPT_batch)) {
+ m_option_data.m_batch = true;
+ }
+
+ if (auto *arg = args.getLastArg(OPT_core)) {
+ auto arg_value = arg->getValue();
+ SBFileSpec file(arg_value);
+ if (!file.Exists()) {
+ error.SetErrorStringWithFormat(
+ "file specified in --core (-c) option doesn't exist: '%s'",
+ arg_value);
+ return error;
+ }
+ m_option_data.m_core_file = arg_value;
}
- BuildGetOptTable(g_options, long_options_vector, num_options);
+ if (args.hasArg(OPT_editor)) {
+ m_option_data.m_use_external_editor = true;
+ }
- if (long_options_vector.empty())
- long_options = NULL;
- else
- long_options = &long_options_vector.front();
+ if (args.hasArg(OPT_no_lldbinit)) {
+ m_debugger.SkipLLDBInitFiles(true);
+ m_debugger.SkipAppInitFiles(true);
+ }
- if (long_options == NULL) {
- error.SetErrorStringWithFormat("invalid long options");
- return error;
+ if (args.hasArg(OPT_no_use_colors)) {
+ m_debugger.SetUseColor(false);
}
- // Build the option_string argument for call to getopt_long_only.
-
- for (int i = 0; long_options[i].name != NULL; ++i) {
- if (long_options[i].flag == NULL) {
- option_string.push_back((char)long_options[i].val);
- switch (long_options[i].has_arg) {
- default:
- case no_argument:
- break;
- case required_argument:
- option_string.push_back(':');
- break;
- case optional_argument:
- option_string.append("::");
- break;
- }
+ if (auto *arg = args.getLastArg(OPT_file)) {
+ auto arg_value = arg->getValue();
+ SBFileSpec file(arg_value);
+ if (file.Exists()) {
+ m_option_data.m_args.emplace_back(arg_value);
+ } else if (file.ResolveExecutableLocation()) {
+ char path[PATH_MAX];
+ file.GetPath(path, sizeof(path));
+ m_option_data.m_args.emplace_back(path);
+ } else {
+ error.SetErrorStringWithFormat(
+ "file specified in --file (-f) option doesn't exist: '%s'",
+ arg_value);
+ return error;
}
}
- // This is kind of a pain, but since we make the debugger in the Driver's
- // constructor, we can't
- // know at that point whether we should read in init files yet. So we don't
- // read them in in the
- // Driver constructor, then set the flags back to "read them in" here, and
- // then if we see the
- // "-n" flag, we'll turn it off again. Finally we have to read them in by
- // hand later in the
- // main loop.
+ if (auto *arg = args.getLastArg(OPT_arch)) {
+ auto arg_value = arg->getValue();
+ if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {
+ error.SetErrorStringWithFormat(
+ "invalid architecture in the -a or --arch option: '%s'", arg_value);
+ return error;
+ }
+ }
- m_debugger.SkipLLDBInitFiles(false);
- m_debugger.SkipAppInitFiles(false);
+ if (auto *arg = args.getLastArg(OPT_script_language)) {
+ auto arg_value = arg->getValue();
+ m_option_data.m_script_lang = m_debugger.GetScriptingLanguage(arg_value);
+ }
-// Prepare for & make calls to getopt_long_only.
-#if __GLIBC__
- optind = 0;
-#else
- optreset = 1;
- optind = 1;
-#endif
- int val;
- while (1) {
- int long_options_index = -1;
- val = ::getopt_long_only(argc, const_cast<char **>(argv),
- option_string.c_str(), long_options,
- &long_options_index);
-
- if (val == -1)
- break;
- else if (val == '?') {
- m_option_data.m_print_help = true;
- error.SetErrorStringWithFormat("unknown or ambiguous option");
- break;
- } else if (val == 0)
- continue;
- else {
- m_option_data.m_seen_options.insert((char)val);
- if (long_options_index == -1) {
- for (int i = 0; long_options[i].name || long_options[i].has_arg ||
- long_options[i].flag || long_options[i].val;
- ++i) {
- if (long_options[i].val == val) {
- long_options_index = i;
- break;
- }
- }
- }
+ if (args.hasArg(OPT_no_use_colors)) {
+ m_option_data.m_debug_mode = true;
+ }
- if (long_options_index >= 0) {
- const int short_option = g_options[long_options_index].short_option;
-
- switch (short_option) {
- case 'h':
- m_option_data.m_print_help = true;
- break;
-
- case 'v':
- m_option_data.m_print_version = true;
- break;
-
- case 'P':
- m_option_data.m_print_python_path = true;
- break;
-
- case 'b':
- m_option_data.m_batch = true;
- break;
-
- case 'c': {
- SBFileSpec file(optarg);
- if (file.Exists()) {
- m_option_data.m_core_file = optarg;
- } else
- error.SetErrorStringWithFormat(
- "file specified in --core (-c) option doesn't exist: '%s'",
- optarg);
- } break;
-
- case 'e':
- m_option_data.m_use_external_editor = true;
- break;
-
- case 'x':
- m_debugger.SkipLLDBInitFiles(true);
- m_debugger.SkipAppInitFiles(true);
- break;
-
- case 'X':
- m_debugger.SetUseColor(false);
- break;
-
- case 'f': {
- SBFileSpec file(optarg);
- if (file.Exists()) {
- m_option_data.m_args.push_back(optarg);
- } else if (file.ResolveExecutableLocation()) {
- char path[PATH_MAX];
- file.GetPath(path, sizeof(path));
- m_option_data.m_args.push_back(path);
- } else
- error.SetErrorStringWithFormat(
- "file specified in --file (-f) option doesn't exist: '%s'",
- optarg);
- } break;
-
- case 'a':
- if (!m_debugger.SetDefaultArchitecture(optarg))
- error.SetErrorStringWithFormat(
- "invalid architecture in the -a or --arch option: '%s'",
- optarg);
- break;
-
- case 'l':
- m_option_data.m_script_lang = m_debugger.GetScriptingLanguage(optarg);
- break;
-
- case 'd':
- m_option_data.m_debug_mode = true;
- break;
-
- case 'Q':
- m_option_data.m_source_quietly = true;
- break;
-
- case 'K':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash,
- true, error);
- break;
- case 'k':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash,
- false, error);
- break;
-
- case 'n':
- m_option_data.m_process_name = optarg;
- break;
-
- case 'w':
- m_option_data.m_wait_for = true;
- break;
-
- case 'p': {
- char *remainder;
- m_option_data.m_process_pid = strtol(optarg, &remainder, 0);
- if (remainder == optarg || *remainder != '\0')
- error.SetErrorStringWithFormat(
- "Could not convert process PID: \"%s\" into a pid.", optarg);
- } break;
-
- case 'r':
- m_option_data.m_repl = true;
- if (optarg && optarg[0])
- m_option_data.m_repl_options = optarg;
- else
- m_option_data.m_repl_options.clear();
- break;
-
- case 'R':
- m_option_data.m_repl_lang =
- SBLanguageRuntime::GetLanguageTypeFromString(optarg);
- if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
- error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
- optarg);
- }
- break;
-
- case 's':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile,
- true, error);
- break;
- case 'o':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile,
- false, error);
- break;
- case 'S':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile,
- true, error);
- break;
- case 'O':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile,
- false, error);
- break;
- default:
- m_option_data.m_print_help = true;
- error.SetErrorStringWithFormat("unrecognized option %c",
- short_option);
- break;
- }
- } else {
- error.SetErrorStringWithFormat("invalid option with value %i", val);
- }
- if (error.Fail()) {
+ if (args.hasArg(OPT_no_use_colors)) {
+ m_debugger.SetUseColor(false);
+ }
+
+ if (args.hasArg(OPT_source_quietly)) {
+ m_option_data.m_source_quietly = true;
+ }
+
+ if (auto *arg = args.getLastArg(OPT_attach_name)) {
+ auto arg_value = arg->getValue();
+ m_option_data.m_process_name = arg_value;
+ }
+
+ if (args.hasArg(OPT_wait_for)) {
+ m_option_data.m_wait_for = true;
+ }
+
+ if (auto *arg = args.getLastArg(OPT_attach_pid)) {
+ auto arg_value = arg->getValue();
+ char *remainder;
+ m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);
+ if (remainder == arg_value || *remainder != '\0') {
+ error.SetErrorStringWithFormat(
+ "Could not convert process PID: \"%s\" into a pid.", arg_value);
+ return error;
+ }
+ }
+
+ if (auto *arg = args.getLastArg(OPT_repl_language)) {
+ auto arg_value = arg->getValue();
+ m_option_data.m_repl_lang =
+ SBLanguageRuntime::GetLanguageTypeFromString(arg_value);
+ if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
+ error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
+ arg_value);
+ return error;
+ }
+ }
+
+ if (args.hasArg(OPT_repl)) {
+ m_option_data.m_repl = true;
+ }
+
+ if (auto *arg = args.getLastArg(OPT_repl_)) {
+ m_option_data.m_repl = true;
+ if (auto arg_value = arg->getValue())
+ m_option_data.m_repl_options = arg_value;
+ }
+
+ // We need to process the options below together as their relative order
+ // matters.
+ for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,
+ OPT_source, OPT_source_before_file,
+ OPT_one_line, OPT_one_line_before_file)) {
+ auto arg_value = arg->getValue();
+ if (arg->getOption().matches(OPT_source_on_crash)) {
+ m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
+ true, error);
+ if (error.Fail())
+ return error;
+ }
+
+ if (arg->getOption().matches(OPT_one_line_on_crash)) {
+ m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
+ false, error);
+ if (error.Fail())
+ return error;
+ }
+
+ if (arg->getOption().matches(OPT_source)) {
+ m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
+ true, error);
+ if (error.Fail())
+ return error;
+ }
+
+ if (arg->getOption().matches(OPT_source_before_file)) {
+ m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
+ true, error);
+ if (error.Fail())
+ return error;
+ }
+
+ if (arg->getOption().matches(OPT_one_line)) {
+ m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
+ false, error);
+ if (error.Fail())
+ return error;
+ }
+
+ if (arg->getOption().matches(OPT_one_line_before_file)) {
+ m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
+ false, error);
+ if (error.Fail())
return error;
+ }
+ }
+
+ if (m_option_data.m_process_name.empty() &&
+ m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
+
+ // If the option data args array is empty that means the file was not
+ // specified with -f and we need to get it from the input args.
+ if (m_option_data.m_args.empty()) {
+ if (auto *arg = args.getLastArgNoClaim(OPT_INPUT)) {
+ m_option_data.m_args.push_back(arg->getAsString((args)));
}
}
+
+ // Any argument following -- is an argument for the inferior.
+ if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
+ for (auto value : arg->getValues())
+ m_option_data.m_args.emplace_back(value);
+ }
+ } else if (args.getLastArgNoClaim() != nullptr) {
+ WithColor::warning() << "program arguments are ignored when attaching.\n";
}
- if (error.Fail() || m_option_data.m_print_help) {
- ShowUsage(out_fh, g_options, m_option_data);
- exiting = true;
- } else if (m_option_data.m_print_version) {
- ::fprintf(out_fh, "%s\n", m_debugger.GetVersionString());
+ if (m_option_data.m_print_version) {
+ llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
exiting = true;
- } else if (m_option_data.m_print_python_path) {
+ return error;
+ }
+
+ if (m_option_data.m_print_python_path) {
SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
if (python_file_spec.IsValid()) {
char python_path[PATH_MAX];
size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
if (num_chars < PATH_MAX) {
- ::fprintf(out_fh, "%s\n", python_path);
+ llvm::outs() << python_path << '\n';
} else
- ::fprintf(out_fh, "<PATH TOO LONG>\n");
+ llvm::outs() << "<PATH TOO LONG>\n";
} else
- ::fprintf(out_fh, "<COULD NOT FIND PATH>\n");
+ llvm::outs() << "<COULD NOT FIND PATH>\n";
exiting = true;
- } else if (m_option_data.m_process_name.empty() &&
- m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
- // Any arguments that are left over after option parsing are for
- // the program. If a file was specified with -f then the filename
- // is already in the m_option_data.m_args array, and any remaining args
- // are arguments for the inferior program. If no file was specified with
- // -f, then what is left is the program name followed by any arguments.
-
- // Skip any options we consumed with getopt_long_only
- argc -= optind;
- argv += optind;
-
- if (argc > 0) {
- for (int arg_idx = 0; arg_idx < argc; ++arg_idx) {
- const char *arg = argv[arg_idx];
- if (arg)
- m_option_data.m_args.push_back(arg);
- }
- }
-
- } else {
- // Skip any options we consumed with getopt_long_only
- argc -= optind;
-
- if (argc > 0)
- ::fprintf(out_fh,
- "Warning: program arguments are ignored when attaching.\n");
+ return error;
}
return error;
@@ -882,7 +473,7 @@ static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
size_t commands_size, int fds[2]) {
enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
- ::FILE *commands_file = NULL;
+ ::FILE *commands_file = nullptr;
fds[0] = -1;
fds[1] = -1;
int err = 0;
@@ -894,10 +485,13 @@ static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
if (err == 0) {
ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
if (nrwr < 0) {
- fprintf(stderr, "error: write(%i, %p, %" PRIu64 ") failed (errno = %i) "
- "when trying to open LLDB commands pipe\n",
- fds[WRITE], static_cast<const void *>(commands_data),
- static_cast<uint64_t>(commands_size), errno);
+ WithColor::error()
+ << format(
+ "write(%i, %p, %" PRIu64
+ ") failed (errno = %i) when trying to open LLDB commands pipe",
+ fds[WRITE], static_cast<const void *>(commands_data),
+ static_cast<uint64_t>(commands_size), errno)
+ << '\n';
} else if (static_cast<size_t>(nrwr) == commands_size) {
// Close the write end of the pipe so when we give the read end to
// the debugger/command interpreter it will exit when it consumes all
@@ -912,20 +506,20 @@ static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
// Now open the read file descriptor in a FILE * that we can give to
// the debugger as an input handle
commands_file = fdopen(fds[READ], "r");
- if (commands_file) {
- fds[READ] =
- -1; // The FILE * 'commands_file' now owns the read descriptor
- // Hand ownership if the FILE * over to the debugger for
- // "commands_file".
+ if (commands_file != nullptr) {
+ fds[READ] = -1; // The FILE * 'commands_file' now owns the read
+ // descriptor Hand ownership if the FILE * over to the
+ // debugger for "commands_file".
} else {
- fprintf(stderr, "error: fdopen(%i, \"r\") failed (errno = %i) when "
- "trying to open LLDB commands pipe\n",
- fds[READ], errno);
+ WithColor::error() << format("fdopen(%i, \"r\") failed (errno = %i) "
+ "when trying to open LLDB commands pipe",
+ fds[READ], errno)
+ << '\n';
}
}
} else {
- fprintf(stderr,
- "error: can't create pipe file descriptors for LLDB commands\n");
+ WithColor::error()
+ << "can't create pipe file descriptors for LLDB commands\n";
}
return commands_file;
@@ -975,9 +569,9 @@ int Driver::MainLoop() {
// Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
// which causes it to miss newlines depending on whether there have been an
// odd or even number of characters. Bug has been reported to MS via Connect.
- ::setbuf(stdin, NULL);
+ ::setbuf(stdin, nullptr);
#endif
- ::setbuf(stdout, NULL);
+ ::setbuf(stdout, nullptr);
m_debugger.SetErrorFileHandle(stderr, false);
m_debugger.SetOutputFileHandle(stdout, false);
@@ -987,7 +581,7 @@ int Driver::MainLoop() {
m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
struct winsize window_size;
- if (isatty(STDIN_FILENO) &&
+ if ((isatty(STDIN_FILENO) != 0) &&
::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
if (window_size.ws_col > 0)
m_debugger.SetTerminalWidth(window_size.ws_col);
@@ -1018,7 +612,7 @@ int Driver::MainLoop() {
const size_t num_args = m_option_data.m_args.size();
if (num_args > 0) {
char arch_name[64];
- if (m_debugger.GetDefaultArchitecture(arch_name, sizeof(arch_name)))
+ if (lldb::SBDebugger::GetDefaultArchitecture(arch_name, sizeof(arch_name)))
commands_stream.Printf("target create --arch=%s %s", arch_name,
EscapeString(m_option_data.m_args[0]).c_str());
else
@@ -1066,16 +660,16 @@ int Driver::MainLoop() {
bool spawn_thread = false;
if (m_option_data.m_repl) {
- const char *repl_options = NULL;
+ const char *repl_options = nullptr;
if (!m_option_data.m_repl_options.empty())
repl_options = m_option_data.m_repl_options.c_str();
SBError error(m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
if (error.Fail()) {
const char *error_cstr = error.GetCString();
- if (error_cstr && error_cstr[0])
- fprintf(stderr, "error: %s\n", error_cstr);
+ if ((error_cstr != nullptr) && (error_cstr[0] != 0))
+ WithColor::error() << error_cstr << '\n';
else
- fprintf(stderr, "error: %u\n", error.GetError());
+ WithColor::error() << error.GetError() << '\n';
}
} else {
// Check if we have any data in the commands stream, and if so, save it to a
@@ -1088,12 +682,12 @@ int Driver::MainLoop() {
// track that.
bool quit_requested = false;
bool stopped_for_crash = false;
- if (commands_data && commands_size) {
+ if ((commands_data != nullptr) && (commands_size != 0u)) {
int initial_commands_fds[2];
bool success = true;
FILE *commands_file = PrepareCommandsForSourcing(
commands_data, commands_size, initial_commands_fds);
- if (commands_file) {
+ if (commands_file != nullptr) {
m_debugger.SetInputFileHandle(commands_file, true);
// Set the debugger into Sync mode when running the command file.
@@ -1122,7 +716,7 @@ int Driver::MainLoop() {
const size_t crash_commands_size = crash_commands_stream.GetSize();
commands_file = PrepareCommandsForSourcing(
crash_commands_data, crash_commands_size, crash_command_fds);
- if (commands_file) {
+ if (commands_file != nullptr) {
bool local_quit_requested;
bool local_stopped_for_crash;
m_debugger.SetInputFileHandle(commands_file, true);
@@ -1177,9 +771,9 @@ void Driver::ResizeWindow(unsigned short col) {
void sigwinch_handler(int signo) {
struct winsize window_size;
- if (isatty(STDIN_FILENO) &&
+ if ((isatty(STDIN_FILENO) != 0) &&
::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
- if ((window_size.ws_col > 0) && g_driver != NULL) {
+ if ((window_size.ws_col > 0) && g_driver != nullptr) {
g_driver->ResizeWindow(window_size.ws_col);
}
}
@@ -1187,7 +781,7 @@ void sigwinch_handler(int signo) {
void sigint_handler(int signo) {
static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
- if (g_driver) {
+ if (g_driver != nullptr) {
if (!g_interrupt_sent.test_and_set()) {
g_driver->GetDebugger().DispatchInputInterrupt();
g_interrupt_sent.clear();
@@ -1199,7 +793,7 @@ void sigint_handler(int signo) {
}
void sigtstp_handler(int signo) {
- if (g_driver)
+ if (g_driver != nullptr)
g_driver->GetDebugger().SaveInputTerminalState();
signal(signo, SIG_DFL);
@@ -1208,7 +802,7 @@ void sigtstp_handler(int signo) {
}
void sigcont_handler(int signo) {
- if (g_driver)
+ if (g_driver != nullptr)
g_driver->GetDebugger().RestoreInputTerminalState();
signal(signo, SIG_DFL);
@@ -1216,6 +810,45 @@ void sigcont_handler(int signo) {
signal(signo, sigcont_handler);
}
+static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
+ std::string usage_str = tool_name.str() + "options";
+ table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
+
+ std::string examples = R"___(
+EXAMPLES:
+ The debugger can be started in several modes.
+
+ Passing an executable as a positional argument prepares lldb to debug the
+ given executable. Arguments passed after -- are considered arguments to the
+ debugged executable.
+
+ lldb --arch x86_64 /path/to/program -- --arch arvm7
+
+ Passing one of the attach options causes lldb to immediately attach to the
+ given process.
+
+ lldb -p <pid>
+ lldb -n <process-name>
+
+ Passing --repl starts lldb in REPL mode.
+
+ lldb -r
+
+ Passing --core causes lldb to debug the core file.
+
+ lldb -c /path/to/core
+
+ Command options can be combined with either mode and cause lldb to run the
+ specified commands before or after events, like loading the file or crashing,
+ in the order provided on the command line.
+
+ lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
+ lldb -S /source/before/file -s /source/after/file
+ lldb -K /source/before/crash -k /source/after/crash
+ )___";
+ llvm::outs() << examples;
+}
+
int
#ifdef _MSC_VER
wmain(int argc, wchar_t const *wargv[])
@@ -1234,11 +867,48 @@ main(int argc, char const *argv[])
const char **argv = argvPointers.data();
#endif
- llvm::StringRef ToolName = argv[0];
+ // Print stack trace on crash.
+ llvm::StringRef ToolName = llvm::sys::path::filename(argv[0]);
llvm::sys::PrintStackTraceOnErrorSignal(ToolName);
llvm::PrettyStackTraceProgram X(argc, argv);
- SBDebugger::Initialize();
+ // Parse arguments.
+ LLDBOptTable T;
+ unsigned MAI;
+ unsigned MAC;
+ ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
+ opt::InputArgList input_args = T.ParseArgs(arg_arr, MAI, MAC);
+
+ if (input_args.hasArg(OPT_help)) {
+ printHelp(T, ToolName);
+ return 0;
+ }
+
+ for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
+ WithColor::warning() << "ignoring unknown option: " << arg->getSpelling()
+ << '\n';
+ }
+
+ SBInitializerOptions options;
+
+ if (auto *arg = input_args.getLastArg(OPT_capture)) {
+ auto arg_value = arg->getValue();
+ options.SetReproducerPath(arg_value);
+ options.SetCaptureReproducer(true);
+ }
+
+ if (auto *arg = input_args.getLastArg(OPT_replay)) {
+ auto arg_value = arg->getValue();
+ options.SetReplayReproducer(true);
+ options.SetReproducerPath(arg_value);
+ }
+
+ SBError error = SBDebugger::Initialize(options);
+ if (error.Fail()) {
+ WithColor::error() << "initialization failed: " << error.GetCString()
+ << '\n';
+ return 1;
+ }
SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
@@ -1257,12 +927,11 @@ main(int argc, char const *argv[])
Driver driver;
bool exiting = false;
- SBError error(driver.ParseArgs(argc, argv, stdout, exiting));
+ SBError error(driver.ProcessArgs(input_args, exiting));
if (error.Fail()) {
exit_code = 1;
- const char *error_cstr = error.GetCString();
- if (error_cstr)
- ::fprintf(stderr, "error: %s\n", error_cstr);
+ if (const char *error_cstr = error.GetCString())
+ WithColor::error() << error_cstr << '\n';
} else if (!exiting) {
exit_code = driver.MainLoop();
}
diff --git a/tools/driver/Driver.h b/tools/driver/Driver.h
index 34746a239999..3f2b0759255a 100644
--- a/tools/driver/Driver.h
+++ b/tools/driver/Driver.h
@@ -11,19 +11,19 @@
#define lldb_Driver_h_
#include "Platform.h"
-#include "lldb/Host/PseudoTerminal.h"
-
-#include <bitset>
-#include <set>
-#include <string>
-#include <vector>
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBError.h"
-class IOChannel;
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+
+#include <set>
+#include <string>
+#include <vector>
class Driver : public lldb::SBBroadcaster {
public:
@@ -42,8 +42,7 @@ public:
/// @return The exit code that the process should return.
int MainLoop();
- lldb::SBError ParseArgs(int argc, const char *argv[], FILE *out_fh,
- bool &do_exit);
+ lldb::SBError ProcessArgs(const llvm::opt::InputArgList &args, bool &exiting);
const char *GetFilename() const;
@@ -58,60 +57,57 @@ public:
bool GetDebugMode() const;
- class OptionData {
- public:
- OptionData();
- ~OptionData();
-
- void Clear();
-
- void AddInitialCommand(const char *command, CommandPlacement placement,
+ struct OptionData {
+ void AddLocalLLDBInit();
+ void AddInitialCommand(std::string command, CommandPlacement placement,
bool is_file, lldb::SBError &error);
- // static OptionDefinition m_cmd_option_table[];
-
struct InitialCmdEntry {
- InitialCmdEntry(const char *in_contents, bool in_is_file,
+ InitialCmdEntry(std::string contents, bool in_is_file,
bool is_cwd_lldbinit_file_read, bool in_quiet = false)
- : contents(in_contents), is_file(in_is_file),
- is_cwd_lldbinit_file_read(is_cwd_lldbinit_file_read),
- source_quietly(in_quiet) {}
+ : contents(std::move(contents)), is_file(in_is_file),
+ source_quietly(in_quiet),
+ is_cwd_lldbinit_file_read(is_cwd_lldbinit_file_read) {}
std::string contents;
bool is_file;
- bool is_cwd_lldbinit_file_read; // if this is reading ./.lldbinit - so we
- // may skip if not permitted
bool source_quietly;
+
+ /// Remember if this is reading the local lldbinit file so we can skip it
+ /// if not permitted.
+ bool is_cwd_lldbinit_file_read;
};
std::vector<std::string> m_args;
- lldb::ScriptLanguage m_script_lang;
+
+ lldb::ScriptLanguage m_script_lang = lldb::eScriptLanguageDefault;
+ lldb::LanguageType m_repl_lang = lldb::eLanguageTypeUnknown;
+ lldb::pid_t m_process_pid = LLDB_INVALID_PROCESS_ID;
+
std::string m_core_file;
std::string m_crash_log;
+ std::string m_repl_options;
+ std::string m_process_name;
+
std::vector<InitialCmdEntry> m_initial_commands;
std::vector<InitialCmdEntry> m_after_file_commands;
std::vector<InitialCmdEntry> m_after_crash_commands;
- bool m_debug_mode;
- bool m_source_quietly;
- bool m_print_version;
- bool m_print_python_path;
- bool m_print_help;
- bool m_wait_for;
- bool m_repl;
- lldb::LanguageType m_repl_lang;
- std::string m_repl_options;
- std::string m_process_name;
- lldb::pid_t m_process_pid;
- bool m_use_external_editor; // FIXME: When we have set/show variables we can
- // remove this from here.
- bool m_batch;
- typedef std::set<char> OptionSet;
+
+ bool m_debug_mode = false;
+ bool m_source_quietly = false;
+ bool m_print_version = false;
+ bool m_print_python_path = false;
+ bool m_wait_for = false;
+ bool m_repl = false;
+ bool m_batch = false;
+
+ // FIXME: When we have set/show variables we can remove this from here.
+ bool m_use_external_editor = false;
+
+ using OptionSet = std::set<char>;
OptionSet m_seen_options;
};
- static lldb::SBError SetOptionValue(int option_idx, const char *option_arg,
- Driver::OptionData &data);
-
lldb::SBDebugger &GetDebugger() { return m_debugger; }
void ResizeWindow(unsigned short col);
@@ -119,10 +115,6 @@ public:
private:
lldb::SBDebugger m_debugger;
OptionData m_option_data;
-
- void ResetOptionValues();
-
- void ReadyForCommand();
};
#endif // lldb_Driver_h_
diff --git a/tools/driver/Options.td b/tools/driver/Options.td
new file mode 100644
index 000000000000..563c0b54fb98
--- /dev/null
+++ b/tools/driver/Options.td
@@ -0,0 +1,229 @@
+include "llvm/Option/OptParser.td"
+
+class F<string name>: Flag<["--", "-"], name>;
+class S<string name>: Separate<["--", "-"], name>;
+class R<list<string> prefixes, string name>
+ : Option<prefixes, name, KIND_REMAINING_ARGS>;
+
+// Attaching options.
+def grp_attach : OptionGroup<"attaching">, HelpText<"ATTACHING">;
+
+def attach_name: Separate<["--", "-"], "attach-name">,
+ MetaVarName<"<name>">,
+ HelpText<"Tells the debugger to attach to a process with the given name.">,
+ Group<grp_attach>;
+def: Separate<["-"], "n">,
+ Alias<attach_name>,
+ HelpText<"Alias for --attach-name">,
+ Group<grp_attach>;
+
+def wait_for: F<"wait-for">,
+ HelpText<"Tells the debugger to wait for a process with the given pid or name to launch before attaching.">,
+ Group<grp_attach>;
+def: Flag<["-"], "w">,
+ Alias<wait_for>,
+ HelpText<"Alias for --wait-for">,
+ Group<grp_attach>;
+
+def attach_pid: Separate<["--", "-"], "attach-pid">,
+ MetaVarName<"<pid>">,
+ HelpText<"Tells the debugger to attach to a process with the given pid.">,
+ Group<grp_attach>;
+def: Separate<["-"], "p">,
+ Alias<attach_pid>,
+ HelpText<"Alias for --attach-pid">,
+ Group<grp_attach>;
+
+
+// Scripting options.
+def grp_scripting : OptionGroup<"scripting">, HelpText<"SCRIPTING">;
+
+def python_path: F<"python-path">,
+ HelpText<"Prints out the path to the lldb.py file for this version of lldb.">,
+ Group<grp_scripting>;
+def: Flag<["-"], "P">,
+ Alias<python_path>,
+ HelpText<"Alias for --python-path">,
+ Group<grp_scripting>;
+
+def script_language: Separate<["--", "-"], "script-language">,
+ MetaVarName<"<language>">,
+ HelpText<"Tells the debugger to use the specified scripting language for user-defined scripts.">,
+ Group<grp_scripting>;
+def: Separate<["-"], "l">,
+ Alias<script_language>,
+ HelpText<"Alias for --script-language">,
+ Group<grp_scripting>;
+
+// Repl options.
+def grp_repl : OptionGroup<"repl">, HelpText<"REPL">;
+
+def repl: Flag<["--", "-"], "repl">,
+ HelpText<"Runs lldb in REPL mode with a stub process.">,
+ Group<grp_repl>;
+def: Flag<["-"], "r">,
+ Alias<repl>,
+ HelpText<"Alias for --repl">,
+ Group<grp_repl>;
+def repl_: Joined<["--", "-"], "repl=">,
+ MetaVarName<"<flags>">,
+ HelpText<"Runs lldb in REPL mode with a stub process with the given flags.">,
+ Group<grp_repl>;
+def: Joined<["-"], "r=">,
+ MetaVarName<"<flags>">,
+ Alias<repl_>,
+ HelpText<"Alias for --repl=<flags>">,
+ Group<grp_repl>;
+
+def repl_language: Separate<["--", "-"], "repl-language">,
+ MetaVarName<"<language>">,
+ HelpText<"Chooses the language for the REPL.">,
+ Group<grp_repl>;
+def: Separate<["-"], "R">,
+ Alias<repl_language>,
+ HelpText<"Alias for --repl-language">,
+ Group<grp_repl>;
+
+
+// Command options.
+def grp_command : OptionGroup<"command">, HelpText<"COMMANDS">;
+
+def no_lldbinit: F<"no-lldbinit">,
+ HelpText<"Do not automatically parse any '.lldbinit' files.">,
+ Group<grp_command>;
+def: Flag<["-"], "x">,
+ Alias<no_lldbinit>,
+ HelpText<"Alias for --no-lldbinit">,
+ Group<grp_command>;
+
+def batch: F<"batch">,
+ HelpText<"Tells the debugger to run the commands from -s, -S, -o & -O, and then quit.">,
+ Group<grp_command>;
+def: Flag<["-"], "b">,
+ Alias<batch>,
+ HelpText<"Alias for --batch">,
+ Group<grp_command>;
+
+def source_quietly: F<"source-quietly">,
+ HelpText<"Tells the debugger to execute this one-line lldb command before any file has been loaded.">,
+ Group<grp_command>;
+def: Flag<["-"], "Q">,
+ Alias<source_quietly>,
+ HelpText<"Alias for --source-quietly">,
+ Group<grp_command>;
+
+def one_line_on_crash: Separate<["--", "-"], "one-line-on-crash">,
+ MetaVarName<"<command>">,
+ HelpText<"When in batch mode, tells the debugger to source this file of lldb commands if the target crashes.">,
+ Group<grp_command>;
+def: Separate<["-"], "k">,
+ Alias<one_line_on_crash>,
+ HelpText<"Alias for --one-line-on-crash">,
+ Group<grp_command>;
+
+def source_on_crash: Separate<["--", "-"], "source-on-crash">,
+ MetaVarName<"<file>">,
+ HelpText<"When in batch mode, tells the debugger to source this file of lldb commands if the target crashes.">,
+ Group<grp_command>;
+def: Separate<["-"], "K">,
+ Alias<source_on_crash>,
+ HelpText<"Alias for --source-on-crash">,
+ Group<grp_command>;
+
+def source: Separate<["--", "-"], "source">,
+ MetaVarName<"<file>">,
+ HelpText<"Tells the debugger to read in and execute the lldb commands in the given file, after any file has been loaded.">,
+ Group<grp_command>;
+def: Separate<["-"], "s">,
+ Alias<source>,
+ HelpText<"Alias for --source">,
+ Group<grp_command>;
+
+def source_before_file: Separate<["--", "-"], "source-before-file">,
+ MetaVarName<"<file>">,
+ HelpText<"Tells the debugger to read in and execute the lldb commands in the given file, before any file has been loaded.">,
+ Group<grp_command>;
+def: Separate<["-"], "S">,
+ Alias<source_before_file>,
+ HelpText<"Alias for --source-before-file">,
+ Group<grp_command>;
+
+def one_line: Separate<["--", "-"], "one-line">,
+ MetaVarName<"<command>">,
+ HelpText<"Tells the debugger to execute this one-line lldb command after any file provided on the command line has been loaded.">,
+ Group<grp_command>;
+def: Separate<["-"], "o">,
+ Alias<one_line>,
+ HelpText<"Alias for --one-line">,
+ Group<grp_command>;
+
+def one_line_before_file: Separate<["--", "-"], "one-line-before-file">,
+ MetaVarName<"<command>">,
+ HelpText<"Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded.">,
+ Group<grp_command>;
+def: Separate<["-"], "O">,
+ Alias<one_line_before_file>,
+ HelpText<"Alias for --one-line-before-file">,
+ Group<grp_command>;
+
+
+// General options.
+def version: F<"version">,
+ HelpText<"Prints out the current version number of the LLDB debugger.">;
+def: Flag<["-"], "v">,
+ Alias<version>,
+ HelpText<"Alias for --version">;
+
+def help: F<"help">,
+ HelpText<"Prints out the usage information for the LLDB debugger.">;
+def: Flag<["-"], "h">,
+ Alias<help>,
+ HelpText<"Alias for --help">;
+
+def core: Separate<["--", "-"], "core">,
+ MetaVarName<"<filename>">,
+ HelpText<"Tells the debugger to use the full path to <filename> as the core file.">;
+def: Separate<["-"], "c">,
+ Alias<core>,
+ HelpText<"Alias for --core">;
+
+def editor: F<"editor">,
+ HelpText<"Tells the debugger to open source files using the host's \"external editor\" mechanism.">;
+def: Flag<["-"], "e">,
+ Alias<editor>,
+ HelpText<"Alias for --editor">;
+
+def no_use_colors: F<"no-use-colors">,
+ HelpText<"Do not use colors.">;
+def: Flag<["-"], "X">,
+ Alias<no_use_colors>,
+ HelpText<"Alias for --no-use-color">;
+
+def file: Separate<["--", "-"], "file">,
+ MetaVarName<"<filename>">,
+ HelpText<"Tells the debugger to use the file <filename> as the program to be debugged.">;
+def: Separate<["-"], "f">,
+ Alias<file>,
+ HelpText<"Alias for --file">;
+
+def arch: Separate<["--", "-"], "arch">,
+ MetaVarName<"<architecture>">,
+ HelpText<"Tells the debugger to use the specified architecture when starting and running the program.">;
+def: Separate<["-"], "a">,
+ Alias<arch>,
+ HelpText<"Alias for --arch">;
+
+def debug: F<"debug">,
+ HelpText<"Tells the debugger to print out extra information for debugging itself.">;
+def: Flag<["-"], "d">,
+ Alias<debug>,
+ HelpText<"Alias for --debug">;
+
+def capture: Separate<["--", "-"], "capture">,
+ MetaVarName<"<filename>">,
+ HelpText<"Tells the debugger to capture a reproducer to <filename>.">;
+def replay: Separate<["--", "-"], "replay">,
+ MetaVarName<"<filename>">,
+ HelpText<"Tells the debugger to replay a reproducer from <filename>.">;
+
+def REM : R<["--"], "">;
diff --git a/tools/driver/Platform.h b/tools/driver/Platform.h
index 521c5a1ccbb5..1bb42f9cfc16 100644
--- a/tools/driver/Platform.h
+++ b/tools/driver/Platform.h
@@ -12,7 +12,6 @@
#if defined(_WIN32)
-#include "lldb/Host/HostGetOpt.h"
#include <io.h>
#if defined(_MSC_VER)
#include <signal.h>
@@ -61,7 +60,6 @@ struct timeval {
long tv_usec;
};
typedef long pid_t;
-#define snprintf _snprintf
#define PATH_MAX MAX_PATH
#endif
@@ -74,7 +72,6 @@ extern int tcsetattr(int fd, int optional_actions,
extern int tcgetattr(int fildes, struct termios *termios_p);
#else
-#include "lldb/Host/HostGetOpt.h"
#include <inttypes.h>
#include <libgen.h>
diff --git a/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp b/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp
index e654f076fb3a..df1221f3ccff 100644
--- a/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp
+++ b/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp
@@ -12,7 +12,6 @@
#include <cerrno>
#include <string>
-// Project includes
#include "cli-wrapper-mpxtable.h"
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBCommandReturnObject.h"
diff --git a/tools/intel-features/intel-pt/Decoder.cpp b/tools/intel-features/intel-pt/Decoder.cpp
index 0c385adc811c..f838ff4c1e6e 100644
--- a/tools/intel-features/intel-pt/Decoder.cpp
+++ b/tools/intel-features/intel-pt/Decoder.cpp
@@ -7,14 +7,12 @@
//
//===----------------------------------------------------------------------===//
-// 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"
diff --git a/tools/intel-features/intel-pt/Decoder.h b/tools/intel-features/intel-pt/Decoder.h
index 3762196058fd..58ebb7e734cb 100644
--- a/tools/intel-features/intel-pt/Decoder.h
+++ b/tools/intel-features/intel-pt/Decoder.h
@@ -16,7 +16,6 @@
#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"
diff --git a/tools/intel-features/intel-pt/PTDecoder.cpp b/tools/intel-features/intel-pt/PTDecoder.cpp
index 4f3554e84d3c..72effbe3da79 100644
--- a/tools/intel-features/intel-pt/PTDecoder.cpp
+++ b/tools/intel-features/intel-pt/PTDecoder.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// Project includes
#include "PTDecoder.h"
#include "Decoder.h"
diff --git a/tools/intel-features/intel-pt/PTDecoder.h b/tools/intel-features/intel-pt/PTDecoder.h
index 8af8c8672b18..c38057ac715a 100644
--- a/tools/intel-features/intel-pt/PTDecoder.h
+++ b/tools/intel-features/intel-pt/PTDecoder.h
@@ -13,7 +13,6 @@
// 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"
diff --git a/tools/lldb-mi/CMakeLists.txt b/tools/lldb-mi/CMakeLists.txt
index f3f4c0097efd..20c031a12004 100644
--- a/tools/lldb-mi/CMakeLists.txt
+++ b/tools/lldb-mi/CMakeLists.txt
@@ -93,3 +93,7 @@ add_lldb_tool(lldb-mi
LINK_COMPONENTS
Support
)
+
+if(LLDB_BUILD_FRAMEWORK)
+ lldb_setup_framework_rpaths_in_tool(lldb-mi)
+endif()
diff --git a/tools/lldb-mi/MICmdArgSet.h b/tools/lldb-mi/MICmdArgSet.h
index cb321f0204d2..88716a91f0ad 100644
--- a/tools/lldb-mi/MICmdArgSet.h
+++ b/tools/lldb-mi/MICmdArgSet.h
@@ -9,12 +9,8 @@
#pragma once
-// C Includes
-// C++ Includes
#include <vector>
-// Other libraries and framework includes
-// Project includes
#include "MICmdArgContext.h"
#include "MICmnBase.h"
diff --git a/tools/lldb-mi/MICmdArgValBase.cpp b/tools/lldb-mi/MICmdArgValBase.cpp
index bedd983a06f6..8b1706db93ef 100644
--- a/tools/lldb-mi/MICmdArgValBase.cpp
+++ b/tools/lldb-mi/MICmdArgValBase.cpp
@@ -7,10 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "MICmdArgValBase.h"
#include "MICmdArgContext.h"
#include "MIUtilString.h"
diff --git a/tools/lldb-mi/MICmdArgValBase.h b/tools/lldb-mi/MICmdArgValBase.h
index 288476082806..1b4582963e57 100644
--- a/tools/lldb-mi/MICmdArgValBase.h
+++ b/tools/lldb-mi/MICmdArgValBase.h
@@ -9,10 +9,6 @@
#pragma once
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "MICmdArgSet.h"
#include "MIUtilString.h"
diff --git a/tools/lldb-mi/MICmdArgValConsume.cpp b/tools/lldb-mi/MICmdArgValConsume.cpp
index 5a76ab4b56f5..86c4f0912565 100644
--- a/tools/lldb-mi/MICmdArgValConsume.cpp
+++ b/tools/lldb-mi/MICmdArgValConsume.cpp
@@ -67,7 +67,7 @@ bool CMICmdArgValConsume::Validate(CMICmdArgContext &vwArgContext) {
while (it != vecOptions.end()) {
const CMIUtilString &rTxt(*it);
- if (rTxt.compare("--") == 0) {
+ if (rTxt == "--") {
m_bFound = true;
m_bValid = true;
if (!vwArgContext.RemoveArg(rTxt))
diff --git a/tools/lldb-mi/MICmdArgValFile.cpp b/tools/lldb-mi/MICmdArgValFile.cpp
index 77e9a6b2af8e..cb2ba0125903 100644
--- a/tools/lldb-mi/MICmdArgValFile.cpp
+++ b/tools/lldb-mi/MICmdArgValFile.cpp
@@ -158,10 +158,7 @@ bool CMICmdArgValFile::IsFilePath(const CMIUtilString &vrFileNamePath) const {
return false;
const bool bValidChars = IsValidChars(vrFileNamePath);
- if (bValidChars || bHavePosSlash || bHaveBckSlash)
- return true;
-
- return false;
+ return bValidChars || bHavePosSlash || bHaveBckSlash;
}
//++
diff --git a/tools/lldb-mi/MICmdArgValOptionLong.cpp b/tools/lldb-mi/MICmdArgValOptionLong.cpp
index 70faab900f63..3824fe19188a 100644
--- a/tools/lldb-mi/MICmdArgValOptionLong.cpp
+++ b/tools/lldb-mi/MICmdArgValOptionLong.cpp
@@ -252,10 +252,7 @@ bool CMICmdArgValOptionLong::IsArgLongOption(const CMIUtilString &vrTxt) const {
return false;
const CMIUtilString strArg = vrTxt.substr(2);
- if (strArg.IsNumber())
- return false;
-
- return true;
+ return !strArg.IsNumber();
}
//++
diff --git a/tools/lldb-mi/MICmdArgValString.cpp b/tools/lldb-mi/MICmdArgValString.cpp
index e872f3630587..28d4d18c361b 100644
--- a/tools/lldb-mi/MICmdArgValString.cpp
+++ b/tools/lldb-mi/MICmdArgValString.cpp
@@ -33,7 +33,7 @@ CMICmdArgValString::CMICmdArgValString()
// Throws: None.
//--
CMICmdArgValString::CMICmdArgValString(const bool vbAnything)
- : m_bHandleQuotedString(vbAnything ? true : false), m_bAcceptNumbers(false),
+ : m_bHandleQuotedString(vbAnything), m_bAcceptNumbers(false),
m_bHandleDirPaths(false), m_bHandleAnything(vbAnything) {}
//++
@@ -391,8 +391,5 @@ bool CMICmdArgValString::IsStringArgQuotedQuotedTextEmbedded(
return false;
const size_t nLen = vrTxt.length();
- if ((nLen > 5) && ((nPos + 2) == (nPos2 - 2)))
- return false;
-
- return true;
+ return !((nLen > 5) && ((nPos + 2) == (nPos2 - 2)));
}
diff --git a/tools/lldb-mi/MICmdArgValThreadGrp.cpp b/tools/lldb-mi/MICmdArgValThreadGrp.cpp
index 613ad0dcc348..4ed83e6191e1 100644
--- a/tools/lldb-mi/MICmdArgValThreadGrp.cpp
+++ b/tools/lldb-mi/MICmdArgValThreadGrp.cpp
@@ -115,10 +115,7 @@ bool CMICmdArgValThreadGrp::IsArgThreadGrp(const CMIUtilString &vrTxt) const {
return false;
const CMIUtilString strNum = vrTxt.substr(1);
- if (!strNum.IsNumber())
- return false;
-
- return true;
+ return strNum.IsNumber();
}
//++
diff --git a/tools/lldb-mi/MICmdBase.h b/tools/lldb-mi/MICmdBase.h
index cb44504a1613..fe6aadd66999 100644
--- a/tools/lldb-mi/MICmdBase.h
+++ b/tools/lldb-mi/MICmdBase.h
@@ -9,14 +9,10 @@
#pragma once
-// C Includes
-// C++ Includes
-#include <functional> // for function
+#include <functional>
-// Other libraries and framework includes
#include "lldb/API/SBError.h"
-// Project includes
#include "MICmdArgSet.h"
#include "MICmdData.h"
#include "MICmdFactory.h"
diff --git a/tools/lldb-mi/MICmdCmdBreak.cpp b/tools/lldb-mi/MICmdCmdBreak.cpp
index caad9192366f..0e42f8562ab4 100644
--- a/tools/lldb-mi/MICmdCmdBreak.cpp
+++ b/tools/lldb-mi/MICmdCmdBreak.cpp
@@ -165,8 +165,15 @@ bool CMICmdCmdBreakInsert::Execute() {
if (sbTarget == rSessionInfo.GetDebugger().GetDummyTarget())
m_bBrkPtIsPending = true;
- else
+ else {
m_bBrkPtIsPending = pArgPendingBrkPt->GetFound();
+ if (!m_bBrkPtIsPending) {
+ CMIUtilString pending;
+ if (m_rLLDBDebugSessionInfo.SharedDataRetrieve("breakpoint.pending", pending)) {
+ m_bBrkPtIsPending = pending == "on";
+ }
+ }
+ }
if (pArgLocation->GetFound())
m_brkName = pArgLocation->GetValue();
diff --git a/tools/lldb-mi/MICmdCmdData.cpp b/tools/lldb-mi/MICmdCmdData.cpp
index 53c2d7e621a7..7a4845bba430 100644
--- a/tools/lldb-mi/MICmdCmdData.cpp
+++ b/tools/lldb-mi/MICmdCmdData.cpp
@@ -23,9 +23,9 @@
#include "lldb/API/SBInstructionList.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBThread.h"
-#include "llvm/ADT/Twine.h"
#include "llvm/ADT/StringRef.h"
-#include <inttypes.h> // For PRIx64
+#include "llvm/ADT/Twine.h"
+#include <inttypes.h>
#include <string>
// In-house headers:
diff --git a/tools/lldb-mi/MICmdCmdGdbInfo.cpp b/tools/lldb-mi/MICmdCmdGdbInfo.cpp
index ba96319469a1..5988066883d1 100644
--- a/tools/lldb-mi/MICmdCmdGdbInfo.cpp
+++ b/tools/lldb-mi/MICmdCmdGdbInfo.cpp
@@ -11,7 +11,7 @@
// Third party headers:
#include "lldb/API/SBCommandReturnObject.h"
-#include <inttypes.h> // For PRIx64
+#include <inttypes.h>
// In-house headers:
#include "MICmdArgValString.h"
diff --git a/tools/lldb-mi/MICmdCmdGdbSet.cpp b/tools/lldb-mi/MICmdCmdGdbSet.cpp
index 9f7325c931fc..b433f7678449 100644
--- a/tools/lldb-mi/MICmdCmdGdbSet.cpp
+++ b/tools/lldb-mi/MICmdCmdGdbSet.cpp
@@ -28,7 +28,8 @@ const CMICmdCmdGdbSet::MapGdbOptionNameToFnGdbOptionPtr_t
{"output-radix", &CMICmdCmdGdbSet::OptionFnOutputRadix},
{"solib-search-path", &CMICmdCmdGdbSet::OptionFnSolibSearchPath},
{"disassembly-flavor", &CMICmdCmdGdbSet::OptionFnDisassemblyFlavor},
- {"fallback", &CMICmdCmdGdbSet::OptionFnFallback}};
+ {"fallback", &CMICmdCmdGdbSet::OptionFnFallback},
+ {"breakpoint", &CMICmdCmdGdbSet::OptionFnBreakpoint}};
//++
//------------------------------------------------------------------------------------
@@ -433,6 +434,56 @@ bool CMICmdCmdGdbSet::OptionFnDisassemblyFlavor(
//++
//------------------------------------------------------------------------------------
+// Details: Carry out work to complete the GDB set option 'breakpoint' to
+// prepare
+// and send back information asked for.
+// Type: Method.
+// Args: vrWords - (R) List of additional parameters used by this option.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbSet::OptionFnBreakpoint(
+ const CMIUtilString::VecString_t &vrWords) {
+ bool bPending = false;
+ bool bOk = true;
+
+ if (vrWords.size() != 2)
+ // Wrong number of arguments.
+ bOk = false;
+ else if (CMIUtilString::Compare(vrWords[0], "pending") &&
+ (CMIUtilString::Compare(vrWords[1], "on") ||
+ CMIUtilString::Compare(vrWords[1], "1")))
+ bPending = true;
+ else if (CMIUtilString::Compare(vrWords[0], "pending") &&
+ (CMIUtilString::Compare(vrWords[1], "off") ||
+ CMIUtilString::Compare(vrWords[1], "0")))
+ bPending = false;
+ else
+ // Unrecognized argument(s).
+ bOk = false;
+
+ if (!bOk) {
+ // Report error.
+ m_bGbbOptionFnHasError = false;
+ SetError(MIRSRC(IDS_CMD_ERR_GDBSET_OPT_BREAKPOINT));
+ return MIstatus::failure;
+ }
+
+ CMIUtilString sPendingVal = bPending ? "on" : "off";
+ CMIUtilString sKey = "breakpoint.pending";
+ if (!m_rLLDBDebugSessionInfo.SharedDataAdd(sKey, sPendingVal)) {
+ m_bGbbOptionFnHasError = false;
+ SetError(CMIUtilString::Format(MIRSRC(IDS_DBGSESSION_ERR_SHARED_DATA_ADD),
+ m_cmdData.strMiCmd.c_str(), sKey.c_str()));
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++
+//------------------------------------------------------------------------------------
// Details: Carry out work to complete the GDB set option to prepare and send
// back the
// requested information.
diff --git a/tools/lldb-mi/MICmdCmdGdbSet.h b/tools/lldb-mi/MICmdCmdGdbSet.h
index 730754f7f82a..7cca20c3348d 100644
--- a/tools/lldb-mi/MICmdCmdGdbSet.h
+++ b/tools/lldb-mi/MICmdCmdGdbSet.h
@@ -80,6 +80,7 @@ private:
bool OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWords);
bool OptionFnOutputRadix(const CMIUtilString::VecString_t &vrWords);
bool OptionFnDisassemblyFlavor(const CMIUtilString::VecString_t &vrWords);
+ bool OptionFnBreakpoint(const CMIUtilString::VecString_t &vrWords);
bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords);
// Attributes:
diff --git a/tools/lldb-mi/MICmdCmdGdbShow.cpp b/tools/lldb-mi/MICmdCmdGdbShow.cpp
index 4ae45f8579e2..196b8271064f 100644
--- a/tools/lldb-mi/MICmdCmdGdbShow.cpp
+++ b/tools/lldb-mi/MICmdCmdGdbShow.cpp
@@ -32,7 +32,8 @@ const CMICmdCmdGdbShow::MapGdbOptionNameToFnGdbOptionPtr_t
{"print", &CMICmdCmdGdbShow::OptionFnPrint},
{"language", &CMICmdCmdGdbShow::OptionFnLanguage},
{"disassembly-flavor", &CMICmdCmdGdbShow::OptionFnDisassemblyFlavor},
- {"fallback", &CMICmdCmdGdbShow::OptionFnFallback}};
+ {"fallback", &CMICmdCmdGdbShow::OptionFnFallback},
+ {"breakpoint", &CMICmdCmdGdbShow::OptionFnBreakpoint}};
//++
//------------------------------------------------------------------------------------
@@ -349,6 +350,43 @@ bool CMICmdCmdGdbShow::OptionFnDisassemblyFlavor(const CMIUtilString::VecString_
//++
//------------------------------------------------------------------------------------
+// Details: Carry out work to complete the GDB show option 'breakpoint' to
+// prepare
+// and send back the requested information.
+// Type: Method.
+// Args: vrWords - (R) List of additional parameters used by this option.
+// Return: MIstatus::success - Function succeeded.
+// MIstatus::failure - Function failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbShow::OptionFnBreakpoint(
+ const CMIUtilString::VecString_t &vrWords) {
+ if (vrWords.size() != 1) {
+ m_bGbbOptionFnHasError = true;
+ m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSHOW_OPT_BREAKPOINT_BAD_ARGS);
+ return MIstatus::failure;
+ }
+
+ const CMIUtilString strOption(vrWords[0]);
+ if (!CMIUtilString::Compare(strOption, "pending")) {
+ m_bGbbOptionFnHasError = true;
+ m_strGdbOptionFnError = CMIUtilString::Format(
+ MIRSRC(IDS_CMD_ERR_GDBSHOW_OPT_BREAKPOINT_UNKNOWN_OPTION),
+ strOption.c_str());
+ return MIstatus::failure;
+ }
+
+ if (!m_rLLDBDebugSessionInfo.SharedDataRetrieve("breakpoint.pending",
+ m_strValue)) {
+ if (m_strValue.empty())
+ m_strValue = "off";
+ }
+
+ return MIstatus::success;
+}
+
+//++
+//------------------------------------------------------------------------------------
// Details: Carry out work to complete the GDB show option to prepare and send
// back the
// requested information.
diff --git a/tools/lldb-mi/MICmdCmdGdbShow.h b/tools/lldb-mi/MICmdCmdGdbShow.h
index 452db827032c..51f07092843f 100644
--- a/tools/lldb-mi/MICmdCmdGdbShow.h
+++ b/tools/lldb-mi/MICmdCmdGdbShow.h
@@ -80,6 +80,7 @@ private:
bool OptionFnLanguage(const CMIUtilString::VecString_t &vrWords);
bool OptionFnDisassemblyFlavor(const CMIUtilString::VecString_t &vrWords);
bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords);
+ bool OptionFnBreakpoint(const CMIUtilString::VecString_t &vrWords);
// Attributes:
private:
diff --git a/tools/lldb-mi/MICmdCmdTarget.cpp b/tools/lldb-mi/MICmdCmdTarget.cpp
index a82bd682de81..0666fc4c60ec 100644
--- a/tools/lldb-mi/MICmdCmdTarget.cpp
+++ b/tools/lldb-mi/MICmdCmdTarget.cpp
@@ -10,9 +10,8 @@
// Overview: CMICmdCmdTargetSelect implementation.
// Third Party Headers:
-#include "lldb/API/SBCommandInterpreter.h"
-#include "lldb/API/SBCommandReturnObject.h"
#include "lldb/API/SBStream.h"
+#include "lldb/API/SBError.h"
// In-house headers:
#include "MICmdArgValNumber.h"
@@ -52,7 +51,7 @@ CMICmdCmdTargetSelect::CMICmdCmdTargetSelect()
// Return: None.
// Throws: None.
//--
-CMICmdCmdTargetSelect::~CMICmdCmdTargetSelect() {}
+CMICmdCmdTargetSelect::~CMICmdCmdTargetSelect() = default;
//++
//------------------------------------------------------------------------------------
@@ -93,16 +92,17 @@ bool CMICmdCmdTargetSelect::Execute() {
CMICmnLLDBDebugSessionInfo &rSessionInfo(
CMICmnLLDBDebugSessionInfo::Instance());
+ lldb::SBTarget target = rSessionInfo.GetTarget();
- // Check we have a valid target
- // Note: target created via 'file-exec-and-symbols' command
- if (!rSessionInfo.GetTarget().IsValid()) {
+ // Check we have a valid target.
+ // Note: target created via 'file-exec-and-symbols' command.
+ if (!target.IsValid()) {
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT),
m_cmdData.strMiCmd.c_str()));
return MIstatus::failure;
}
- // Verify that we are executing remotely
+ // Verify that we are executing remotely.
const CMIUtilString &rRemoteType(pArgType->GetValue());
if (rRemoteType != "remote") {
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_TYPE),
@@ -111,33 +111,25 @@ bool CMICmdCmdTargetSelect::Execute() {
return MIstatus::failure;
}
- // Create a URL pointing to the remote gdb stub
+ // Create a URL pointing to the remote gdb stub.
const CMIUtilString strUrl =
CMIUtilString::Format("connect://%s", pArgParameters->GetValue().c_str());
- // Ask LLDB to connect to the target port
- const char *pPlugin("gdb-remote");
lldb::SBError error;
- lldb::SBProcess process = rSessionInfo.GetTarget().ConnectRemote(
+ // Ask LLDB to connect to the target port.
+ const char *pPlugin("gdb-remote");
+ lldb::SBProcess process = target.ConnectRemote(
rSessionInfo.GetListener(), strUrl.c_str(), pPlugin, error);
- // Verify that we have managed to connect successfully
- lldb::SBStream errMsg;
- error.GetDescription(errMsg);
+ // Verify that we have managed to connect successfully.
if (!process.IsValid()) {
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_PLUGIN),
m_cmdData.strMiCmd.c_str(),
- errMsg.GetData()));
- return MIstatus::failure;
- }
- if (error.Fail()) {
- SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_CONNECT_TO_TARGET),
- m_cmdData.strMiCmd.c_str(),
- errMsg.GetData()));
+ error.GetCString()));
return MIstatus::failure;
}
- // Set the environment path if we were given one
+ // Set the environment path if we were given one.
CMIUtilString strWkDir;
if (rSessionInfo.SharedDataRetrieve<CMIUtilString>(
rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir)) {
@@ -150,28 +142,13 @@ bool CMICmdCmdTargetSelect::Execute() {
}
}
- // Set the shared object path if we were given one
+ // Set the shared object path if we were given one.
CMIUtilString strSolibPath;
if (rSessionInfo.SharedDataRetrieve<CMIUtilString>(
- rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath)) {
- lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger();
- lldb::SBCommandInterpreter cmdIterpreter = rDbgr.GetCommandInterpreter();
-
- CMIUtilString strCmdString = CMIUtilString::Format(
- "target modules search-paths add . %s", strSolibPath.c_str());
-
- lldb::SBCommandReturnObject retObj;
- cmdIterpreter.HandleCommand(strCmdString.c_str(), retObj, false);
+ rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath))
+ target.AppendImageSearchPath(".", strSolibPath.c_str(), error);
- if (!retObj.Succeeded()) {
- SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FNFAILED),
- m_cmdData.strMiCmd.c_str(),
- "target-select"));
- return MIstatus::failure;
- }
- }
-
- return MIstatus::success;
+ return HandleSBError(error);
}
//++
diff --git a/tools/lldb-mi/MICmdFactory.cpp b/tools/lldb-mi/MICmdFactory.cpp
index 8f6215463627..ad4283e50215 100644
--- a/tools/lldb-mi/MICmdFactory.cpp
+++ b/tools/lldb-mi/MICmdFactory.cpp
@@ -128,10 +128,7 @@ bool CMICmdFactory::CmdRegister(const CMIUtilString &vMiCmd,
bool CMICmdFactory::HaveAlready(const CMIUtilString &vMiCmd) const {
const MapMiCmdToCmdCreatorFn_t::const_iterator it =
m_mapMiCmdToCmdCreatorFn.find(vMiCmd);
- if (it != m_mapMiCmdToCmdCreatorFn.end())
- return true;
-
- return false;
+ return it != m_mapMiCmdToCmdCreatorFn.end();
}
//++
diff --git a/tools/lldb-mi/MICmnBase.cpp b/tools/lldb-mi/MICmnBase.cpp
index 63544dc5b9c7..7f82c6120e1a 100644
--- a/tools/lldb-mi/MICmnBase.cpp
+++ b/tools/lldb-mi/MICmnBase.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
// Third party headers
-#include <stdarg.h> // va_list, va_start, var_end
+#include <stdarg.h>
// In-house headers:
#include "MICmnBase.h"
diff --git a/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp b/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp
index 9a173d1007e2..f7f43f001b7b 100644
--- a/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp
+++ b/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp
@@ -9,11 +9,11 @@
// Third party headers:
#include "lldb/API/SBThread.h"
-#include <inttypes.h> // For PRIx64
+#include <inttypes.h>
#ifdef _WIN32
-#include <io.h> // For the ::_access()
+#include <io.h>
#else
-#include <unistd.h> // For the ::access()
+#include <unistd.h>
#endif // _WIN32
#include "lldb/API/SBBreakpointLocation.h"
@@ -532,7 +532,7 @@ bool CMICmnLLDBDebugSessionInfo::GetVariableInfo(const lldb::SBValue &vrValue,
const bool vbInSimpleForm,
CMIUtilString &vwrStrValue) {
const CMICmnLLDBUtilSBValue utilValue(vrValue, true, false);
- const bool bExpandAggregates = vbInSimpleForm ? false : true;
+ const bool bExpandAggregates = !vbInSimpleForm;
vwrStrValue = utilValue.GetValue(bExpandAggregates);
return MIstatus::success;
}
diff --git a/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
index dceb29f5908f..cd54c2bb5bc4 100644
--- a/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
+++ b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
@@ -20,9 +20,9 @@
#include "lldb/API/SBUnixSignals.h"
#include "llvm/Support/Compiler.h"
#ifdef _WIN32
-#include <io.h> // For the ::_access()
+#include <io.h>
#else
-#include <unistd.h> // For the ::access()
+#include <unistd.h>
#endif // _WIN32
// In-house headers:
@@ -39,7 +39,7 @@
#include "MICmnStreamStdout.h"
#include "MIDriver.h"
#include "MIUtilDebug.h"
-#include "Platform.h" // for PATH_MAX
+#include "Platform.h"
#include <algorithm>
@@ -437,10 +437,10 @@ bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointAdded(
sBrkPtInfo.m_nIgnore = brkPt.GetIgnoreCount();
sBrkPtInfo.m_bPending = false;
const char *pStrCondition = brkPt.GetCondition();
- sBrkPtInfo.m_bCondition = (pStrCondition != nullptr) ? true : false;
+ sBrkPtInfo.m_bCondition = pStrCondition != nullptr;
sBrkPtInfo.m_strCondition =
(pStrCondition != nullptr) ? pStrCondition : "??";
- sBrkPtInfo.m_bBrkPtThreadId = (brkPt.GetThreadID() != 0) ? true : false;
+ sBrkPtInfo.m_bBrkPtThreadId = brkPt.GetThreadID() != 0;
sBrkPtInfo.m_nBrkPtThreadId = brkPt.GetThreadID();
}
@@ -950,6 +950,7 @@ bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventBroadcastBitStateChanged(
bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateSuspended(
const lldb::SBEvent &vEvent) {
bool bOk = MIstatus::success;
+ lldb::SBStream streamOut;
lldb::SBDebugger &rDebugger =
CMICmnLLDBDebugSessionInfo::Instance().GetDebugger();
lldb::SBProcess sbProcess =
@@ -958,16 +959,17 @@ bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateSuspended(
if (rDebugger.GetSelectedTarget() == target) {
if (!UpdateSelectedThread())
return MIstatus::failure;
-
- lldb::SBCommandReturnObject result;
- const lldb::ReturnStatus status =
- rDebugger.GetCommandInterpreter().HandleCommand("process status",
- result, false);
- MIunused(status);
- bOk = TextToStderr(result.GetError());
- bOk = bOk && TextToStdout(result.GetOutput());
+ sbProcess.GetDescription(streamOut);
+ // Add a delimiter between process' and threads' info.
+ streamOut.Printf("\n");
+ for (uint32_t i = 0, e = sbProcess.GetNumThreads(); i < e; ++i) {
+ const lldb::SBThread thread = sbProcess.GetThreadAtIndex(i);
+ if (!thread.IsValid())
+ continue;
+ thread.GetDescription(streamOut);
+ }
+ bOk = TextToStdout(streamOut.GetData());
} else {
- lldb::SBStream streamOut;
const MIuint nTargetIndex = rDebugger.GetIndexOfTarget(target);
if (nTargetIndex != UINT_MAX)
streamOut.Printf("Target %d: (", nTargetIndex);
diff --git a/tools/lldb-mi/MICmnLog.cpp b/tools/lldb-mi/MICmnLog.cpp
index 8643a8784e35..d30c03f5063d 100644
--- a/tools/lldb-mi/MICmnLog.cpp
+++ b/tools/lldb-mi/MICmnLog.cpp
@@ -209,10 +209,7 @@ bool CMICmnLog::RegisterMedium(const IMedium &vrMedium) {
bool CMICmnLog::HaveMediumAlready(const IMedium &vrMedium) const {
IMedium *pMedium = const_cast<IMedium *>(&vrMedium);
const MapMediumToName_t::const_iterator it = m_mapMediumToName.find(pMedium);
- if (it != m_mapMediumToName.end())
- return true;
-
- return false;
+ return it != m_mapMediumToName.end();
}
//++
diff --git a/tools/lldb-mi/MICmnResources.cpp b/tools/lldb-mi/MICmnResources.cpp
index e32a816fc9f1..d8fa0a829245 100644
--- a/tools/lldb-mi/MICmnResources.cpp
+++ b/tools/lldb-mi/MICmnResources.cpp
@@ -9,7 +9,7 @@
// Third party headers
#include "assert.h"
-#include <inttypes.h> // For PRIx64
+#include <inttypes.h>
// In-house headers:
#include "MICmnResources.h"
@@ -78,7 +78,7 @@ const CMICmnResources::SRsrcTextData
"and a custom plugin.\nThe custom plugin is not necessary to operate "
"the MI Driver."},
{IDE_MI_APP_ARG_USAGE, "\nMI driver usage:\n\n\tlldb-mi [--longOption] "
- "[-s hortOption] [executeable]\n\n[] = optional "
+ "[-s hortOption] [executable]\n\n[] = optional "
"argument."},
{IDE_MI_APP_ARG_HELP, "-h\n--help\n\tPrints out usage information for "
"the MI debugger. Exit the MI\n\tDriver "
@@ -439,6 +439,8 @@ const CMICmnResources::SRsrcTextData
{IDS_CMD_ERR_INFO_PRINTFN_FAILED, "The request '%s' failed."},
{IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC,
"'target-async' expects \"on\" or \"off\""},
+ {IDS_CMD_ERR_GDBSET_OPT_BREAKPOINT,
+ "'breakpoint' expects \"pending on\" or \"pending off\""},
{IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH,
"'solib-search-path' requires at least one argument"},
{IDS_CMD_ERR_GDBSET_OPT_PRINT_BAD_ARGS,
@@ -449,6 +451,10 @@ const CMICmnResources::SRsrcTextData
"'print' expects option-name and \"on\" or \"off\""},
{IDS_CMD_ERR_GDBSHOW_OPT_PRINT_UNKNOWN_OPTION,
"'print' error. The option '%s' not found"},
+ {IDS_CMD_ERR_GDBSHOW_OPT_BREAKPOINT_BAD_ARGS,
+ "'breakpoint' expects option-name"},
+ {IDS_CMD_ERR_GDBSHOW_OPT_BREAKPOINT_UNKNOWN_OPTION,
+ "'breakpoint' error. The option '%s' not found"},
{IDS_CMD_ERR_EXPR_INVALID, "Failed to evaluate expression: %s"},
{IDS_CMD_ERR_ATTACH_FAILED,
"Command '%s'. Attach to process failed: %s"},
diff --git a/tools/lldb-mi/MICmnResources.h b/tools/lldb-mi/MICmnResources.h
index 8912a2b8463e..4177a95a5488 100644
--- a/tools/lldb-mi/MICmnResources.h
+++ b/tools/lldb-mi/MICmnResources.h
@@ -264,11 +264,14 @@ enum {
IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND,
IDS_CMD_ERR_INFO_PRINTFN_FAILED,
IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC,
+ IDS_CMD_ERR_GDBSET_OPT_BREAKPOINT,
IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH,
IDS_CMD_ERR_GDBSET_OPT_PRINT_BAD_ARGS,
IDS_CMD_ERR_GDBSET_OPT_PRINT_UNKNOWN_OPTION,
IDS_CMD_ERR_GDBSHOW_OPT_PRINT_BAD_ARGS,
IDS_CMD_ERR_GDBSHOW_OPT_PRINT_UNKNOWN_OPTION,
+ IDS_CMD_ERR_GDBSHOW_OPT_BREAKPOINT_BAD_ARGS,
+ IDS_CMD_ERR_GDBSHOW_OPT_BREAKPOINT_UNKNOWN_OPTION,
IDS_CMD_ERR_EXPR_INVALID,
IDS_CMD_ERR_ATTACH_FAILED,
IDS_CMD_ERR_ATTACH_BAD_ARGS
diff --git a/tools/lldb-mi/MICmnStreamStdin.cpp b/tools/lldb-mi/MICmnStreamStdin.cpp
index 154519dbec4c..4d3fa2aabd96 100644
--- a/tools/lldb-mi/MICmnStreamStdin.cpp
+++ b/tools/lldb-mi/MICmnStreamStdin.cpp
@@ -11,7 +11,7 @@
#ifdef _MSC_VER
#include <windows.h>
#endif
-#include <string.h> // For std::strerror()
+#include <string.h>
// In-house headers:
#include "MICmnLog.h"
diff --git a/tools/lldb-mi/MIDataTypes.h b/tools/lldb-mi/MIDataTypes.h
index 34fe4575160e..59ff099389cb 100644
--- a/tools/lldb-mi/MIDataTypes.h
+++ b/tools/lldb-mi/MIDataTypes.h
@@ -21,7 +21,7 @@
// Debugging:
#ifdef _DEBUG
-#include <crtdbg.h> // C-runtime debugging library (defines _ASSERT).
+#include <crtdbg.h>
#endif // _DEBUG
#endif // _WIN32
diff --git a/tools/lldb-mi/MIDriver.cpp b/tools/lldb-mi/MIDriver.cpp
index 23039110b428..cb8fb1c2c25f 100644
--- a/tools/lldb-mi/MIDriver.cpp
+++ b/tools/lldb-mi/MIDriver.cpp
@@ -443,8 +443,7 @@ lldb::SBError CMIDriver::ParseArgs(const int argc, const char *argv[],
CMICmdArgValString(true, false, true).IsStringArg(strArg)) {
// Is this the command file for the '-s' or '--source' options?
const CMIUtilString strPrevArg(argv[i - 1]);
- if (strPrevArg.compare("-s") == 0 ||
- strPrevArg.compare("--source") == 0) {
+ if (strPrevArg == "-s" || strPrevArg == "--source") {
m_strCmdLineArgCommandFileNamePath = strArg;
m_bHaveCommandFileNamePathOnCmdLine = true;
i--; // skip '-s' on the next loop
@@ -457,7 +456,7 @@ lldb::SBError CMIDriver::ParseArgs(const int argc, const char *argv[],
}
// Report error if no command file was specified for the '-s' or
// '--source' options
- else if (strArg.compare("-s") == 0 || strArg.compare("--source") == 0) {
+ else if (strArg == "-s" || strArg == "--source") {
vwbExiting = true;
const CMIUtilString errMsg = CMIUtilString::Format(
MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF), strArg.c_str());
@@ -465,13 +464,13 @@ lldb::SBError CMIDriver::ParseArgs(const int argc, const char *argv[],
break;
}
// This argument is also checked for in CMIDriverMgr::ParseArgs()
- else if (strArg.compare("--executable") == 0) // Used to specify that
- // there is executable
- // argument also on the
- // command line
- { // See fn description.
+ else if (strArg == "--executable") // Used to specify that
+ // there is executable
+ // argument also on the
+ // command line
+ { // See fn description.
bHaveExecutableLongOption = true;
- } else if (strArg.compare("--synchronous") == 0) {
+ } else if (strArg == "--synchronous") {
CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().SetAsync(false);
}
}
diff --git a/tools/lldb-mi/MIDriverMain.cpp b/tools/lldb-mi/MIDriverMain.cpp
index 1b3521e8f03f..d347ecbbebeb 100644
--- a/tools/lldb-mi/MIDriverMain.cpp
+++ b/tools/lldb-mi/MIDriverMain.cpp
@@ -42,7 +42,7 @@
#include "MIDriver.h"
#include "MIDriverMgr.h"
#include "MIUtilDebug.h"
-#include "Platform.h" // Define signals - CODETAG_IOR_SIGNALS
+#include "Platform.h"
#if defined(_MSC_VER)
#pragma warning( \
@@ -165,11 +165,7 @@ bool DriverSystemShutdown(const bool vbAppExitOk) {
//--
int main(int argc, char const *argv[]) {
#if MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
-#ifdef _WIN32
- CMIUtilDebug::ShowDlgWaitForDbgAttach();
-#else
CMIUtilDebug::WaitForDbgAttachInfinteLoop();
-#endif // _WIN32
#endif // MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
llvm::StringRef ToolName = argv[0];
diff --git a/tools/lldb-mi/MIDriverMgr.cpp b/tools/lldb-mi/MIDriverMgr.cpp
index 6b39832d736e..93070a5912d6 100644
--- a/tools/lldb-mi/MIDriverMgr.cpp
+++ b/tools/lldb-mi/MIDriverMgr.cpp
@@ -516,29 +516,27 @@ bool CMIDriverMgr::ParseArgs(const int argc, const char *argv[],
const CMIUtilString strArg(argv[i]);
// Argument "--executable" is also check for in CMIDriver::ParseArgs()
- if ((0 ==
- strArg.compare(
- "--interpreter")) || // Given by the client such as Eclipse
- (0 == strArg.compare("--executable"))) // Used to specify that there
- // is executable argument also
- // on the command line
- { // See fn description.
+ if (("--interpreter" == strArg) || // Given by the client such as Eclipse
+ ("--executable" == strArg)) // Used to specify that there
+ // is executable argument also
+ // on the command line
+ { // See fn description.
bHaveArgInterpret = true;
}
- if (0 == strArg.compare("--version")) {
+ if ("--version" == strArg) {
bHaveArgVersion = true;
}
- if (0 == strArg.compare("--versionLong")) {
+ if ("--versionLong" == strArg) {
bHaveArgVersionLong = true;
}
- if (0 == strArg.compare("--log")) {
+ if ("--log" == strArg) {
bHaveArgLog = true;
}
if (0 == strArg.compare(0, 10, "--log-dir=")) {
strLogDir = strArg.substr(10, CMIUtilString::npos);
bHaveArgLogDir = true;
}
- if ((0 == strArg.compare("--help")) || (0 == strArg.compare("-h"))) {
+ if (("--help" == strArg) || ("-h" == strArg)) {
bHaveArgHelp = true;
}
}
diff --git a/tools/lldb-mi/MIUtilDebug.cpp b/tools/lldb-mi/MIUtilDebug.cpp
index 519fd950feb2..598a1a71046b 100644
--- a/tools/lldb-mi/MIUtilDebug.cpp
+++ b/tools/lldb-mi/MIUtilDebug.cpp
@@ -39,25 +39,6 @@ CMIUtilDebug::~CMIUtilDebug() {}
//++
//------------------------------------------------------------------------------------
-// Details: Show a dialog to the process/application halts. It gives the
-// opportunity to
-// attach a debugger.
-// Type: Static method.
-// Args: None.
-// Return: None.
-// Throws: None.
-//--
-void CMIUtilDebug::ShowDlgWaitForDbgAttach() {
- const CMIUtilString strCaption(CMIDriver::Instance().GetAppNameShort());
-#ifdef _WIN32
- ::MessageBoxA(NULL, "Attach your debugger now", strCaption.c_str(), MB_OK);
-#else
-// ToDo: Implement other platform version of an Ok to continue dialog box
-#endif // _WIN32
-}
-
-//++
-//------------------------------------------------------------------------------------
// Details: Temporarily stall the process/application to give the programmer the
// opportunity to attach a debugger. How to use: Put a break in the
// programmer
diff --git a/tools/lldb-mi/MIUtilDebug.h b/tools/lldb-mi/MIUtilDebug.h
index a49fd9a868ec..16b080ee7b62 100644
--- a/tools/lldb-mi/MIUtilDebug.h
+++ b/tools/lldb-mi/MIUtilDebug.h
@@ -24,7 +24,6 @@ class CMICmnLog;
class CMIUtilDebug {
// Statics:
public:
- static void ShowDlgWaitForDbgAttach();
static void WaitForDbgAttachInfinteLoop();
// Methods:
diff --git a/tools/lldb-mi/MIUtilFileStd.cpp b/tools/lldb-mi/MIUtilFileStd.cpp
index 1e76c1c58fe2..abf0ef407d3b 100644
--- a/tools/lldb-mi/MIUtilFileStd.cpp
+++ b/tools/lldb-mi/MIUtilFileStd.cpp
@@ -11,7 +11,7 @@
#include <assert.h>
#include <cerrno>
#include <stdio.h>
-#include <string.h> // For strerror()
+#include <string.h>
// In-house headers:
#include "MICmnResources.h"
diff --git a/tools/lldb-mi/MIUtilMapIdToVariant.cpp b/tools/lldb-mi/MIUtilMapIdToVariant.cpp
index 52bc413a471f..0a4e7299e926 100644
--- a/tools/lldb-mi/MIUtilMapIdToVariant.cpp
+++ b/tools/lldb-mi/MIUtilMapIdToVariant.cpp
@@ -52,10 +52,7 @@ void CMIUtilMapIdToVariant::Clear() { m_mapKeyToVariantValue.clear(); }
bool CMIUtilMapIdToVariant::HaveAlready(const CMIUtilString &vId) const {
const MapKeyToVariantValue_t::const_iterator it =
m_mapKeyToVariantValue.find(vId);
- if (it != m_mapKeyToVariantValue.end())
- return true;
-
- return false;
+ return it != m_mapKeyToVariantValue.end();
}
//++
diff --git a/tools/lldb-mi/MIUtilString.cpp b/tools/lldb-mi/MIUtilString.cpp
index 3797d1001798..627c2f3d4d3b 100644
--- a/tools/lldb-mi/MIUtilString.cpp
+++ b/tools/lldb-mi/MIUtilString.cpp
@@ -10,12 +10,12 @@
// Third party headers
#include "llvm/Support/Compiler.h"
#include <cstdlib>
-#include <inttypes.h> // for PRIx8
-#include <limits.h> // for ULONG_MAX
-#include <memory> // std::unique_ptr
-#include <sstream> // std::stringstream
-#include <stdarg.h> // va_list, va_start, var_end
-#include <string.h> // for strncmp
+#include <inttypes.h>
+#include <limits.h>
+#include <memory>
+#include <sstream>
+#include <stdarg.h>
+#include <string.h>
// In-house headers:
#include "MIUtilString.h"
@@ -378,10 +378,7 @@ bool CMIUtilString::IsNumber() const {
return false;
const size_t nPos = find_first_not_of("-.0123456789");
- if (nPos != std::string::npos)
- return false;
-
- return true;
+ return nPos == std::string::npos;
}
//++
@@ -399,10 +396,7 @@ bool CMIUtilString::IsHexadecimalNumber() const {
// Skip '0x..' prefix
const size_t nPos = find_first_not_of("01234567890ABCDEFabcedf", 2);
- if (nPos != std::string::npos)
- return false;
-
- return true;
+ return nPos == std::string::npos;
}
//++
@@ -419,10 +413,7 @@ bool CMIUtilString::ExtractNumber(MIint64 &vwrNumber) const {
vwrNumber = 0;
if (!IsNumber()) {
- if (ExtractNumberFromHexadecimal(vwrNumber))
- return true;
-
- return false;
+ return ExtractNumberFromHexadecimal(vwrNumber);
}
std::stringstream ss(const_cast<CMIUtilString &>(*this));
@@ -639,10 +630,7 @@ bool CMIUtilString::IsQuoted() const {
return false;
const size_t nLen = length();
- if ((nLen > 0) && (at(nLen - 1) != cQuote))
- return false;
-
- return true;
+ return !((nLen > 0) && (at(nLen - 1) != cQuote));
}
//++
diff --git a/tools/lldb-server/CMakeLists.txt b/tools/lldb-server/CMakeLists.txt
index c74f553e9659..5b138534404f 100644
--- a/tools/lldb-server/CMakeLists.txt
+++ b/tools/lldb-server/CMakeLists.txt
@@ -42,7 +42,7 @@ else()
list(APPEND LLDB_PLUGINS lldbPluginObjectFileELF)
endif()
-add_lldb_tool(lldb-server INCLUDE_IN_SUITE
+add_lldb_tool(lldb-server
Acceptor.cpp
lldb-gdbserver.cpp
lldb-platform.cpp
diff --git a/tools/lldb-server/SystemInitializerLLGS.cpp b/tools/lldb-server/SystemInitializerLLGS.cpp
index aeaf382a1dd8..93ef4d9d0761 100644
--- a/tools/lldb-server/SystemInitializerLLGS.cpp
+++ b/tools/lldb-server/SystemInitializerLLGS.cpp
@@ -22,9 +22,14 @@ using HostObjectFile = ObjectFileELF;
using namespace lldb_private;
-void SystemInitializerLLGS::Initialize() {
- SystemInitializerCommon::Initialize();
+llvm::Error
+SystemInitializerLLGS::Initialize(const InitializerOptions &options) {
+ if (auto e = SystemInitializerCommon::Initialize(options))
+ return e;
+
HostObjectFile::Initialize();
+
+ return llvm::Error::success();
}
void SystemInitializerLLGS::Terminate() {
diff --git a/tools/lldb-server/SystemInitializerLLGS.h b/tools/lldb-server/SystemInitializerLLGS.h
index e6460a2cdd39..7feba3fe07bd 100644
--- a/tools/lldb-server/SystemInitializerLLGS.h
+++ b/tools/lldb-server/SystemInitializerLLGS.h
@@ -10,11 +10,13 @@
#ifndef LLDB_SYSTEMINITIALIZERLLGS_H
#define LLDB_SYSTEMINITIALIZERLLGS_H
+#include "lldb/Initialization/SystemInitializer.h"
#include "lldb/Initialization/SystemInitializerCommon.h"
class SystemInitializerLLGS : public lldb_private::SystemInitializerCommon {
public:
- void Initialize() override;
+ llvm::Error
+ Initialize(const lldb_private::InitializerOptions &options) override;
void Terminate() override;
};
diff --git a/tools/lldb-server/lldb-gdbserver.cpp b/tools/lldb-server/lldb-gdbserver.cpp
index c91a8a89e46a..062bbd0c3b6e 100644
--- a/tools/lldb-server/lldb-gdbserver.cpp
+++ b/tools/lldb-server/lldb-gdbserver.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
@@ -19,8 +18,6 @@
#include <unistd.h>
#endif
-// C++ Includes
-
#include "Acceptor.h"
#include "LLDBServerUtilities.h"
@@ -28,6 +25,7 @@
#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostGetOpt.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Host/Pipe.h"
@@ -187,7 +185,9 @@ void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server, int argc,
llvm::errs() << "Error getting current directory: " << ec.message() << "\n";
exit(1);
}
- info.SetWorkingDirectory(FileSpec(cwd, true));
+ FileSpec cwd_spec(cwd);
+ FileSystem::Instance().Resolve(cwd_spec);
+ info.SetWorkingDirectory(cwd_spec);
info.GetEnvironment() = Host::GetEnvironment();
gdb_server.SetLaunchInfo(info);
@@ -218,20 +218,17 @@ Status writeSocketIdToPipe(const char *const named_pipe_path,
return writeSocketIdToPipe(port_name_pipe, socket_id);
}
-Status writeSocketIdToPipe(int unnamed_pipe_fd, const std::string &socket_id) {
-#if defined(_WIN32)
- return Status("Unnamed pipes are not supported on Windows.");
-#else
- Pipe port_pipe{Pipe::kInvalidDescriptor, unnamed_pipe_fd};
+Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe,
+ const std::string &socket_id) {
+ Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe};
return writeSocketIdToPipe(port_pipe, socket_id);
-#endif
}
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, pipe_t unnamed_pipe,
int connection_fd) {
Status error;
@@ -331,8 +328,8 @@ void ConnectToRemote(MainLoop &mainloop,
}
// If we have an unnamed pipe to write the socket id back to, do that
// now.
- else if (unnamed_pipe_fd >= 0) {
- error = writeSocketIdToPipe(unnamed_pipe_fd, socket_id);
+ else if (unnamed_pipe != LLDB_INVALID_PIPE) {
+ error = writeSocketIdToPipe(unnamed_pipe, socket_id);
if (error.Fail())
fprintf(stderr, "failed to write to the unnamed pipe: %s\n",
error.AsCString());
@@ -384,7 +381,7 @@ int main_gdbserver(int argc, char *argv[]) {
std::string log_file;
StringRef
log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
- int unnamed_pipe_fd = -1;
+ lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE;
bool reverse_connect = false;
int connection_fd = -1;
@@ -425,7 +422,7 @@ int main_gdbserver(int argc, char *argv[]) {
case 'U': // unnamed pipe
if (optarg && optarg[0])
- unnamed_pipe_fd = StringConvert::ToUInt32(optarg, -1);
+ unnamed_pipe = (pipe_t)StringConvert::ToUInt64(optarg, -1);
break;
case 'r':
@@ -528,8 +525,8 @@ int main_gdbserver(int argc, char *argv[]) {
printf("%s-%s", LLGS_PROGRAM_NAME, LLGS_VERSION_STR);
ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port,
- progname, subcommand, named_pipe_path.c_str(),
- unnamed_pipe_fd, connection_fd);
+ progname, subcommand, named_pipe_path.c_str(),
+ unnamed_pipe, connection_fd);
if (!gdb_server.IsConnected()) {
fprintf(stderr, "no connection information provided, unable to run\n");
diff --git a/tools/lldb-server/lldb-platform.cpp b/tools/lldb-server/lldb-platform.cpp
index cfaf5550d096..b7f7950d4ccf 100644
--- a/tools/lldb-server/lldb-platform.cpp
+++ b/tools/lldb-server/lldb-platform.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
#include <errno.h>
#if defined(__APPLE__)
#include <netinet/in.h>
@@ -19,10 +18,8 @@
#include <string.h>
#include <sys/wait.h>
-// C++ Includes
#include <fstream>
-// Other libraries and framework includes
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
@@ -100,7 +97,7 @@ static void display_usage(const char *progname, const char *subcommand) {
static Status save_socket_id_to_file(const std::string &socket_id,
const FileSpec &file_spec) {
- FileSpec temp_file_spec(file_spec.GetDirectory().AsCString(), false);
+ FileSpec temp_file_spec(file_spec.GetDirectory().AsCString());
Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath()));
if (error.Fail())
return Status("Failed to create directory %s: %s",
@@ -193,7 +190,7 @@ int main_platform(int argc, char *argv[]) {
case 'f': // Socket file
if (optarg && optarg[0])
- socket_file.SetFile(optarg, false, FileSpec::Style::native);
+ socket_file.SetFile(optarg, FileSpec::Style::native);
break;
case 'p': {
diff --git a/tools/lldb-server/lldb-server.cpp b/tools/lldb-server/lldb-server.cpp
index f05c96cfaa95..c924fa22f310 100644
--- a/tools/lldb-server/lldb-server.cpp
+++ b/tools/lldb-server/lldb-server.cpp
@@ -38,8 +38,9 @@ int main_gdbserver(int argc, char *argv[]);
int main_platform(int argc, char *argv[]);
static void initialize() {
- g_debugger_lifetime->Initialize(llvm::make_unique<SystemInitializerLLGS>(),
- nullptr);
+ if (auto e = g_debugger_lifetime->Initialize(
+ llvm::make_unique<SystemInitializerLLGS>(), {}, nullptr))
+ llvm::consumeError(std::move(e));
}
static void terminate() { g_debugger_lifetime->Terminate(); }
diff --git a/tools/lldb-test/FormatUtil.cpp b/tools/lldb-test/FormatUtil.cpp
index 381cbd6e25b8..970f25a6b42f 100644
--- a/tools/lldb-test/FormatUtil.cpp
+++ b/tools/lldb-test/FormatUtil.cpp
@@ -14,6 +14,11 @@
using namespace lldb_private;
using namespace llvm;
+LinePrinter::Line::~Line() {
+ if (P)
+ P->NewLine();
+}
+
LinePrinter::LinePrinter(int Indent, llvm::raw_ostream &Stream)
: OS(Stream), IndentSpaces(Indent), CurrentIndent(0) {}
@@ -31,39 +36,31 @@ void LinePrinter::Unindent(uint32_t 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();
+ if (Data.empty()) {
+ line() << Label << " ()";
+ return;
}
- OS << ")";
+ line() << Label << " (";
+ OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ NewLine();
+ line() << ")";
}
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();
+ if (Data.empty()) {
+ line() << Label << " ()";
+ return;
}
- OS << ")";
+ line() << Label << " (";
+ Base += StartOffset;
+ OS << format_bytes_with_ascii(Data, Base, 32, 4, CurrentIndent + IndentSpaces,
+ true);
+ NewLine();
+ line() << ")";
}
diff --git a/tools/lldb-test/FormatUtil.h b/tools/lldb-test/FormatUtil.h
index f22ee41662ee..598d4c5440f5 100644
--- a/tools/lldb-test/FormatUtil.h
+++ b/tools/lldb-test/FormatUtil.h
@@ -26,27 +26,36 @@ class LinePrinter {
int CurrentIndent;
public:
+ class Line {
+ LinePrinter *P;
+
+ public:
+ Line(LinePrinter &P) : P(&P) { P.OS.indent(P.CurrentIndent); }
+ ~Line();
+
+ Line(Line &&RHS) : P(RHS.P) { RHS.P = nullptr; }
+ void operator=(Line &&) = delete;
+
+ operator llvm::raw_ostream &() { return P->OS; }
+ };
+
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);
+ void printLine(const llvm::Twine &T) { line() << 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; }
+ Line line() { return Line(*this); }
int getIndentLevel() const { return CurrentIndent; }
};
@@ -64,12 +73,6 @@ struct AutoIndent {
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
index 2c190ecfc745..1220312def84 100644
--- a/tools/lldb-test/SystemInitializerTest.cpp
+++ b/tools/lldb-test/SystemInitializerTest.cpp
@@ -14,9 +14,6 @@
#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"
@@ -48,22 +45,17 @@
#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/ObjectFile/Breakpad/ObjectFileBreakpad.h"
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.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"
@@ -78,6 +70,7 @@
#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
#include "Plugins/Process/minidump/ProcessMinidump.h"
#include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h"
+#include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h"
#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
@@ -120,16 +113,18 @@ SystemInitializerTest::SystemInitializerTest() {}
SystemInitializerTest::~SystemInitializerTest() {}
-void SystemInitializerTest::Initialize() {
- SystemInitializerCommon::Initialize();
+llvm::Error
+SystemInitializerTest::Initialize(const InitializerOptions &options) {
+ if (auto e = SystemInitializerCommon::Initialize(options))
+ return e;
+ breakpad::ObjectFileBreakpad::Initialize();
ObjectFileELF::Initialize();
ObjectFileMachO::Initialize();
ObjectFilePECOFF::Initialize();
ScriptInterpreterNone::Initialize();
- OperatingSystemGo::Initialize();
platform_freebsd::PlatformFreeBSD::Initialize();
platform_linux::PlatformLinux::Initialize();
@@ -152,9 +147,6 @@ void SystemInitializerTest::Initialize() {
llvm::InitializeAllDisassemblers();
ClangASTContext::Initialize();
- GoASTContext::Initialize();
- JavaASTContext::Initialize();
- OCamlASTContext::Initialize();
ABIMacOSX_i386::Initialize();
ABIMacOSX_arm::Initialize();
@@ -185,6 +177,7 @@ void SystemInitializerTest::Initialize() {
MainThreadCheckerRuntime::Initialize();
SymbolVendorELF::Initialize();
+ breakpad::SymbolFileBreakpad::Initialize();
SymbolFileDWARF::Initialize();
SymbolFilePDB::Initialize();
SymbolFileSymtab::Initialize();
@@ -198,15 +191,10 @@ void SystemInitializerTest::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();
@@ -249,6 +237,8 @@ void SystemInitializerTest::Initialize() {
// AFTER PluginManager::Initialize is called.
Debugger::SettingsInitialize();
+
+ return llvm::Error::success();
}
void SystemInitializerTest::Terminate() {
@@ -261,9 +251,6 @@ void SystemInitializerTest::Terminate() {
PluginManager::Terminate();
ClangASTContext::Terminate();
- GoASTContext::Terminate();
- JavaASTContext::Terminate();
- OCamlASTContext::Terminate();
ABIMacOSX_i386::Terminate();
ABIMacOSX_arm::Terminate();
@@ -289,6 +276,7 @@ void SystemInitializerTest::Terminate() {
UndefinedBehaviorSanitizerRuntime::Terminate();
MainThreadCheckerRuntime::Terminate();
SymbolVendorELF::Terminate();
+ breakpad::SymbolFileBreakpad::Terminate();
SymbolFileDWARF::Terminate();
SymbolFilePDB::Terminate();
SymbolFileSymtab::Terminate();
@@ -302,14 +290,10 @@ void SystemInitializerTest::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();
@@ -337,7 +321,6 @@ void SystemInitializerTest::Terminate() {
DynamicLoaderStatic::Terminate();
DynamicLoaderWindowsDYLD::Terminate();
- OperatingSystemGo::Terminate();
platform_freebsd::PlatformFreeBSD::Terminate();
platform_linux::PlatformLinux::Terminate();
@@ -353,6 +336,7 @@ void SystemInitializerTest::Terminate() {
PlatformDarwinKernel::Terminate();
#endif
+ breakpad::ObjectFileBreakpad::Terminate();
ObjectFileELF::Terminate();
ObjectFileMachO::Terminate();
ObjectFilePECOFF::Terminate();
diff --git a/tools/lldb-test/SystemInitializerTest.h b/tools/lldb-test/SystemInitializerTest.h
index 887d6243765d..5950ff725ff0 100644
--- a/tools/lldb-test/SystemInitializerTest.h
+++ b/tools/lldb-test/SystemInitializerTest.h
@@ -26,7 +26,7 @@ public:
SystemInitializerTest();
~SystemInitializerTest() override;
- void Initialize() override;
+ llvm::Error Initialize(const InitializerOptions &options) override;
void Terminate() override;
};
diff --git a/tools/lldb-test/lldb-test.cpp b/tools/lldb-test/lldb-test.cpp
index c9225f63d303..f7bfc487c0ce 100644
--- a/tools/lldb-test/lldb-test.cpp
+++ b/tools/lldb-test/lldb-test.cpp
@@ -30,6 +30,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Utility/CleanUp.h"
#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/State.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/IntervalMap.h"
@@ -90,19 +91,27 @@ namespace object {
cl::opt<bool> SectionContents("contents",
cl::desc("Dump each section's contents"),
cl::sub(ObjectFileSubcommand));
+cl::opt<bool> SectionDependentModules("dep-modules",
+ cl::desc("Dump each dependent module"),
+ cl::sub(ObjectFileSubcommand));
cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
cl::OneOrMore,
cl::sub(ObjectFileSubcommand));
} // namespace object
namespace symbols {
-static cl::list<std::string> InputFilenames(cl::Positional,
- cl::desc("<input files>"),
- cl::OneOrMore,
- cl::sub(SymbolsSubcommand));
+static cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input file>"),
+ cl::Required, cl::sub(SymbolsSubcommand));
+
+static cl::opt<std::string>
+ SymbolPath("symbol-file",
+ cl::desc("The file from which to fetch symbol information."),
+ cl::value_desc("file"), cl::sub(SymbolsSubcommand));
+
enum class FindType {
None,
Function,
+ Block,
Namespace,
Type,
Variable,
@@ -112,6 +121,7 @@ static cl::opt<FindType> Find(
cl::values(
clEnumValN(FindType::None, "none", "No search, just dump the module."),
clEnumValN(FindType::Function, "function", "Find functions."),
+ clEnumValN(FindType::Block, "block", "Find blocks."),
clEnumValN(FindType::Namespace, "namespace", "Find namespaces."),
clEnumValN(FindType::Type, "type", "Find types."),
clEnumValN(FindType::Variable, "variable", "Find global variables.")),
@@ -146,6 +156,10 @@ static FunctionNameType getFunctionNameFlags() {
return Result;
}
+static cl::opt<bool> DumpAST("dump-ast",
+ cl::desc("Dump AST restored from symbols."),
+ cl::sub(SymbolsSubcommand));
+
static cl::opt<bool> Verify("verify", cl::desc("Verify symbol information."),
cl::sub(SymbolsSubcommand));
@@ -158,10 +172,12 @@ static cl::opt<int> Line("line", cl::desc("Line to search."),
static Expected<CompilerDeclContext> getDeclContext(SymbolVendor &Vendor);
static Error findFunctions(lldb_private::Module &Module);
+static Error findBlocks(lldb_private::Module &Module);
static Error findNamespaces(lldb_private::Module &Module);
static Error findTypes(lldb_private::Module &Module);
static Error findVariables(lldb_private::Module &Module);
static Error dumpModule(lldb_private::Module &Module);
+static Error dumpAST(lldb_private::Module &Module);
static Error verify(lldb_private::Module &Module);
static Expected<Error (*)(lldb_private::Module &)> getAction();
@@ -197,7 +213,6 @@ struct IRMemoryMapTestState {
: Target(Target), Map(Target), Allocations(IntervalMapAllocator) {}
};
-bool areAllocationsOverlapping(const AllocationT &L, const AllocationT &R);
bool evalMalloc(StringRef Line, IRMemoryMapTestState &State);
bool evalFree(StringRef Line, IRMemoryMapTestState &State);
int evaluateMemoryMapCommands(Debugger &Dbg);
@@ -214,10 +229,9 @@ static Error make_string_error(const char *Format, Args &&... args) {
TargetSP opts::createTarget(Debugger &Dbg, const std::string &Filename) {
TargetSP Target;
- Status ST =
- Dbg.GetTargetList().CreateTarget(Dbg, Filename, /*triple*/ "",
- /*get_dependent_modules*/ false,
- /*platform_options*/ nullptr, Target);
+ Status ST = Dbg.GetTargetList().CreateTarget(
+ Dbg, Filename, /*triple*/ "", eLoadDependentsNo,
+ /*platform_options*/ nullptr, Target);
if (ST.Fail()) {
errs() << formatv("Failed to create target '{0}: {1}\n", Filename, ST);
exit(1);
@@ -278,7 +292,7 @@ std::string opts::breakpoint::substitute(StringRef Cmd) {
OS << sys::path::parent_path(breakpoint::CommandFile);
break;
}
- // fall through
+ LLVM_FALLTHROUGH;
default:
size_t pos = Cmd.find('%');
OS << Cmd.substr(0, pos);
@@ -340,7 +354,7 @@ Error opts::symbols::findFunctions(lldb_private::Module &Module) {
if (!File.empty()) {
assert(Line != 0);
- FileSpec src_file(File, false);
+ FileSpec src_file(File);
size_t cu_count = Module.GetNumCompileUnits();
for (size_t i = 0; i < cu_count; i++) {
lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i);
@@ -383,6 +397,42 @@ Error opts::symbols::findFunctions(lldb_private::Module &Module) {
return Error::success();
}
+Error opts::symbols::findBlocks(lldb_private::Module &Module) {
+ assert(!Regex);
+ assert(!File.empty());
+ assert(Line != 0);
+
+ SymbolContextList List;
+
+ FileSpec src_file(File);
+ size_t cu_count = Module.GetNumCompileUnits();
+ for (size_t i = 0; i < cu_count; i++) {
+ lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i);
+ if (!cu_sp)
+ continue;
+
+ LineEntry le;
+ cu_sp->FindLineEntry(0, Line, &src_file, false, &le);
+ if (!le.IsValid())
+ continue;
+
+ auto addr = le.GetSameLineContiguousAddressRange().GetBaseAddress();
+ if (!addr.IsValid())
+ continue;
+
+ SymbolContext sc;
+ uint32_t resolved = addr.CalculateSymbolContext(&sc, eSymbolContextBlock);
+ if (resolved & eSymbolContextBlock)
+ List.Append(sc);
+ }
+
+ outs() << formatv("Found {0} blocks:\n", List.GetSize());
+ StreamString Stream;
+ List.Dump(&Stream, nullptr);
+ outs() << Stream.GetData() << "\n";
+ return Error::success();
+}
+
Error opts::symbols::findNamespaces(lldb_private::Module &Module) {
SymbolVendor &Vendor = *Module.GetSymbolVendor();
Expected<CompilerDeclContext> ContextOr = getDeclContext(Vendor);
@@ -391,9 +441,8 @@ Error opts::symbols::findNamespaces(lldb_private::Module &Module) {
CompilerDeclContext *ContextPtr =
ContextOr->IsValid() ? &*ContextOr : nullptr;
- SymbolContext SC;
CompilerDeclContext Result =
- Vendor.FindNamespace(SC, ConstString(Name), ContextPtr);
+ Vendor.FindNamespace(ConstString(Name), ContextPtr);
if (Result)
outs() << "Found namespace: "
<< Result.GetScopeQualifiedName().GetStringRef() << "\n";
@@ -410,10 +459,9 @@ Error opts::symbols::findTypes(lldb_private::Module &Module) {
CompilerDeclContext *ContextPtr =
ContextOr->IsValid() ? &*ContextOr : nullptr;
- SymbolContext SC;
DenseSet<SymbolFile *> SearchedFiles;
TypeMap Map;
- Vendor.FindTypes(SC, ConstString(Name), ContextPtr, true, UINT32_MAX,
+ Vendor.FindTypes(ConstString(Name), ContextPtr, true, UINT32_MAX,
SearchedFiles, Map);
outs() << formatv("Found {0} types:\n", Map.GetSize());
@@ -470,6 +518,32 @@ Error opts::symbols::dumpModule(lldb_private::Module &Module) {
return Error::success();
}
+Error opts::symbols::dumpAST(lldb_private::Module &Module) {
+ SymbolVendor &plugin = *Module.GetSymbolVendor();
+ Module.ParseAllDebugSymbols();
+
+ auto symfile = plugin.GetSymbolFile();
+ if (!symfile)
+ return make_string_error("Module has no symbol file.");
+
+ auto clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
+ symfile->GetTypeSystemForLanguage(eLanguageTypeC_plus_plus));
+ if (!clang_ast_ctx)
+ return make_string_error("Can't retrieve Clang AST context.");
+
+ auto ast_ctx = clang_ast_ctx->getASTContext();
+ if (!ast_ctx)
+ return make_string_error("Can't retrieve AST context.");
+
+ auto tu = ast_ctx->getTranslationUnitDecl();
+ if (!tu)
+ return make_string_error("Can't retrieve translation unit declaration.");
+
+ tu->print(outs());
+
+ return Error::success();
+}
+
Error opts::symbols::verify(lldb_private::Module &Module) {
SymbolVendor &plugin = *Module.GetSymbolVendor();
@@ -523,6 +597,10 @@ Error opts::symbols::verify(lldb_private::Module &Module) {
}
Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
+ if (Verify && DumpAST)
+ return make_string_error(
+ "Cannot both verify symbol information and dump AST.");
+
if (Verify) {
if (Find != FindType::None)
return make_string_error(
@@ -535,6 +613,17 @@ Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
return verify;
}
+ if (DumpAST) {
+ if (Find != FindType::None)
+ return make_string_error("Cannot both search and dump AST.");
+ if (Regex || !Context.empty() || !Name.empty() || !File.empty() ||
+ Line != 0)
+ return make_string_error(
+ "-regex, -context, -name, -file and -line options are not "
+ "applicable for dumping AST.");
+ return dumpAST;
+ }
+
if (Regex && !Context.empty())
return make_string_error(
"Cannot search using both regular expressions and context.");
@@ -566,6 +655,15 @@ Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
"when searching a function.");
return findFunctions;
+ case FindType::Block:
+ if (File.empty() || Line == 0)
+ return make_string_error("Both file name and line number must be "
+ "specified when searching a block.");
+ if (Regex || getFunctionNameFlags() != 0)
+ return make_string_error("Cannot use regular expression or "
+ "function-flags for searching a block.");
+ return findBlocks;
+
case FindType::Namespace:
if (Regex || !File.empty() || Line != 0)
return make_string_error("Cannot search for namespaces using regular "
@@ -584,6 +682,8 @@ Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
"using line numbers.");
return findVariables;
}
+
+ llvm_unreachable("Unsupported symbol action.");
}
int opts::symbols::dumpSymbols(Debugger &Dbg) {
@@ -594,28 +694,59 @@ int opts::symbols::dumpSymbols(Debugger &Dbg) {
}
auto Action = *ActionOr;
- int HadErrors = 0;
- for (const auto &File : InputFilenames) {
- outs() << "Module: " << File << "\n";
- ModuleSpec Spec{FileSpec(File, false)};
- Spec.GetSymbolFileSpec().SetFile(File, false, FileSpec::Style::native);
+ outs() << "Module: " << InputFile << "\n";
+ ModuleSpec Spec{FileSpec(InputFile)};
+ StringRef Symbols = SymbolPath.empty() ? InputFile : SymbolPath;
+ Spec.GetSymbolFileSpec().SetFile(Symbols, FileSpec::Style::native);
- auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
- SymbolVendor *Vendor = ModulePtr->GetSymbolVendor();
- if (!Vendor) {
- WithColor::error() << "Module has no symbol vendor.\n";
- HadErrors = 1;
- continue;
- }
+ auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
+ SymbolVendor *Vendor = ModulePtr->GetSymbolVendor();
+ if (!Vendor) {
+ WithColor::error() << "Module has no symbol vendor.\n";
+ return 1;
+ }
- if (Error E = Action(*ModulePtr)) {
- WithColor::error() << toString(std::move(E)) << "\n";
- HadErrors = 1;
+ if (Error E = Action(*ModulePtr)) {
+ WithColor::error() << toString(std::move(E)) << "\n";
+ return 1;
+ }
+
+ return 0;
+}
+
+static void dumpSectionList(LinePrinter &Printer, const SectionList &List, bool is_subsection) {
+ size_t Count = List.GetNumSections(0);
+ if (Count == 0) {
+ Printer.formatLine("There are no {0}sections", is_subsection ? "sub" : "");
+ return;
+ }
+ Printer.formatLine("Showing {0} {1}sections", Count,
+ is_subsection ? "sub" : "");
+ for (size_t I = 0; I < Count; ++I) {
+ auto S = List.GetSectionAtIndex(I);
+ assert(S);
+ AutoIndent Indent(Printer, 2);
+ Printer.formatLine("Index: {0}", I);
+ Printer.formatLine("ID: {0:x}", S->GetID());
+ Printer.formatLine("Name: {0}", S->GetName().GetStringRef());
+ Printer.formatLine("Type: {0}", S->GetTypeAsCString());
+ Printer.formatLine("Permissions: {0}", GetPermissionsAsCString(S->GetPermissions()));
+ Printer.formatLine("Thread specific: {0:y}", S->IsThreadSpecific());
+ Printer.formatLine("VM address: {0:x}", S->GetFileAddress());
+ Printer.formatLine("VM size: {0}", S->GetByteSize());
+ Printer.formatLine("File size: {0}", S->GetFileSize());
+
+ if (opts::object::SectionContents) {
+ DataExtractor Data;
+ S->GetSectionData(Data);
+ ArrayRef<uint8_t> Bytes = {Data.GetDataStart(), Data.GetDataEnd()};
+ Printer.formatBinary("Data: ", Bytes, 0);
}
- outs().flush();
+ if (S->GetType() == eSectionTypeContainer)
+ dumpSectionList(Printer, S->GetChildren(), true);
+ Printer.NewLine();
}
- return HadErrors;
}
static int dumpObjectFiles(Debugger &Dbg) {
@@ -623,9 +754,17 @@ static int dumpObjectFiles(Debugger &Dbg) {
int HadErrors = 0;
for (const auto &File : opts::object::InputFilenames) {
- ModuleSpec Spec{FileSpec(File, false)};
+ ModuleSpec Spec{FileSpec(File)};
auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
+
+ ObjectFile *ObjectPtr = ModulePtr->GetObjectFile();
+ if (!ObjectPtr) {
+ WithColor::error() << File << " not recognised as an object file\n";
+ HadErrors = 1;
+ continue;
+ }
+
// Fetch symbol vendor before we get the section list to give the symbol
// vendor a chance to populate it.
ModulePtr->GetSymbolVendor();
@@ -636,27 +775,29 @@ static int dumpObjectFiles(Debugger &Dbg) {
continue;
}
+ Printer.formatLine("Plugin name: {0}", ObjectPtr->GetPluginName());
Printer.formatLine("Architecture: {0}",
ModulePtr->GetArchitecture().GetTriple().getTriple());
Printer.formatLine("UUID: {0}", ModulePtr->GetUUID().GetAsString());
-
- 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("Type: {0}", S->GetTypeAsCString());
- Printer.formatLine("VM size: {0}", S->GetByteSize());
- Printer.formatLine("File size: {0}", S->GetFileSize());
-
- if (opts::object::SectionContents) {
- DataExtractor Data;
- S->GetSectionData(Data);
- ArrayRef<uint8_t> Bytes = {Data.GetDataStart(), Data.GetDataEnd()};
- Printer.formatBinary("Data: ", Bytes, 0);
+ Printer.formatLine("Executable: {0}", ObjectPtr->IsExecutable());
+ Printer.formatLine("Stripped: {0}", ObjectPtr->IsStripped());
+ Printer.formatLine("Type: {0}", ObjectPtr->GetType());
+ Printer.formatLine("Strata: {0}", ObjectPtr->GetStrata());
+ Printer.formatLine("Base VM address: {0:x}",
+ ObjectPtr->GetBaseAddress().GetFileAddress());
+
+ dumpSectionList(Printer, *Sections, /*is_subsection*/ false);
+
+ if (opts::object::SectionDependentModules) {
+ // A non-empty section list ensures a valid object file.
+ auto Obj = ModulePtr->GetObjectFile();
+ FileSpecList Files;
+ auto Count = Obj->GetDependentModules(Files);
+ Printer.formatLine("Showing {0} dependent module(s)", Count);
+ for (size_t I = 0; I < Files.GetSize(); ++I) {
+ AutoIndent Indent(Printer, 2);
+ Printer.formatLine("Name: {0}",
+ Files.GetFileSpecAtIndex(I).GetCString());
}
Printer.NewLine();
}
@@ -664,13 +805,6 @@ static int dumpObjectFiles(Debugger &Dbg) {
return HadErrors;
}
-/// Check if two half-open intervals intersect:
-/// http://world.std.com/~swmcd/steven/tech/interval.html
-bool opts::irmemorymap::areAllocationsOverlapping(const AllocationT &L,
- const AllocationT &R) {
- return R.first < L.second && L.first < R.second;
-}
-
bool opts::irmemorymap::evalMalloc(StringRef Line,
IRMemoryMapTestState &State) {
// ::= <label> = malloc <size> <alignment>
@@ -717,28 +851,21 @@ bool opts::irmemorymap::evalMalloc(StringRef Line,
exit(1);
}
- // Check that the allocation does not overlap another allocation. Do so by
- // testing each allocation which may cover the interval [Addr, EndOfRegion).
- addr_t EndOfRegion = Addr + Size;
- auto Probe = State.Allocations.begin();
- Probe.advanceTo(Addr); //< First interval s.t stop >= Addr.
- AllocationT NewAllocation = {Addr, EndOfRegion};
- while (Probe != State.Allocations.end() && Probe.start() < EndOfRegion) {
- AllocationT ProbeAllocation = {Probe.start(), Probe.stop()};
- if (areAllocationsOverlapping(ProbeAllocation, NewAllocation)) {
- outs() << "Malloc error: overlapping allocation detected"
- << formatv(", previous allocation at [{0:x}, {1:x})\n",
- Probe.start(), Probe.stop());
- exit(1);
- }
- ++Probe;
+ // In case of Size == 0, we still expect the returned address to be unique and
+ // non-overlapping.
+ addr_t EndOfRegion = Addr + std::max<size_t>(Size, 1);
+ if (State.Allocations.overlaps(Addr, EndOfRegion)) {
+ auto I = State.Allocations.find(Addr);
+ outs() << "Malloc error: overlapping allocation detected"
+ << formatv(", previous allocation at [{0:x}, {1:x})\n", I.start(),
+ I.stop());
+ exit(1);
}
- // Insert the new allocation into the interval map. Use unique allocation IDs
- // to inhibit interval coalescing.
+ // Insert the new allocation into the interval map. Use unique allocation
+ // IDs to inhibit interval coalescing.
static unsigned AllocationID = 0;
- if (Size)
- State.Allocations.insert(Addr, EndOfRegion, AllocationID++);
+ State.Allocations.insert(Addr, EndOfRegion, AllocationID++);
// Store the label -> address mapping.
State.Label2AddrMap[Label] = Addr;
@@ -836,8 +963,13 @@ int main(int argc, const char *argv[]) {
cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
SystemLifetimeManager DebuggerLifetime;
- DebuggerLifetime.Initialize(llvm::make_unique<SystemInitializerTest>(),
- nullptr);
+ if (auto e = DebuggerLifetime.Initialize(
+ llvm::make_unique<SystemInitializerTest>(), {}, nullptr)) {
+ WithColor::error() << "initialization failed: " << toString(std::move(e))
+ << '\n';
+ return 1;
+ }
+
CleanUp TerminateDebugger([&] { DebuggerLifetime.Terminate(); });
auto Dbg = lldb_private::Debugger::CreateInstance();
diff --git a/tools/lldb-vscode/BreakpointBase.cpp b/tools/lldb-vscode/BreakpointBase.cpp
new file mode 100644
index 000000000000..adb7abd1a3a1
--- /dev/null
+++ b/tools/lldb-vscode/BreakpointBase.cpp
@@ -0,0 +1,37 @@
+//===-- BreakpointBase.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BreakpointBase.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace lldb_vscode;
+
+BreakpointBase::BreakpointBase(const llvm::json::Object &obj)
+ : condition(GetString(obj, "condition")),
+ hitCondition(GetString(obj, "hitCondition")),
+ logMessage(GetString(obj, "logMessage")) {}
+
+void BreakpointBase::SetCondition() { bp.SetCondition(condition.c_str()); }
+
+void BreakpointBase::SetHitCondition() {
+ uint64_t hitCount = 0;
+ if (llvm::to_integer(hitCondition, hitCount))
+ bp.SetIgnoreCount(hitCount - 1);
+}
+
+void BreakpointBase::UpdateBreakpoint(const BreakpointBase &request_bp) {
+ if (condition != request_bp.condition) {
+ condition = request_bp.condition;
+ SetCondition();
+ }
+ if (hitCondition != request_bp.hitCondition) {
+ hitCondition = request_bp.hitCondition;
+ SetHitCondition();
+ }
+}
diff --git a/tools/lldb-vscode/BreakpointBase.h b/tools/lldb-vscode/BreakpointBase.h
new file mode 100644
index 000000000000..e27ffe3bd390
--- /dev/null
+++ b/tools/lldb-vscode/BreakpointBase.h
@@ -0,0 +1,44 @@
+//===-- BreakpointBase.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDBVSCODE_BREAKPOINTBASE_H_
+#define LLDBVSCODE_BREAKPOINTBASE_H_
+
+#include "JSONUtils.h"
+#include "lldb/API/SBBreakpoint.h"
+#include "llvm/Support/JSON.h"
+#include <string>
+
+namespace lldb_vscode {
+
+struct BreakpointBase {
+
+ // An optional expression for conditional breakpoints.
+ std::string condition;
+ // An optional expression that controls how many hits of the breakpoint are
+ // ignored. The backend is expected to interpret the expression as needed
+ std::string hitCondition;
+ // If this attribute exists and is non-empty, the backend must not 'break'
+ // (stop) but log the message instead. Expressions within {} are
+ // interpolated.
+ std::string logMessage;
+ // The LLDB breakpoint associated wit this source breakpoint
+ lldb::SBBreakpoint bp;
+
+ BreakpointBase() = default;
+ BreakpointBase(const llvm::json::Object &obj);
+
+ void SetCondition();
+ void SetHitCondition();
+ void UpdateBreakpoint(const BreakpointBase &request_bp);
+};
+
+} // namespace lldb_vscode
+
+#endif
diff --git a/tools/lldb-vscode/CMakeLists.txt b/tools/lldb-vscode/CMakeLists.txt
new file mode 100644
index 000000000000..08511248d335
--- /dev/null
+++ b/tools/lldb-vscode/CMakeLists.txt
@@ -0,0 +1,34 @@
+if ( CMAKE_SYSTEM_NAME MATCHES "Windows" OR CMAKE_SYSTEM_NAME MATCHES "NetBSD" )
+ add_definitions( -DIMPORT_LIBLLDB )
+ list(APPEND extra_libs lldbHost)
+endif ()
+
+if (HAVE_LIBPTHREAD)
+ list(APPEND extra_libs pthread)
+endif ()
+
+# We need to include the llvm components we depend on manually, as liblldb does
+# not re-export those.
+set(LLVM_LINK_COMPONENTS Support)
+add_lldb_tool(lldb-vscode
+ lldb-vscode.cpp
+ BreakpointBase.cpp
+ ExceptionBreakpoint.cpp
+ FunctionBreakpoint.cpp
+ JSONUtils.cpp
+ LLDBUtils.cpp
+ SourceBreakpoint.cpp
+ VSCode.cpp
+
+ LINK_LIBS
+ liblldb
+ ${host_lib}
+ ${extra_libs}
+
+ LINK_COMPONENTS
+ Support
+ )
+
+if(LLDB_BUILD_FRAMEWORK)
+ lldb_setup_framework_rpaths_in_tool(lldb-vscode)
+endif()
diff --git a/tools/lldb-vscode/ExceptionBreakpoint.cpp b/tools/lldb-vscode/ExceptionBreakpoint.cpp
new file mode 100644
index 000000000000..96bc0930e429
--- /dev/null
+++ b/tools/lldb-vscode/ExceptionBreakpoint.cpp
@@ -0,0 +1,32 @@
+//===-- ExceptionBreakpoint.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExceptionBreakpoint.h"
+#include "VSCode.h"
+
+namespace lldb_vscode {
+
+void ExceptionBreakpoint::SetBreakpoint() {
+ if (bp.IsValid())
+ return;
+ bool catch_value = filter.find("_catch") != std::string::npos;
+ bool throw_value = filter.find("_throw") != std::string::npos;
+ bp = g_vsc.target.BreakpointCreateForException(language, catch_value,
+ throw_value);
+}
+
+void ExceptionBreakpoint::ClearBreakpoint() {
+ if (!bp.IsValid())
+ return;
+ g_vsc.target.BreakpointDelete(bp.GetID());
+ bp = lldb::SBBreakpoint();
+}
+
+} // namespace lldb_vscode
+
diff --git a/tools/lldb-vscode/ExceptionBreakpoint.h b/tools/lldb-vscode/ExceptionBreakpoint.h
new file mode 100644
index 000000000000..f3e1e7068095
--- /dev/null
+++ b/tools/lldb-vscode/ExceptionBreakpoint.h
@@ -0,0 +1,38 @@
+//===-- ExceptionBreakpoint.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDBVSCODE_EXCEPTIONBREAKPOINT_H_
+#define LLDBVSCODE_EXCEPTIONBREAKPOINT_H_
+
+#include <string>
+
+#include "lldb/API/SBBreakpoint.h"
+
+namespace lldb_vscode {
+
+struct ExceptionBreakpoint {
+ std::string filter;
+ std::string label;
+ lldb::LanguageType language;
+ bool default_value;
+ lldb::SBBreakpoint bp;
+ ExceptionBreakpoint(std::string f, std::string l, lldb::LanguageType lang) :
+ filter(std::move(f)),
+ label(std::move(l)),
+ language(lang),
+ default_value(false),
+ bp() {}
+
+ void SetBreakpoint();
+ void ClearBreakpoint();
+};
+
+} // namespace lldb_vscode
+
+#endif
diff --git a/tools/lldb-vscode/FunctionBreakpoint.cpp b/tools/lldb-vscode/FunctionBreakpoint.cpp
new file mode 100644
index 000000000000..f83333dc9895
--- /dev/null
+++ b/tools/lldb-vscode/FunctionBreakpoint.cpp
@@ -0,0 +1,28 @@
+//===-- FunctionBreakpoint.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FunctionBreakpoint.h"
+#include "VSCode.h"
+
+namespace lldb_vscode {
+
+FunctionBreakpoint::FunctionBreakpoint(const llvm::json::Object &obj)
+ : BreakpointBase(obj), functionName(GetString(obj, "name")) {}
+
+void FunctionBreakpoint::SetBreakpoint() {
+ if (functionName.empty())
+ return;
+ bp = g_vsc.target.BreakpointCreateByName(functionName.c_str());
+ if (!condition.empty())
+ SetCondition();
+ if (!hitCondition.empty())
+ SetHitCondition();
+}
+
+}
diff --git a/tools/lldb-vscode/FunctionBreakpoint.h b/tools/lldb-vscode/FunctionBreakpoint.h
new file mode 100644
index 000000000000..ff4f34dba077
--- /dev/null
+++ b/tools/lldb-vscode/FunctionBreakpoint.h
@@ -0,0 +1,29 @@
+//===-- FunctionBreakpoint.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDBVSCODE_FUNCTIONBREAKPOINT_H_
+#define LLDBVSCODE_FUNCTIONBREAKPOINT_H_
+
+#include "BreakpointBase.h"
+
+namespace lldb_vscode {
+
+struct FunctionBreakpoint : public BreakpointBase {
+ std::string functionName;
+
+ FunctionBreakpoint() = default;
+ FunctionBreakpoint(const llvm::json::Object &obj);
+
+ // Set this breakpoint in LLDB as a new breakpoint
+ void SetBreakpoint();
+};
+
+} // namespace lldb_vscode
+
+#endif
diff --git a/tools/lldb-vscode/JSONUtils.cpp b/tools/lldb-vscode/JSONUtils.cpp
new file mode 100644
index 000000000000..76cd44cc72d1
--- /dev/null
+++ b/tools/lldb-vscode/JSONUtils.cpp
@@ -0,0 +1,892 @@
+//===-- JSONUtils.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <algorithm>
+
+#include "llvm/Support/FormatAdapters.h"
+
+#include "lldb/API/SBBreakpoint.h"
+#include "lldb/API/SBBreakpointLocation.h"
+#include "lldb/API/SBValue.h"
+#include "lldb/Host/PosixApi.h"
+
+#include "ExceptionBreakpoint.h"
+#include "JSONUtils.h"
+#include "LLDBUtils.h"
+#include "VSCode.h"
+
+namespace lldb_vscode {
+
+void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
+ llvm::StringRef str) {
+ if (LLVM_LIKELY(llvm::json::isUTF8(str)))
+ obj.try_emplace(key, str.str());
+ else
+ obj.try_emplace(key, llvm::json::fixUTF8(str));
+}
+
+llvm::StringRef GetAsString(const llvm::json::Value &value) {
+ if (auto s = value.getAsString())
+ return *s;
+ return llvm::StringRef();
+}
+
+// Gets a string from a JSON object using the key, or returns an empty string.
+llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key) {
+ if (auto value = obj.getString(key))
+ return GetAsString(*value);
+ return llvm::StringRef();
+}
+
+llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key) {
+ if (obj == nullptr)
+ return llvm::StringRef();
+ return GetString(*obj, key);
+}
+
+// Gets an unsigned integer from a JSON object using the key, or returns the
+// specified fail value.
+uint64_t GetUnsigned(const llvm::json::Object &obj, llvm::StringRef key,
+ uint64_t fail_value) {
+ if (auto value = obj.getInteger(key))
+ return (uint64_t)*value;
+ return fail_value;
+}
+
+uint64_t GetUnsigned(const llvm::json::Object *obj, llvm::StringRef key,
+ uint64_t fail_value) {
+ if (obj == nullptr)
+ return fail_value;
+ return GetUnsigned(*obj, key, fail_value);
+}
+
+bool GetBoolean(const llvm::json::Object &obj, llvm::StringRef key,
+ bool fail_value) {
+ if (auto value = obj.getBoolean(key))
+ return *value;
+ if (auto value = obj.getInteger(key))
+ return *value != 0;
+ return fail_value;
+}
+
+bool GetBoolean(const llvm::json::Object *obj, llvm::StringRef key,
+ bool fail_value) {
+ if (obj == nullptr)
+ return fail_value;
+ return GetBoolean(*obj, key, fail_value);
+}
+
+int64_t GetSigned(const llvm::json::Object &obj, llvm::StringRef key,
+ int64_t fail_value) {
+ if (auto value = obj.getInteger(key))
+ return *value;
+ return fail_value;
+}
+
+int64_t GetSigned(const llvm::json::Object *obj, llvm::StringRef key,
+ int64_t fail_value) {
+ if (obj == nullptr)
+ return fail_value;
+ return GetSigned(*obj, key, fail_value);
+}
+
+bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key) {
+ return obj.find(key) != obj.end();
+}
+
+std::vector<std::string> GetStrings(const llvm::json::Object *obj,
+ llvm::StringRef key) {
+ std::vector<std::string> strs;
+ auto json_array = obj->getArray(key);
+ if (!json_array)
+ return strs;
+ for (const auto &value : *json_array) {
+ switch (value.kind()) {
+ case llvm::json::Value::String:
+ strs.push_back(value.getAsString()->str());
+ break;
+ case llvm::json::Value::Number:
+ case llvm::json::Value::Boolean: {
+ std::string s;
+ llvm::raw_string_ostream strm(s);
+ strm << value;
+ strs.push_back(strm.str());
+ break;
+ }
+ case llvm::json::Value::Null:
+ case llvm::json::Value::Object:
+ case llvm::json::Value::Array:
+ break;
+ }
+ }
+ return strs;
+}
+
+void SetValueForKey(lldb::SBValue &v, llvm::json::Object &object,
+ llvm::StringRef key) {
+
+ llvm::StringRef value = v.GetValue();
+ llvm::StringRef summary = v.GetSummary();
+ llvm::StringRef type_name = v.GetType().GetDisplayTypeName();
+
+ std::string result;
+ llvm::raw_string_ostream strm(result);
+ if (!value.empty()) {
+ strm << value;
+ if (!summary.empty())
+ strm << ' ' << summary;
+ } else if (!summary.empty()) {
+ strm << ' ' << summary;
+ } else if (!type_name.empty()) {
+ strm << type_name;
+ lldb::addr_t address = v.GetLoadAddress();
+ if (address != LLDB_INVALID_ADDRESS)
+ strm << " @ " << llvm::format_hex(address, 0);
+ }
+ strm.flush();
+ EmplaceSafeString(object, key, result);
+}
+
+void FillResponse(const llvm::json::Object &request,
+ llvm::json::Object &response) {
+ // Fill in all of the needed response fields to a "request" and set "success"
+ // to true by default.
+ response.try_emplace("type", "response");
+ response.try_emplace("seq", (int64_t)0);
+ EmplaceSafeString(response, "command", GetString(request, "command"));
+ const int64_t seq = GetSigned(request, "seq", 0);
+ response.try_emplace("request_seq", seq);
+ response.try_emplace("success", true);
+}
+
+//----------------------------------------------------------------------
+// "Scope": {
+// "type": "object",
+// "description": "A Scope is a named container for variables. Optionally
+// a scope can map to a source or a range within a source.",
+// "properties": {
+// "name": {
+// "type": "string",
+// "description": "Name of the scope such as 'Arguments', 'Locals'."
+// },
+// "variablesReference": {
+// "type": "integer",
+// "description": "The variables of this scope can be retrieved by
+// passing the value of variablesReference to the
+// VariablesRequest."
+// },
+// "namedVariables": {
+// "type": "integer",
+// "description": "The number of named variables in this scope. The
+// client can use this optional information to present
+// the variables in a paged UI and fetch them in chunks."
+// },
+// "indexedVariables": {
+// "type": "integer",
+// "description": "The number of indexed variables in this scope. The
+// client can use this optional information to present
+// the variables in a paged UI and fetch them in chunks."
+// },
+// "expensive": {
+// "type": "boolean",
+// "description": "If true, the number of variables in this scope is
+// large or expensive to retrieve."
+// },
+// "source": {
+// "$ref": "#/definitions/Source",
+// "description": "Optional source for this scope."
+// },
+// "line": {
+// "type": "integer",
+// "description": "Optional start line of the range covered by this
+// scope."
+// },
+// "column": {
+// "type": "integer",
+// "description": "Optional start column of the range covered by this
+// scope."
+// },
+// "endLine": {
+// "type": "integer",
+// "description": "Optional end line of the range covered by this scope."
+// },
+// "endColumn": {
+// "type": "integer",
+// "description": "Optional end column of the range covered by this
+// scope."
+// }
+// },
+// "required": [ "name", "variablesReference", "expensive" ]
+// }
+//----------------------------------------------------------------------
+llvm::json::Value CreateScope(const llvm::StringRef name,
+ int64_t variablesReference,
+ int64_t namedVariables, bool expensive) {
+ llvm::json::Object object;
+ EmplaceSafeString(object, "name", name.str());
+ object.try_emplace("variablesReference", variablesReference);
+ object.try_emplace("expensive", expensive);
+ object.try_emplace("namedVariables", namedVariables);
+ return llvm::json::Value(std::move(object));
+}
+
+//----------------------------------------------------------------------
+// "Breakpoint": {
+// "type": "object",
+// "description": "Information about a Breakpoint created in setBreakpoints
+// or setFunctionBreakpoints.",
+// "properties": {
+// "id": {
+// "type": "integer",
+// "description": "An optional unique identifier for the breakpoint."
+// },
+// "verified": {
+// "type": "boolean",
+// "description": "If true breakpoint could be set (but not necessarily
+// at the desired location)."
+// },
+// "message": {
+// "type": "string",
+// "description": "An optional message about the state of the breakpoint.
+// This is shown to the user and can be used to explain
+// why a breakpoint could not be verified."
+// },
+// "source": {
+// "$ref": "#/definitions/Source",
+// "description": "The source where the breakpoint is located."
+// },
+// "line": {
+// "type": "integer",
+// "description": "The start line of the actual range covered by the
+// breakpoint."
+// },
+// "column": {
+// "type": "integer",
+// "description": "An optional start column of the actual range covered
+// by the breakpoint."
+// },
+// "endLine": {
+// "type": "integer",
+// "description": "An optional end line of the actual range covered by
+// the breakpoint."
+// },
+// "endColumn": {
+// "type": "integer",
+// "description": "An optional end column of the actual range covered by
+// the breakpoint. If no end line is given, then the end
+// column is assumed to be in the start line."
+// }
+// },
+// "required": [ "verified" ]
+// }
+//----------------------------------------------------------------------
+llvm::json::Value CreateBreakpoint(lldb::SBBreakpointLocation &bp_loc) {
+ // Each breakpoint location is treated as a separate breakpoint for VS code.
+ // They don't have the notion of a single breakpoint with multiple locations.
+ llvm::json::Object object;
+ if (!bp_loc.IsValid())
+ return llvm::json::Value(std::move(object));
+
+ object.try_emplace("verified", true);
+ const auto vs_id = MakeVSCodeBreakpointID(bp_loc);
+ object.try_emplace("id", vs_id);
+ auto bp_addr = bp_loc.GetAddress();
+ if (bp_addr.IsValid()) {
+ auto line_entry = bp_addr.GetLineEntry();
+ const auto line = line_entry.GetLine();
+ if (line != UINT32_MAX)
+ object.try_emplace("line", line);
+ object.try_emplace("source", CreateSource(line_entry));
+ }
+ return llvm::json::Value(std::move(object));
+}
+
+void AppendBreakpoint(lldb::SBBreakpoint &bp, llvm::json::Array &breakpoints) {
+ if (!bp.IsValid())
+ return;
+ const auto num_locations = bp.GetNumLocations();
+ if (num_locations == 0)
+ return;
+ for (size_t i = 0; i < num_locations; ++i) {
+ auto bp_loc = bp.GetLocationAtIndex(i);
+ breakpoints.emplace_back(CreateBreakpoint(bp_loc));
+ }
+}
+
+//----------------------------------------------------------------------
+// "Event": {
+// "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, {
+// "type": "object",
+// "description": "Server-initiated event.",
+// "properties": {
+// "type": {
+// "type": "string",
+// "enum": [ "event" ]
+// },
+// "event": {
+// "type": "string",
+// "description": "Type of event."
+// },
+// "body": {
+// "type": [ "array", "boolean", "integer", "null", "number" ,
+// "object", "string" ],
+// "description": "Event-specific information."
+// }
+// },
+// "required": [ "type", "event" ]
+// }]
+// },
+// "ProtocolMessage": {
+// "type": "object",
+// "description": "Base class of requests, responses, and events.",
+// "properties": {
+// "seq": {
+// "type": "integer",
+// "description": "Sequence number."
+// },
+// "type": {
+// "type": "string",
+// "description": "Message type.",
+// "_enum": [ "request", "response", "event" ]
+// }
+// },
+// "required": [ "seq", "type" ]
+// }
+//----------------------------------------------------------------------
+llvm::json::Object CreateEventObject(const llvm::StringRef event_name) {
+ llvm::json::Object event;
+ event.try_emplace("seq", 0);
+ event.try_emplace("type", "event");
+ EmplaceSafeString(event, "event", event_name);
+ return event;
+}
+
+//----------------------------------------------------------------------
+// "ExceptionBreakpointsFilter": {
+// "type": "object",
+// "description": "An ExceptionBreakpointsFilter is shown in the UI as an
+// option for configuring how exceptions are dealt with.",
+// "properties": {
+// "filter": {
+// "type": "string",
+// "description": "The internal ID of the filter. This value is passed
+// to the setExceptionBreakpoints request."
+// },
+// "label": {
+// "type": "string",
+// "description": "The name of the filter. This will be shown in the UI."
+// },
+// "default": {
+// "type": "boolean",
+// "description": "Initial value of the filter. If not specified a value
+// 'false' is assumed."
+// }
+// },
+// "required": [ "filter", "label" ]
+// }
+//----------------------------------------------------------------------
+llvm::json::Value
+CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) {
+ llvm::json::Object object;
+ EmplaceSafeString(object, "filter", bp.filter);
+ EmplaceSafeString(object, "label", bp.label);
+ object.try_emplace("default", bp.default_value);
+ return llvm::json::Value(std::move(object));
+}
+
+//----------------------------------------------------------------------
+// "Source": {
+// "type": "object",
+// "description": "A Source is a descriptor for source code. It is returned
+// from the debug adapter as part of a StackFrame and it is
+// used by clients when specifying breakpoints.",
+// "properties": {
+// "name": {
+// "type": "string",
+// "description": "The short name of the source. Every source returned
+// from the debug adapter has a name. When sending a
+// source to the debug adapter this name is optional."
+// },
+// "path": {
+// "type": "string",
+// "description": "The path of the source to be shown in the UI. It is
+// only used to locate and load the content of the
+// source if no sourceReference is specified (or its
+// value is 0)."
+// },
+// "sourceReference": {
+// "type": "number",
+// "description": "If sourceReference > 0 the contents of the source must
+// be retrieved through the SourceRequest (even if a path
+// is specified). A sourceReference is only valid for a
+// session, so it must not be used to persist a source."
+// },
+// "presentationHint": {
+// "type": "string",
+// "description": "An optional hint for how to present the source in the
+// UI. A value of 'deemphasize' can be used to indicate
+// that the source is not available or that it is
+// skipped on stepping.",
+// "enum": [ "normal", "emphasize", "deemphasize" ]
+// },
+// "origin": {
+// "type": "string",
+// "description": "The (optional) origin of this source: possible values
+// 'internal module', 'inlined content from source map',
+// etc."
+// },
+// "sources": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/Source"
+// },
+// "description": "An optional list of sources that are related to this
+// source. These may be the source that generated this
+// source."
+// },
+// "adapterData": {
+// "type":["array","boolean","integer","null","number","object","string"],
+// "description": "Optional data that a debug adapter might want to loop
+// through the client. The client should leave the data
+// intact and persist it across sessions. The client
+// should not interpret the data."
+// },
+// "checksums": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/Checksum"
+// },
+// "description": "The checksums associated with this file."
+// }
+// }
+// }
+//----------------------------------------------------------------------
+llvm::json::Value CreateSource(lldb::SBLineEntry &line_entry) {
+ llvm::json::Object object;
+ lldb::SBFileSpec file = line_entry.GetFileSpec();
+ if (file.IsValid()) {
+ const char *name = file.GetFilename();
+ if (name)
+ EmplaceSafeString(object, "name", name);
+ char path[PATH_MAX] = "";
+ file.GetPath(path, sizeof(path));
+ if (path[0]) {
+ EmplaceSafeString(object, "path", std::string(path));
+ }
+ }
+ return llvm::json::Value(std::move(object));
+}
+
+llvm::json::Value CreateSource(lldb::SBFrame &frame, int64_t &disasm_line) {
+ disasm_line = 0;
+ auto line_entry = frame.GetLineEntry();
+ if (line_entry.GetFileSpec().IsValid())
+ return CreateSource(line_entry);
+
+ llvm::json::Object object;
+ const auto pc = frame.GetPC();
+
+ lldb::SBInstructionList insts;
+ lldb::SBFunction function = frame.GetFunction();
+ lldb::addr_t low_pc = LLDB_INVALID_ADDRESS;
+ if (function.IsValid()) {
+ low_pc = function.GetStartAddress().GetLoadAddress(g_vsc.target);
+ auto addr_srcref = g_vsc.addr_to_source_ref.find(low_pc);
+ if (addr_srcref != g_vsc.addr_to_source_ref.end()) {
+ // We have this disassembly cached already, return the existing
+ // sourceReference
+ object.try_emplace("sourceReference", addr_srcref->second);
+ disasm_line = g_vsc.GetLineForPC(addr_srcref->second, pc);
+ } else {
+ insts = function.GetInstructions(g_vsc.target);
+ }
+ } else {
+ lldb::SBSymbol symbol = frame.GetSymbol();
+ if (symbol.IsValid()) {
+ low_pc = symbol.GetStartAddress().GetLoadAddress(g_vsc.target);
+ auto addr_srcref = g_vsc.addr_to_source_ref.find(low_pc);
+ if (addr_srcref != g_vsc.addr_to_source_ref.end()) {
+ // We have this disassembly cached already, return the existing
+ // sourceReference
+ object.try_emplace("sourceReference", addr_srcref->second);
+ disasm_line = g_vsc.GetLineForPC(addr_srcref->second, pc);
+ } else {
+ insts = symbol.GetInstructions(g_vsc.target);
+ }
+ }
+ }
+ const auto num_insts = insts.GetSize();
+ if (low_pc != LLDB_INVALID_ADDRESS && num_insts > 0) {
+ EmplaceSafeString(object, "name", frame.GetFunctionName());
+ SourceReference source;
+ llvm::raw_string_ostream src_strm(source.content);
+ std::string line;
+ for (size_t i = 0; i < num_insts; ++i) {
+ lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
+ const auto inst_addr = inst.GetAddress().GetLoadAddress(g_vsc.target);
+ const char *m = inst.GetMnemonic(g_vsc.target);
+ const char *o = inst.GetOperands(g_vsc.target);
+ const char *c = inst.GetComment(g_vsc.target);
+ if (pc == inst_addr)
+ disasm_line = i + 1;
+ const auto inst_offset = inst_addr - low_pc;
+ int spaces = 0;
+ if (inst_offset < 10)
+ spaces = 3;
+ else if (inst_offset < 100)
+ spaces = 2;
+ else if (inst_offset < 1000)
+ spaces = 1;
+ line.clear();
+ llvm::raw_string_ostream line_strm(line);
+ line_strm << llvm::formatv("{0:X+}: <{1}> {2} {3,12} {4}", inst_addr,
+ inst_offset, llvm::fmt_repeat(' ', spaces), m,
+ o);
+
+ // If there is a comment append it starting at column 60 or after one
+ // space past the last char
+ const uint32_t comment_row = std::max(line_strm.str().size(), (size_t)60);
+ if (c && c[0]) {
+ if (line.size() < comment_row)
+ line_strm.indent(comment_row - line_strm.str().size());
+ line_strm << " # " << c;
+ }
+ src_strm << line_strm.str() << "\n";
+ source.addr_to_line[inst_addr] = i + 1;
+ }
+ // Flush the source stream
+ src_strm.str();
+ auto sourceReference = VSCode::GetNextSourceReference();
+ g_vsc.source_map[sourceReference] = std::move(source);
+ g_vsc.addr_to_source_ref[low_pc] = sourceReference;
+ object.try_emplace("sourceReference", sourceReference);
+ }
+ return llvm::json::Value(std::move(object));
+}
+
+//----------------------------------------------------------------------
+// "StackFrame": {
+// "type": "object",
+// "description": "A Stackframe contains the source location.",
+// "properties": {
+// "id": {
+// "type": "integer",
+// "description": "An identifier for the stack frame. It must be unique
+// across all threads. This id can be used to retrieve
+// the scopes of the frame with the 'scopesRequest' or
+// to restart the execution of a stackframe."
+// },
+// "name": {
+// "type": "string",
+// "description": "The name of the stack frame, typically a method name."
+// },
+// "source": {
+// "$ref": "#/definitions/Source",
+// "description": "The optional source of the frame."
+// },
+// "line": {
+// "type": "integer",
+// "description": "The line within the file of the frame. If source is
+// null or doesn't exist, line is 0 and must be ignored."
+// },
+// "column": {
+// "type": "integer",
+// "description": "The column within the line. If source is null or
+// doesn't exist, column is 0 and must be ignored."
+// },
+// "endLine": {
+// "type": "integer",
+// "description": "An optional end line of the range covered by the
+// stack frame."
+// },
+// "endColumn": {
+// "type": "integer",
+// "description": "An optional end column of the range covered by the
+// stack frame."
+// },
+// "moduleId": {
+// "type": ["integer", "string"],
+// "description": "The module associated with this frame, if any."
+// },
+// "presentationHint": {
+// "type": "string",
+// "enum": [ "normal", "label", "subtle" ],
+// "description": "An optional hint for how to present this frame in
+// the UI. A value of 'label' can be used to indicate
+// that the frame is an artificial frame that is used
+// as a visual label or separator. A value of 'subtle'
+// can be used to change the appearance of a frame in
+// a 'subtle' way."
+// }
+// },
+// "required": [ "id", "name", "line", "column" ]
+// }
+//----------------------------------------------------------------------
+llvm::json::Value CreateStackFrame(lldb::SBFrame &frame) {
+ llvm::json::Object object;
+ int64_t frame_id = MakeVSCodeFrameID(frame);
+ object.try_emplace("id", frame_id);
+ EmplaceSafeString(object, "name", frame.GetFunctionName());
+ int64_t disasm_line = 0;
+ object.try_emplace("source", CreateSource(frame, disasm_line));
+
+ auto line_entry = frame.GetLineEntry();
+ if (disasm_line > 0) {
+ object.try_emplace("line", disasm_line);
+ } else {
+ auto line = line_entry.GetLine();
+ if (line == UINT32_MAX)
+ line = 0;
+ object.try_emplace("line", line);
+ }
+ object.try_emplace("column", line_entry.GetColumn());
+ return llvm::json::Value(std::move(object));
+}
+
+//----------------------------------------------------------------------
+// "Thread": {
+// "type": "object",
+// "description": "A Thread",
+// "properties": {
+// "id": {
+// "type": "integer",
+// "description": "Unique identifier for the thread."
+// },
+// "name": {
+// "type": "string",
+// "description": "A name of the thread."
+// }
+// },
+// "required": [ "id", "name" ]
+// }
+//----------------------------------------------------------------------
+llvm::json::Value CreateThread(lldb::SBThread &thread) {
+ llvm::json::Object object;
+ object.try_emplace("id", (int64_t)thread.GetThreadID());
+ char thread_str[64];
+ snprintf(thread_str, sizeof(thread_str), "Thread #%u", thread.GetIndexID());
+ const char *name = thread.GetName();
+ if (name) {
+ std::string thread_with_name(thread_str);
+ thread_with_name += ' ';
+ thread_with_name += name;
+ EmplaceSafeString(object, "name", thread_with_name);
+ } else {
+ EmplaceSafeString(object, "name", std::string(thread_str));
+ }
+ return llvm::json::Value(std::move(object));
+}
+
+//----------------------------------------------------------------------
+// "StoppedEvent": {
+// "allOf": [ { "$ref": "#/definitions/Event" }, {
+// "type": "object",
+// "description": "Event message for 'stopped' event type. The event
+// indicates that the execution of the debuggee has stopped
+// due to some condition. This can be caused by a break
+// point previously set, a stepping action has completed,
+// by executing a debugger statement etc.",
+// "properties": {
+// "event": {
+// "type": "string",
+// "enum": [ "stopped" ]
+// },
+// "body": {
+// "type": "object",
+// "properties": {
+// "reason": {
+// "type": "string",
+// "description": "The reason for the event. For backward
+// compatibility this string is shown in the UI if
+// the 'description' attribute is missing (but it
+// must not be translated).",
+// "_enum": [ "step", "breakpoint", "exception", "pause", "entry" ]
+// },
+// "description": {
+// "type": "string",
+// "description": "The full reason for the event, e.g. 'Paused
+// on exception'. This string is shown in the UI
+// as is."
+// },
+// "threadId": {
+// "type": "integer",
+// "description": "The thread which was stopped."
+// },
+// "text": {
+// "type": "string",
+// "description": "Additional information. E.g. if reason is
+// 'exception', text contains the exception name.
+// This string is shown in the UI."
+// },
+// "allThreadsStopped": {
+// "type": "boolean",
+// "description": "If allThreadsStopped is true, a debug adapter
+// can announce that all threads have stopped.
+// The client should use this information to
+// enable that all threads can be expanded to
+// access their stacktraces. If the attribute
+// is missing or false, only the thread with the
+// given threadId can be expanded."
+// }
+// },
+// "required": [ "reason" ]
+// }
+// },
+// "required": [ "event", "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
+ uint32_t stop_id) {
+ llvm::json::Object event(CreateEventObject("stopped"));
+ llvm::json::Object body;
+ switch (thread.GetStopReason()) {
+ case lldb::eStopReasonTrace:
+ case lldb::eStopReasonPlanComplete:
+ body.try_emplace("reason", "step");
+ break;
+ case lldb::eStopReasonBreakpoint: {
+ ExceptionBreakpoint *exc_bp = g_vsc.GetExceptionBPFromStopReason(thread);
+ if (exc_bp) {
+ body.try_emplace("reason", "exception");
+ EmplaceSafeString(body, "description", exc_bp->label);
+ } else {
+ body.try_emplace("reason", "breakpoint");
+ }
+ } break;
+ case lldb::eStopReasonWatchpoint:
+ case lldb::eStopReasonInstrumentation:
+ body.try_emplace("reason", "breakpoint");
+ break;
+ case lldb::eStopReasonSignal:
+ body.try_emplace("reason", "exception");
+ break;
+ case lldb::eStopReasonException:
+ body.try_emplace("reason", "exception");
+ break;
+ case lldb::eStopReasonExec:
+ body.try_emplace("reason", "entry");
+ break;
+ case lldb::eStopReasonThreadExiting:
+ case lldb::eStopReasonInvalid:
+ case lldb::eStopReasonNone:
+ break;
+ }
+ if (stop_id == 0)
+ body.try_emplace("reason", "entry");
+ const lldb::tid_t tid = thread.GetThreadID();
+ body.try_emplace("threadId", (int64_t)tid);
+ // If no description has been set, then set it to the default thread stopped
+ // description. If we have breakpoints that get hit and shouldn't be reported
+ // as breakpoints, then they will set the description above.
+ if (ObjectContainsKey(body, "description")) {
+ char description[1024];
+ if (thread.GetStopDescription(description, sizeof(description))) {
+ EmplaceSafeString(body, "description", std::string(description));
+ }
+ }
+ if (tid == g_vsc.focus_tid) {
+ body.try_emplace("threadCausedFocus", true);
+ }
+ body.try_emplace("preserveFocusHint", tid != g_vsc.focus_tid);
+ body.try_emplace("allThreadsStopped", true);
+ event.try_emplace("body", std::move(body));
+ return llvm::json::Value(std::move(event));
+}
+
+//----------------------------------------------------------------------
+// "Variable": {
+// "type": "object",
+// "description": "A Variable is a name/value pair. Optionally a variable
+// can have a 'type' that is shown if space permits or when
+// hovering over the variable's name. An optional 'kind' is
+// used to render additional properties of the variable,
+// e.g. different icons can be used to indicate that a
+// variable is public or private. If the value is
+// structured (has children), a handle is provided to
+// retrieve the children with the VariablesRequest. If
+// the number of named or indexed children is large, the
+// numbers should be returned via the optional
+// 'namedVariables' and 'indexedVariables' attributes. The
+// client can use this optional information to present the
+// children in a paged UI and fetch them in chunks.",
+// "properties": {
+// "name": {
+// "type": "string",
+// "description": "The variable's name."
+// },
+// "value": {
+// "type": "string",
+// "description": "The variable's value. This can be a multi-line text,
+// e.g. for a function the body of a function."
+// },
+// "type": {
+// "type": "string",
+// "description": "The type of the variable's value. Typically shown in
+// the UI when hovering over the value."
+// },
+// "presentationHint": {
+// "$ref": "#/definitions/VariablePresentationHint",
+// "description": "Properties of a variable that can be used to determine
+// how to render the variable in the UI."
+// },
+// "evaluateName": {
+// "type": "string",
+// "description": "Optional evaluatable name of this variable which can
+// be passed to the 'EvaluateRequest' to fetch the
+// variable's value."
+// },
+// "variablesReference": {
+// "type": "integer",
+// "description": "If variablesReference is > 0, the variable is
+// structured and its children can be retrieved by
+// passing variablesReference to the VariablesRequest."
+// },
+// "namedVariables": {
+// "type": "integer",
+// "description": "The number of named child variables. The client can
+// use this optional information to present the children
+// in a paged UI and fetch them in chunks."
+// },
+// "indexedVariables": {
+// "type": "integer",
+// "description": "The number of indexed child variables. The client
+// can use this optional information to present the
+// children in a paged UI and fetch them in chunks."
+// }
+// },
+// "required": [ "name", "value", "variablesReference" ]
+// }
+//----------------------------------------------------------------------
+llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
+ int64_t varID, bool format_hex) {
+ llvm::json::Object object;
+ auto name = v.GetName();
+ EmplaceSafeString(object, "name", name ? name : "<null>");
+ if (format_hex)
+ v.SetFormat(lldb::eFormatHex);
+ SetValueForKey(v, object, "value");
+ auto type_cstr = v.GetType().GetDisplayTypeName();
+ EmplaceSafeString(object, "type", type_cstr ? type_cstr : NO_TYPENAME);
+ if (varID != INT64_MAX)
+ object.try_emplace("id", varID);
+ if (v.MightHaveChildren())
+ object.try_emplace("variablesReference", variablesReference);
+ else
+ object.try_emplace("variablesReference", (int64_t)0);
+ lldb::SBStream evaluateStream;
+ v.GetExpressionPath(evaluateStream);
+ const char *evaluateName = evaluateStream.GetData();
+ if (evaluateName && evaluateName[0])
+ EmplaceSafeString(object, "evaluateName", std::string(evaluateName));
+ return llvm::json::Value(std::move(object));
+}
+
+} // namespace lldb_vscode
+
diff --git a/tools/lldb-vscode/JSONUtils.h b/tools/lldb-vscode/JSONUtils.h
new file mode 100644
index 000000000000..0ca000ce9385
--- /dev/null
+++ b/tools/lldb-vscode/JSONUtils.h
@@ -0,0 +1,438 @@
+//===-- JSONUtils.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDBVSCODE_JSONUTILS_H_
+#define LLDBVSCODE_JSONUTILS_H_
+
+#include <stdint.h>
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/JSON.h"
+#include "VSCodeForward.h"
+
+namespace lldb_vscode {
+
+//------------------------------------------------------------------
+/// Emplace a StringRef in a json::Object after enusring that the
+/// string is valid UTF8. If not, first call llvm::json::fixUTF8
+/// before emplacing.
+///
+/// @param[in] obj
+/// A JSON object that we will attempt to emplace the value in
+///
+/// @param[in] key
+/// The key to use when emplacing the value
+///
+/// @param[in] str
+/// The string to emplace
+//------------------------------------------------------------------
+void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
+ llvm::StringRef str);
+
+//------------------------------------------------------------------
+/// Extract simple values as a string.
+///
+/// @param[in] value
+/// A JSON value to extract the string from.
+///
+/// @return
+/// A llvm::StringRef that contains the string value, or an empty
+/// string if \a value isn't a string.
+//------------------------------------------------------------------
+llvm::StringRef GetAsString(const llvm::json::Value &value);
+
+//------------------------------------------------------------------
+/// Extract the string value for the specified key from the
+/// specified object.
+///
+/// @param[in] obj
+/// A JSON object that we will attempt to extract the value from
+///
+/// @param[in] key
+/// The key to use when extracting the value
+///
+/// @return
+/// A llvm::StringRef that contains the string value for the
+/// specified \a key, or an empty string if there is no key that
+/// matches or if the value is not a string.
+//------------------------------------------------------------------
+llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key);
+llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key);
+
+//------------------------------------------------------------------
+/// Extract the unsigned integer value for the specified key from
+/// the specified object.
+///
+/// @param[in] obj
+/// A JSON object that we will attempt to extract the value from
+///
+/// @param[in] key
+/// The key to use when extracting the value
+///
+/// @return
+/// The unsigned integer value for the specified \a key, or
+/// \a fail_value if there is no key that matches or if the
+/// value is not an integer.
+//------------------------------------------------------------------
+uint64_t GetUnsigned(const llvm::json::Object &obj, llvm::StringRef key,
+ uint64_t fail_value);
+uint64_t GetUnsigned(const llvm::json::Object *obj, llvm::StringRef key,
+ uint64_t fail_value);
+
+//------------------------------------------------------------------
+/// Extract the boolean value for the specified key from the
+/// specified object.
+///
+/// @param[in] obj
+/// A JSON object that we will attempt to extract the value from
+///
+/// @param[in] key
+/// The key to use when extracting the value
+///
+/// @return
+/// The boolean value for the specified \a key, or \a fail_value
+/// if there is no key that matches or if the value is not a
+/// boolean value of an integer.
+//------------------------------------------------------------------
+bool GetBoolean(const llvm::json::Object &obj, llvm::StringRef key,
+ bool fail_value);
+bool GetBoolean(const llvm::json::Object *obj, llvm::StringRef key,
+ bool fail_value);
+
+//------------------------------------------------------------------
+/// Extract the signed integer for the specified key from the
+/// specified object.
+///
+/// @param[in] obj
+/// A JSON object that we will attempt to extract the value from
+///
+/// @param[in] key
+/// The key to use when extracting the value
+///
+/// @return
+/// The signed integer value for the specified \a key, or
+/// \a fail_value if there is no key that matches or if the
+/// value is not an integer.
+//------------------------------------------------------------------
+int64_t GetSigned(const llvm::json::Object &obj, llvm::StringRef key,
+ int64_t fail_value);
+int64_t GetSigned(const llvm::json::Object *obj, llvm::StringRef key,
+ int64_t fail_value);
+
+//------------------------------------------------------------------
+/// Check if the specified key exists in the specified object.
+///
+/// @param[in] obj
+/// A JSON object that we will attempt to extract the value from
+///
+/// @param[in] key
+/// The key to check for
+///
+/// @return
+/// \b True if the key exists in the \a obj, \b False otherwise.
+//------------------------------------------------------------------
+bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key);
+
+//------------------------------------------------------------------
+/// Extract an array of strings for the specified key from an object.
+///
+/// String values in the array will be extracted without any quotes
+/// around them. Numbers and Booleans will be converted into
+/// strings. Any NULL, array or objects values in the array will be
+/// ignored.
+///
+/// @param[in] obj
+/// A JSON object that we will attempt to extract the array from
+///
+/// @param[in] key
+/// The key to use when extracting the value
+///
+/// @return
+/// An array of string values for the specified \a key, or
+/// \a fail_value if there is no key that matches or if the
+/// value is not an array or all items in the array are not
+/// strings, numbers or booleans.
+//------------------------------------------------------------------
+std::vector<std::string> GetStrings(const llvm::json::Object *obj,
+ llvm::StringRef key);
+
+//------------------------------------------------------------------
+/// Fill a response object given the request object.
+///
+/// The \a response object will get its "type" set to "response",
+/// the "seq" set to zero, "response_seq" set to the "seq" value from
+/// \a request, "command" set to the "command" from \a request,
+/// and "success" set to true.
+///
+/// @param[in] request
+/// The request object received from a call to VSCode::ReadJSON().
+///
+/// @param[in,out] response
+/// An empty llvm::json::Object object that will be filled
+/// in as noted in description.
+//------------------------------------------------------------------
+void FillResponse(const llvm::json::Object &request,
+ llvm::json::Object &response);
+
+//----------------------------------------------------------------------
+/// Emplace the string value from an SBValue into the supplied object
+/// using \a key as the key that will contain the value.
+///
+/// The value is what we will display in VS Code. Some SBValue objects
+/// can have a value and/or a summary. If a value has both, we
+/// combine the value and the summary into one string. If we only have a
+/// value or summary, then that is considered the value. If there is
+/// no value and no summary then the value is the type name followed by
+/// the address of the type if it has an address.
+///
+///
+/// @param[in] v
+/// A lldb::SBValue object to extract the string value from
+///
+///
+/// @param[in] object
+/// The object to place the value object into
+///
+///
+/// @param[in] key
+/// The key name to use when inserting the value object we create
+//----------------------------------------------------------------------
+void SetValueForKey(lldb::SBValue &v, llvm::json::Object &object,
+ llvm::StringRef key);
+
+//----------------------------------------------------------------------
+/// Converts \a bp to a JSON value and appends all locations to the
+/// \a breakpoints array.
+///
+/// @param[in] bp
+/// A LLDB breakpoint object which will get all locations extracted
+/// and converted into a JSON objects in the \a breakpoints array
+///
+/// @param[in] breakpoints
+/// A JSON array that will get a llvm::json::Value for \a bp
+/// appended to it.
+//----------------------------------------------------------------------
+void AppendBreakpoint(lldb::SBBreakpoint &bp, llvm::json::Array &breakpoints);
+
+//----------------------------------------------------------------------
+/// Converts breakpoint location to a Visual Studio Code "Breakpoint"
+/// JSON object and appends it to the \a breakpoints array.
+///
+/// @param[in] bp_loc
+/// A LLDB breakpoint location object to convert into a JSON value
+///
+/// @return
+/// A "Breakpoint" JSON object with that follows the formal JSON
+/// definition outlined by Microsoft.
+//----------------------------------------------------------------------
+llvm::json::Value CreateBreakpoint(lldb::SBBreakpointLocation &bp_loc);
+
+//----------------------------------------------------------------------
+/// Create a "Event" JSON object using \a event_name as the event name
+///
+/// @param[in] event_name
+/// The string value to use for the "event" key in the JSON object.
+///
+/// @return
+/// A "Event" JSON object with that follows the formal JSON
+/// definition outlined by Microsoft.
+//----------------------------------------------------------------------
+llvm::json::Object CreateEventObject(const llvm::StringRef event_name);
+
+//----------------------------------------------------------------------
+/// Create a "ExceptionBreakpointsFilter" JSON object as described in
+/// the Visual Studio Code debug adaptor definition.
+///
+/// @param[in] bp
+/// The exception breakppoint object to use
+///
+/// @return
+/// A "ExceptionBreakpointsFilter" JSON object with that follows
+/// the formal JSON definition outlined by Microsoft.
+//----------------------------------------------------------------------
+llvm::json::Value
+CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp);
+
+//----------------------------------------------------------------------
+/// Create a "Scope" JSON object as described in the Visual Studio Code
+/// debug adaptor definition.
+///
+/// @param[in] name
+/// The value to place into the "name" key
+//
+/// @param[in] variablesReference
+/// The value to place into the "variablesReference" key
+//
+/// @param[in] namedVariables
+/// The value to place into the "namedVariables" key
+//
+/// @param[in] expensive
+/// The value to place into the "expensive" key
+///
+/// @return
+/// A "Scope" JSON object with that follows the formal JSON
+/// definition outlined by Microsoft.
+//----------------------------------------------------------------------
+llvm::json::Value CreateScope(const llvm::StringRef name,
+ int64_t variablesReference,
+ int64_t namedVariables, bool expensive);
+
+//----------------------------------------------------------------------
+/// Create a "Source" JSON object as described in the Visual Studio Code
+/// debug adaptor definition.
+///
+/// @param[in] line_entry
+/// The LLDB line table to use when populating out the "Source"
+/// object
+///
+/// @return
+/// A "Source" JSON object with that follows the formal JSON
+/// definition outlined by Microsoft.
+//----------------------------------------------------------------------
+llvm::json::Value CreateSource(lldb::SBLineEntry &line_entry);
+
+//----------------------------------------------------------------------
+/// Create a "Source" object for a given frame.
+///
+/// When there is no source file information for a stack frame, we will
+/// create disassembly for a function and store a permanent
+/// "sourceReference" that contains the textual disassembly for a
+/// function along with address to line information. The "Source" object
+/// that is created will contain a "sourceReference" that the VSCode
+/// protocol can later fetch as text in order to display disassembly.
+/// The PC will be extracted from the frame and the disassembly line
+/// within the source referred to by "sourceReference" will be filled
+/// in.
+///
+/// @param[in] frame
+/// The LLDB stack frame to use when populating out the "Source"
+/// object.
+///
+/// @param[out] disasm_line
+/// The line within the "sourceReference" file that the PC from
+/// \a frame matches.
+///
+/// @return
+/// A "Source" JSON object with that follows the formal JSON
+/// definition outlined by Microsoft.
+//----------------------------------------------------------------------
+llvm::json::Value CreateSource(lldb::SBFrame &frame, int64_t &disasm_line);
+
+//----------------------------------------------------------------------
+/// Create a "StackFrame" object for a LLDB frame object.
+///
+/// This function will fill in the following keys in the returned
+/// object:
+/// "id" - the stack frame ID as an integer
+/// "name" - the function name as a string
+/// "source" - source file information as a "Source" VSCode object
+/// "line" - the source file line number as an integer
+/// "column" - the source file column number as an integer
+///
+/// @param[in] frame
+/// The LLDB stack frame to use when populating out the "StackFrame"
+/// object.
+///
+/// @return
+/// A "StackFrame" JSON object with that follows the formal JSON
+/// definition outlined by Microsoft.
+//----------------------------------------------------------------------
+llvm::json::Value CreateStackFrame(lldb::SBFrame &frame);
+
+//----------------------------------------------------------------------
+/// Create a "Thread" object for a LLDB thread object.
+///
+/// This function will fill in the following keys in the returned
+/// object:
+/// "id" - the thread ID as an integer
+/// "name" - the thread name as a string which combines the LLDB
+/// thread index ID along with the string name of the thread
+/// from the OS if it has a name.
+///
+/// @param[in] thread
+/// The LLDB thread to use when populating out the "Thread"
+/// object.
+///
+/// @return
+/// A "Thread" JSON object with that follows the formal JSON
+/// definition outlined by Microsoft.
+//----------------------------------------------------------------------
+llvm::json::Value CreateThread(lldb::SBThread &thread);
+
+//----------------------------------------------------------------------
+/// Create a "StoppedEvent" object for a LLDB thread object.
+///
+/// This function will fill in the following keys in the returned
+/// object's "body" object:
+/// "reason" - With a valid stop reason enumeration string value
+/// that Microsoft specifies
+/// "threadId" - The thread ID as an integer
+/// "description" - a stop description (like "breakpoint 12.3") as a
+/// string
+/// "preserveFocusHint" - a boolean value that states if this thread
+/// should keep the focus in the GUI.
+/// "allThreadsStopped" - set to True to indicate that all threads
+/// stop when any thread stops.
+///
+/// @param[in] thread
+/// The LLDB thread to use when populating out the "StoppedEvent"
+/// object.
+///
+/// @return
+/// A "StoppedEvent" JSON object with that follows the formal JSON
+/// definition outlined by Microsoft.
+//----------------------------------------------------------------------
+llvm::json::Value CreateThreadStopped(lldb::SBThread &thread, uint32_t stop_id);
+
+//----------------------------------------------------------------------
+/// Create a "Variable" object for a LLDB thread object.
+///
+/// This function will fill in the following keys in the returned
+/// object:
+/// "name" - the name of the variable
+/// "value" - the value of the variable as a string
+/// "type" - the typename of the variable as a string
+/// "id" - a unique identifier for a value in case there are multiple
+/// variables with the same name. Other parts of the VSCode
+/// protocol refer to values by name so this can help
+/// disambiguate such cases if a IDE passes this "id" value
+/// back down.
+/// "variablesReference" - Zero if the variable has no children,
+/// non-zero integer otherwise which can be used to expand
+/// the variable.
+/// "evaluateName" - The name of the variable to use in expressions
+/// as a string.
+///
+/// @param[in] v
+/// The LLDB value to use when populating out the "Variable"
+/// object.
+///
+/// @param[in] variablesReference
+/// The variable reference. Zero if this value isn't structured
+/// and has no children, non-zero if it does have children and
+/// might be asked to expand itself.
+///
+/// @param[in] varID
+/// A unique variable identifier to help in properly identifying
+/// variables with the same name. This is an extension to the
+/// VS protocol.
+///
+/// @param[in] format_hex
+/// It set to true the variable will be formatted as hex in
+/// the "value" key value pair for the value of the variable.
+///
+/// @return
+/// A "Variable" JSON object with that follows the formal JSON
+/// definition outlined by Microsoft.
+//----------------------------------------------------------------------
+llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
+ int64_t varID, bool format_hex);
+
+} // namespace lldb_vscode
+
+#endif
diff --git a/tools/lldb-vscode/LLDBUtils.cpp b/tools/lldb-vscode/LLDBUtils.cpp
new file mode 100644
index 000000000000..9653522a2d3a
--- /dev/null
+++ b/tools/lldb-vscode/LLDBUtils.cpp
@@ -0,0 +1,98 @@
+//===-- LLDBUtils.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LLDBUtils.h"
+#include "VSCode.h"
+
+namespace lldb_vscode {
+
+void RunLLDBCommands(llvm::StringRef prefix,
+ const llvm::ArrayRef<std::string> &commands,
+ llvm::raw_ostream &strm) {
+ if (commands.empty())
+ return;
+ lldb::SBCommandInterpreter interp = g_vsc.debugger.GetCommandInterpreter();
+ if (!prefix.empty())
+ strm << prefix << "\n";
+ for (const auto &command : commands) {
+ lldb::SBCommandReturnObject result;
+ strm << "(lldb) " << command << "\n";
+ interp.HandleCommand(command.c_str(), result);
+ auto output_len = result.GetOutputSize();
+ if (output_len) {
+ const char *output = result.GetOutput();
+ strm << output;
+ }
+ auto error_len = result.GetErrorSize();
+ if (error_len) {
+ const char *error = result.GetError();
+ strm << error;
+ }
+ }
+}
+
+std::string RunLLDBCommands(llvm::StringRef prefix,
+ const llvm::ArrayRef<std::string> &commands) {
+ std::string s;
+ llvm::raw_string_ostream strm(s);
+ RunLLDBCommands(prefix, commands, strm);
+ strm.flush();
+ return s;
+}
+
+bool ThreadHasStopReason(lldb::SBThread &thread) {
+ switch (thread.GetStopReason()) {
+ case lldb::eStopReasonTrace:
+ case lldb::eStopReasonPlanComplete:
+ case lldb::eStopReasonBreakpoint:
+ case lldb::eStopReasonWatchpoint:
+ case lldb::eStopReasonInstrumentation:
+ case lldb::eStopReasonSignal:
+ case lldb::eStopReasonException:
+ case lldb::eStopReasonExec:
+ return true;
+ case lldb::eStopReasonThreadExiting:
+ case lldb::eStopReasonInvalid:
+ case lldb::eStopReasonNone:
+ break;
+ }
+ return false;
+}
+
+static uint32_t constexpr THREAD_INDEX_SHIFT = 19;
+
+uint32_t GetLLDBThreadIndexID(uint64_t dap_frame_id) {
+ return dap_frame_id >> THREAD_INDEX_SHIFT;
+}
+
+uint32_t GetLLDBFrameID(uint64_t dap_frame_id) {
+ return dap_frame_id & ((1u << THREAD_INDEX_SHIFT) - 1);
+}
+
+int64_t MakeVSCodeFrameID(lldb::SBFrame &frame) {
+ return (int64_t)(frame.GetThread().GetIndexID() << THREAD_INDEX_SHIFT |
+ frame.GetFrameID());
+}
+
+static uint32_t constexpr BREAKPOINT_ID_SHIFT = 22;
+
+uint32_t GetLLDBBreakpointID(uint64_t dap_breakpoint_id) {
+ return dap_breakpoint_id >> BREAKPOINT_ID_SHIFT;
+}
+
+uint32_t GetLLDBBreakpointLocationID(uint64_t dap_breakpoint_id) {
+ return dap_breakpoint_id & ((1u << BREAKPOINT_ID_SHIFT) - 1);
+}
+
+int64_t MakeVSCodeBreakpointID(lldb::SBBreakpointLocation &bp_loc) {
+ return (int64_t)(bp_loc.GetBreakpoint().GetID() << BREAKPOINT_ID_SHIFT |
+ bp_loc.GetID());
+}
+
+} // namespace lldb_vscode
diff --git a/tools/lldb-vscode/LLDBUtils.h b/tools/lldb-vscode/LLDBUtils.h
new file mode 100644
index 000000000000..96ebb85f14b1
--- /dev/null
+++ b/tools/lldb-vscode/LLDBUtils.h
@@ -0,0 +1,170 @@
+//===-- LLDBUtils.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDBVSCODE_LLDBUTILS_H_
+#define LLDBVSCODE_LLDBUTILS_H_
+
+#include "VSCodeForward.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <vector>
+
+namespace lldb_vscode {
+
+///----------------------------------------------------------------------
+/// Run a list of LLDB commands in the LLDB command interpreter.
+///
+/// All output from every command, including the prompt + the command
+/// is placed into the "strm" argument.
+///
+/// @param[in] prefix
+/// A string that will be printed into \a strm prior to emitting
+/// the prompt + command and command output. Can be NULL.
+///
+/// @param[in] commands
+/// An array of LLDB commands to execute.
+///
+/// @param[in] strm
+/// The stream that will receive the prefix, prompt + command and
+/// all command output.
+//----------------------------------------------------------------------
+void RunLLDBCommands(llvm::StringRef prefix,
+ const llvm::ArrayRef<std::string> &commands,
+ llvm::raw_ostream &strm);
+
+///----------------------------------------------------------------------
+/// Run a list of LLDB commands in the LLDB command interpreter.
+///
+/// All output from every command, including the prompt + the command
+/// is returned in the std::string return value.
+///
+/// @param[in] prefix
+/// A string that will be printed into \a strm prior to emitting
+/// the prompt + command and command output. Can be NULL.
+///
+/// @param[in] commands
+/// An array of LLDB commands to execute.
+///
+/// @return
+/// A std::string that contains the prefix and all commands and
+/// command output
+//----------------------------------------------------------------------
+std::string RunLLDBCommands(llvm::StringRef prefix,
+ const llvm::ArrayRef<std::string> &commands);
+
+///----------------------------------------------------------------------
+/// Check if a thread has a stop reason.
+///
+/// @param[in] thread
+/// The LLDB thread object to check
+///
+/// @return
+/// \b True if the thread has a valid stop reason, \b false
+/// otherwise.
+//----------------------------------------------------------------------
+bool ThreadHasStopReason(lldb::SBThread &thread);
+
+///----------------------------------------------------------------------
+/// Given a LLDB frame, make a frame ID that is unique to a specific
+/// thread and frame.
+///
+/// VSCode requires a Stackframe "id" to be unique, so we use the frame
+/// index in the lower 32 bits and the thread index ID in the upper 32
+/// bits.
+///
+/// @param[in] frame
+/// The LLDB stack frame object generate the ID for
+///
+/// @return
+/// A unique integer that allows us to easily find the right
+/// stack frame within a thread on subsequent VS code requests.
+//----------------------------------------------------------------------
+int64_t MakeVSCodeFrameID(lldb::SBFrame &frame);
+
+///----------------------------------------------------------------------
+/// Given a VSCode frame ID, convert to a LLDB thread index id.
+///
+/// VSCode requires a Stackframe "id" to be unique, so we use the frame
+/// index in the lower THREAD_INDEX_SHIFT bits and the thread index ID in
+/// the upper 32 - THREAD_INDEX_SHIFT bits.
+///
+/// @param[in] dap_frame_id
+/// The VSCode frame ID to convert to a thread index ID.
+///
+/// @return
+/// The LLDB thread index ID.
+//----------------------------------------------------------------------
+uint32_t GetLLDBThreadIndexID(uint64_t dap_frame_id);
+
+///----------------------------------------------------------------------
+/// Given a VSCode frame ID, convert to a LLDB frame ID.
+///
+/// VSCode requires a Stackframe "id" to be unique, so we use the frame
+/// index in the lower THREAD_INDEX_SHIFT bits and the thread index ID in
+/// the upper 32 - THREAD_INDEX_SHIFT bits.
+///
+/// @param[in] dap_frame_id
+/// The VSCode frame ID to convert to a frame ID.
+///
+/// @return
+/// The LLDB frame index ID.
+//----------------------------------------------------------------------
+uint32_t GetLLDBFrameID(uint64_t dap_frame_id);
+
+///----------------------------------------------------------------------
+/// Given a LLDB breakpoint, make a breakpoint ID that is unique to a
+/// specific breakpoint and breakpoint location.
+///
+/// VSCode requires a Breakpoint "id" to be unique, so we use the
+/// breakpoint ID in the lower BREAKPOINT_ID_SHIFT bits and the
+/// breakpoint location ID in the upper BREAKPOINT_ID_SHIFT bits.
+///
+/// @param[in] frame
+/// The LLDB stack frame object generate the ID for
+///
+/// @return
+/// A unique integer that allows us to easily find the right
+/// stack frame within a thread on subsequent VS code requests.
+//----------------------------------------------------------------------
+int64_t MakeVSCodeBreakpointID(lldb::SBBreakpointLocation &bp_loc);
+
+///----------------------------------------------------------------------
+/// Given a VSCode breakpoint ID, convert to a LLDB breakpoint ID.
+///
+/// VSCode requires a Breakpoint "id" to be unique, so we use the
+/// breakpoint ID in the lower BREAKPOINT_ID_SHIFT bits and the
+/// breakpoint location ID in the upper BREAKPOINT_ID_SHIFT bits.
+///
+/// @param[in] dap_breakpoint_id
+/// The VSCode breakpoint ID to convert to an LLDB breakpoint ID.
+///
+/// @return
+/// The LLDB breakpoint ID.
+//----------------------------------------------------------------------
+uint32_t GetLLDBBreakpointID(uint64_t dap_breakpoint_id);
+
+///----------------------------------------------------------------------
+/// Given a VSCode breakpoint ID, convert to a LLDB breakpoint location ID.
+///
+/// VSCode requires a Breakpoint "id" to be unique, so we use the
+/// breakpoint ID in the lower BREAKPOINT_ID_SHIFT bits and the
+/// breakpoint location ID in the upper BREAKPOINT_ID_SHIFT bits.
+///
+/// @param[in] dap_breakpoint_id
+/// The VSCode frame ID to convert to a breakpoint location ID.
+///
+/// @return
+/// The LLDB breakpoint location ID.
+//----------------------------------------------------------------------
+uint32_t GetLLDBBreakpointLocationID(uint64_t dap_breakpoint_id);
+} // namespace lldb_vscode
+
+#endif
diff --git a/tools/lldb-vscode/README.md b/tools/lldb-vscode/README.md
new file mode 100644
index 000000000000..2294659fc294
--- /dev/null
+++ b/tools/lldb-vscode/README.md
@@ -0,0 +1,195 @@
+
+# Table of Contents
+
+- [Introduction](#Introduction)
+- [Installation](#Installation-Visual-Studio-Code)
+- [Configurations](#configurations)
+ - [Launch Configuration Settings](#launch-configuration-settings)
+ - [Attach Configuration Settings](#attach-configuration-settings)
+ - [Example configurations](#example-configurations)
+ - [Launching](#launching)
+ - [Attach to process using process ID](#attach-using-pid)
+ - [Attach to process by name](#attach-by-name)
+ - [Loading a core file](#loading-a-core-file)
+
+# Introduction
+
+The `lldb-vscode` tool creates a command line tool that implements the [Visual
+Studio Code Debug API](https://code.visualstudio.com/docs/extensionAPI/api-debugging).
+It can be installed as an extension for the Visual Studio Code and Nuclide IDE.
+The protocol is easy to run remotely and also can allow other tools and IDEs to
+get a full featured debugger with a well defined protocol.
+
+# Installation for Visual Studio Code
+
+Installing the plug-in involves creating a directory in the `~/.vscode/extensions` folder and copying the package.json file that is in the same directory as this
+documentation into it, and copying to symlinking a lldb-vscode binary into
+the `bin` directory inside the plug-in directory.
+
+If you want to make a stand alone plug-in that you can send to others on unix systems:
+
+```
+$ mkdir -p ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
+$ cp package.json ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0
+$ cd ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
+$ cp /path/to/a/built/lldb-vscode .
+$ cp /path/to/a/built/liblldb.so .
+```
+
+
+If you want to make a stand alone plug-in that you can send to others on macOS systems:
+
+```
+$ mkdir -p ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
+$ cp package.json ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0
+$ cd ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
+$ cp /path/to/a/built/lldb-vscode .
+$ rsync -av /path/to/a/built/LLDB.framework LLDB.framework
+```
+
+You might need to create additional directories for the `liblldb.so` or `LLDB.framework` inside or next to the `bin` folder depending on how the [rpath](https://en.wikipedia.org/wiki/Rpath) is set in your `lldb-vscode` binary. By default the `Debug` builds of LLDB usually includes
+the current executable directory in the rpath, so these steps should work for most people.
+
+To create a plug-in that symlinks into your `lldb-vscode` in your build directory:
+
+```
+$ mkdir -p ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
+$ cp package.json ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0
+$ cd ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
+$ ln -s /path/to/a/built/lldb-vscode
+```
+
+This is handy if you want to debug and develope the `lldb-vscode` executable when adding features or fixing bugs.
+
+# Configurations
+
+Launching to attaching require you to create a [launch configuration](https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations). This file
+defines arguments that get passed to `lldb-vscode` and the configuration settings
+control how the launch or attach happens.
+
+## Launch Configuration Settings
+
+When you launch a program with Visual Studio Code you will need to create a [launch.json](https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations)
+file that defines how your program will be run. The JSON configuration file can contain the following `lldb-vscode` specific launch key/value pairs:
+
+|parameter |type|req | |
+|-------------------|----|:--:|---------|
+|**name** |string|Y| A configuration name that will be displayed in the IDE.
+|**type** |string|Y| Must be "lldb-vscode".
+|**request** |string|Y| Must be "launch".
+|**program** |string|Y| Path to the executable to launch.
+|**args** |[string]|| An array of command line argument strings to be passed to the program being launched.
+|**cwd** |string| | The program working directory.
+|**env** |dictionary| | Environment variables to set when launching the program. The format of each environment variable string is "VAR=VALUE" for environment variables with values or just "VAR" for environment variables with no values.
+|**stopOnEntry** |boolean| | Whether to stop program immediately after launching.
+|**initCommands** |[string]| | LLDB commands executed upon debugger startup prior to creating the LLDB target. Commands and command output will be sent to the debugger console when they are executed.
+|**preRunCommands** |[string]| | LLDB commands executed just before launching after the LLDB target has been created. Commands and command output will be sent to the debugger console when they are executed.
+|**stopCommands** |[string]| | LLDB commands executed just after each stop. Commands and command output will be sent to the debugger console when they are executed.
+|**exitCommands** |[string]| | LLDB commands executed when the program exits. Commands and command output will be sent to the debugger console when they are executed.
+|**sourceMap** |[string[2]]| | Specify an array of path re-mappings. Each element in the array must be a two element array containing a source and destination pathname.
+|**debuggerRoot** | string| |Specify a working directory to use when launching lldb-vscode. If the debug information in your executable contains relative paths, this option can be used so that `lldb-vscode` can find source files and object files that have relative paths.
+
+## Attaching Settings
+
+When attaching to a process using LLDB you can attach in a few ways
+
+1. Attach to an existing process using the process ID
+2. Attach to an existing process by name
+3. Attach by name by waiting for the next instance of a process to launch
+
+The JSON configuration file can contain the following `lldb-vscode` specific launch key/value pairs:
+
+|parameter |type |req | |
+|-------------------|--------|:--:|---------|
+|**name** |string |Y| A configuration name that will be displayed in the IDE.
+|**type** |string |Y| Must be "lldb-vscode".
+|**request** |string |Y| Must be "attach".
+|**program** |string | | Path to the executable to attach to. This value is optional but can help to resolve breakpoints prior the attaching to the program.
+|**pid** |number | | The process id of the process you wish to attach to. If **pid** is omitted, the debugger will attempt to attach to the program by finding a process whose file name matches the file name from **porgram**. Setting this value to `${command:pickMyProcess}` will allow interactive process selection in the IDE.
+|**stopOnEntry** |boolean| | Whether to stop program immediately after launching.
+|**waitFor** |boolean | | Wait for the process to launch.
+|**initCommands** |[string]| | LLDB commands executed upon debugger startup prior to creating the LLDB target. Commands and command output will be sent to the debugger console when they are executed.
+|**preRunCommands** |[string]| | LLDB commands executed just before launching after the LLDB target has been created. Commands and command output will be sent to the debugger console when they are executed.
+|**stopCommands** |[string]| | LLDB commands executed just after each stop. Commands and command output will be sent to the debugger console when they are executed.
+|**exitCommands** |[string]| | LLDB commands executed when the program exits. Commands and command output will be sent to the debugger console when they are executed.
+|**attachCommands** |[string]| | LLDB commands that will be executed after **preRunCommands** which take place of the code that normally does the attach. The commands can create a new target and attach or launch it however desired. This allows custom launch and attach configurations. Core files can use `target create --core /path/to/core` to attach to core files.
+
+
+## Example configurations
+
+### Launching
+
+This will launch `/tmp/a.out` with arguments `one`, `two`, and `three` and
+adds `FOO=1` and `bar` to the environment:
+
+```javascript
+{
+ "type": "lldb-vscode",
+ "request": "launch",
+ "name": "Debug",
+ "program": "/tmp/a.out",
+ "args": [ "one", "two", "three" ],
+ "env": [ "FOO=1", "BAR" ],
+}
+```
+
+### Attach using PID
+
+This will attach to a process `a.out` whose process ID is 123:
+
+```javascript
+{
+ "type": "lldb-vscode",
+ "request": "attach",
+ "name": "Attach to PID",
+ "program": "/tmp/a.out",
+ "pid": 123
+}
+```
+
+### Attach by Name
+
+This will attach to an existing process whose base
+name matches `a.out`. All we have to do is leave the `pid` value out of the
+above configuration:
+
+```javascript
+{
+ "name": "Attach to Name",
+ "type": "lldb-vscode",
+ "request": "attach",
+ "program": "/tmp/a.out",
+}
+```
+
+If you want to ignore any existing a.out processes and wait for the next instance
+to be launched you can add the "waitFor" key value pair:
+
+```javascript
+{
+ "name": "Attach to Name (wait)",
+ "type": "lldb-vscode",
+ "request": "attach",
+ "program": "/tmp/a.out",
+ "waitFor": true
+}
+```
+
+This will work as long as the architecture, vendor and OS supports waiting
+for processes. Currently MacOS is the only platform that supports this.
+
+
+### Loading a Core File
+
+Loading a core file can use the `"attach"` request along with the
+`"attachCommands"` to implement a custom attach:
+
+```javascript
+{
+ "name": "Attach to Name (wait)",
+ "type": "lldb-vscode",
+ "request": "attach",
+ "attachCommands": ["target create -c /path/to/123.core /path/to/executable"],
+ "stopOnEntry": false
+}
+```
diff --git a/tools/lldb-vscode/SourceBreakpoint.cpp b/tools/lldb-vscode/SourceBreakpoint.cpp
new file mode 100644
index 000000000000..f2a286c9eca2
--- /dev/null
+++ b/tools/lldb-vscode/SourceBreakpoint.cpp
@@ -0,0 +1,27 @@
+//===-- SourceBreakpoint.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SourceBreakpoint.h"
+#include "VSCode.h"
+
+namespace lldb_vscode {
+
+SourceBreakpoint::SourceBreakpoint(const llvm::json::Object &obj)
+ : BreakpointBase(obj), line(GetUnsigned(obj, "line", 0)),
+ column(GetUnsigned(obj, "column", 0)) {}
+
+void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) {
+ bp = g_vsc.target.BreakpointCreateByLocation(source_path.str().c_str(), line);
+ if (!condition.empty())
+ SetCondition();
+ if (!hitCondition.empty())
+ SetHitCondition();
+}
+
+} // namespace lldb_vscode
diff --git a/tools/lldb-vscode/SourceBreakpoint.h b/tools/lldb-vscode/SourceBreakpoint.h
new file mode 100644
index 000000000000..8af647ca8fe5
--- /dev/null
+++ b/tools/lldb-vscode/SourceBreakpoint.h
@@ -0,0 +1,39 @@
+//===-- SourceBreakpoint.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDBVSCODE_SOURCEBREAKPOINT_H_
+#define LLDBVSCODE_SOURCEBREAKPOINT_H_
+
+#include "llvm/ADT/StringRef.h"
+#include "BreakpointBase.h"
+
+namespace lldb_vscode {
+
+struct SourceBreakpoint : public BreakpointBase {
+
+ uint32_t line; ///< The source line of the breakpoint or logpoint
+ uint32_t column; ///< An optional source column of the breakpoint
+
+ SourceBreakpoint() : BreakpointBase(), line(0), column(0) {}
+ SourceBreakpoint(const llvm::json::Object &obj);
+
+ // Set this breakpoint in LLDB as a new breakpoint
+ void SetBreakpoint(const llvm::StringRef source_path);
+};
+
+inline bool operator<(const SourceBreakpoint &lhs,
+ const SourceBreakpoint &rhs) {
+ if (lhs.line == rhs.line)
+ return lhs.column < rhs.column;
+ return lhs.line < rhs.line;
+}
+
+} // namespace lldb_vscode
+
+#endif
diff --git a/tools/lldb-vscode/SourceReference.h b/tools/lldb-vscode/SourceReference.h
new file mode 100644
index 000000000000..f047143e6c84
--- /dev/null
+++ b/tools/lldb-vscode/SourceReference.h
@@ -0,0 +1,33 @@
+//===-- SourceReference.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDBVSCODE_SOURCEREFERENCE_H_
+#define LLDBVSCODE_SOURCEREFERENCE_H_
+
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/DenseMap.h"
+#include <string>
+
+namespace lldb_vscode {
+
+struct SourceReference {
+ std::string content;
+ llvm::DenseMap<lldb::addr_t, int64_t> addr_to_line;
+
+ int64_t GetLineForPC(lldb::addr_t pc) const {
+ auto addr_line = addr_to_line.find(pc);
+ if (addr_line != addr_to_line.end())
+ return addr_line->second;
+ return 0;
+ }
+};
+
+} // namespace lldb_vscode
+
+#endif
diff --git a/tools/lldb-vscode/VSCode.cpp b/tools/lldb-vscode/VSCode.cpp
new file mode 100644
index 000000000000..0f138ec77707
--- /dev/null
+++ b/tools/lldb-vscode/VSCode.cpp
@@ -0,0 +1,349 @@
+//===-- VSCode.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdarg.h>
+#include <fstream>
+#include <mutex>
+
+#include "VSCode.h"
+#include "LLDBUtils.h"
+
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+using namespace lldb_vscode;
+
+namespace {
+ inline bool IsEmptyLine(llvm::StringRef S) {
+ return S.ltrim().empty();
+ }
+} // namespace
+
+namespace lldb_vscode {
+
+VSCode g_vsc;
+
+VSCode::VSCode()
+ : in(stdin), out(stdout), launch_info(nullptr), variables(),
+ broadcaster("lldb-vscode"), num_regs(0), num_locals(0), num_globals(0),
+ log(), exception_breakpoints(
+ {{"cpp_catch", "C++ Catch", lldb::eLanguageTypeC_plus_plus},
+ {"cpp_throw", "C++ Throw", lldb::eLanguageTypeC_plus_plus},
+ {"objc_catch", "Objective C Catch", lldb::eLanguageTypeObjC},
+ {"objc_throw", "Objective C Throw", lldb::eLanguageTypeObjC},
+ {"swift_catch", "Swift Catch", lldb::eLanguageTypeSwift},
+ {"swift_throw", "Swift Throw", lldb::eLanguageTypeSwift}}),
+ focus_tid(LLDB_INVALID_THREAD_ID), sent_terminated_event(false),
+ stop_at_entry(false) {
+ const char *log_file_path = getenv("LLDBVSCODE_LOG");
+#if defined(_WIN32)
+// Windows opens stdout and stdin in text mode which converts \n to 13,10
+// while the value is just 10 on Darwin/Linux. Setting the file mode to binary
+// fixes this.
+ assert(_setmode(fileno(stdout), _O_BINARY));
+ assert(_setmode(fileno(stdin), _O_BINARY));
+#endif
+ if (log_file_path)
+ log.reset(new std::ofstream(log_file_path));
+}
+
+VSCode::~VSCode() {
+ CloseInputStream();
+ CloseOutputStream();
+}
+
+void VSCode::CloseInputStream() {
+ if (in != stdin) {
+ fclose(in);
+ in = nullptr;
+ }
+}
+
+void VSCode::CloseOutputStream() {
+ if (out != stdout) {
+ fclose(out);
+ out = nullptr;
+ }
+}
+
+int64_t VSCode::GetLineForPC(int64_t sourceReference, lldb::addr_t pc) const {
+ auto pos = source_map.find(sourceReference);
+ if (pos != source_map.end())
+ return pos->second.GetLineForPC(pc);
+ return 0;
+}
+
+ExceptionBreakpoint *VSCode::GetExceptionBreakpoint(const std::string &filter) {
+ for (auto &bp : exception_breakpoints) {
+ if (bp.filter == filter)
+ return &bp;
+ }
+ return nullptr;
+}
+
+ExceptionBreakpoint *
+VSCode::GetExceptionBreakpoint(const lldb::break_id_t bp_id) {
+ for (auto &bp : exception_breakpoints) {
+ if (bp.bp.GetID() == bp_id)
+ return &bp;
+ }
+ return nullptr;
+}
+
+//----------------------------------------------------------------------
+// Send the JSON in "json_str" to the "out" stream. Correctly send the
+// "Content-Length:" field followed by the length, followed by the raw
+// JSON bytes.
+//----------------------------------------------------------------------
+void VSCode::SendJSON(const std::string &json_str) {
+ fprintf(out, "Content-Length: %u\r\n\r\n%s", (uint32_t)json_str.size(),
+ json_str.c_str());
+ fflush(out);
+ if (log) {
+ *log << "<-- " << std::endl
+ << "Content-Length: " << json_str.size() << "\r\n\r\n"
+ << json_str << std::endl;
+ }
+}
+
+//----------------------------------------------------------------------
+// Serialize the JSON value into a string and send the JSON packet to
+// the "out" stream.
+//----------------------------------------------------------------------
+void VSCode::SendJSON(const llvm::json::Value &json) {
+ std::string s;
+ llvm::raw_string_ostream strm(s);
+ strm << json;
+ static std::mutex mutex;
+ std::lock_guard<std::mutex> locker(mutex);
+ SendJSON(strm.str());
+}
+
+//----------------------------------------------------------------------
+// Read a JSON packet from the "in" stream.
+//----------------------------------------------------------------------
+std::string VSCode::ReadJSON() {
+ static std::string header("Content-Length: ");
+
+ uint32_t packet_len = 0;
+ std::string json_str;
+ char line[1024];
+
+ while (fgets(line, sizeof(line), in)) {
+ if (strncmp(line, header.data(), header.size()) == 0) {
+ packet_len = atoi(line + header.size());
+ if (fgets(line, sizeof(line), in)) {
+ if (!IsEmptyLine(line))
+ if (log)
+ *log << "warning: expected empty line but got: \"" << line << "\""
+ << std::endl;
+ break;
+ }
+ } else {
+ if (log)
+ *log << "warning: expected \"" << header << "\" but got: \"" << line
+ << "\"" << std::endl;
+ }
+ }
+ // This is followed by two windows newline sequences ("\r\n\r\n") so eat
+ // two the newline sequences
+ if (packet_len > 0) {
+ json_str.resize(packet_len);
+ auto bytes_read = fread(&json_str[0], 1, packet_len, in);
+ if (bytes_read < packet_len) {
+ if (log)
+ *log << "error: read fewer bytes (" << bytes_read
+ << ") than requested (" << packet_len << ")" << std::endl;
+ json_str.erase(bytes_read);
+ }
+ if (log) {
+ *log << "--> " << std::endl;
+ *log << header << packet_len << "\r\n\r\n" << json_str << std::endl;
+ }
+ }
+ return json_str;
+}
+
+//----------------------------------------------------------------------
+// "OutputEvent": {
+// "allOf": [ { "$ref": "#/definitions/Event" }, {
+// "type": "object",
+// "description": "Event message for 'output' event type. The event
+// indicates that the target has produced some output.",
+// "properties": {
+// "event": {
+// "type": "string",
+// "enum": [ "output" ]
+// },
+// "body": {
+// "type": "object",
+// "properties": {
+// "category": {
+// "type": "string",
+// "description": "The output category. If not specified,
+// 'console' is assumed.",
+// "_enum": [ "console", "stdout", "stderr", "telemetry" ]
+// },
+// "output": {
+// "type": "string",
+// "description": "The output to report."
+// },
+// "variablesReference": {
+// "type": "number",
+// "description": "If an attribute 'variablesReference' exists
+// and its value is > 0, the output contains
+// objects which can be retrieved by passing
+// variablesReference to the VariablesRequest."
+// },
+// "source": {
+// "$ref": "#/definitions/Source",
+// "description": "An optional source location where the output
+// was produced."
+// },
+// "line": {
+// "type": "integer",
+// "description": "An optional source location line where the
+// output was produced."
+// },
+// "column": {
+// "type": "integer",
+// "description": "An optional source location column where the
+// output was produced."
+// },
+// "data": {
+// "type":["array","boolean","integer","null","number","object",
+// "string"],
+// "description": "Optional data to report. For the 'telemetry'
+// category the data will be sent to telemetry, for
+// the other categories the data is shown in JSON
+// format."
+// }
+// },
+// "required": ["output"]
+// }
+// },
+// "required": [ "event", "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+void VSCode::SendOutput(OutputType o, const llvm::StringRef output) {
+ if (output.empty())
+ return;
+
+ llvm::json::Object event(CreateEventObject("output"));
+ llvm::json::Object body;
+ const char *category = nullptr;
+ switch (o) {
+ case OutputType::Console:
+ category = "console";
+ break;
+ case OutputType::Stdout:
+ category = "stdout";
+ break;
+ case OutputType::Stderr:
+ category = "stderr";
+ break;
+ case OutputType::Telemetry:
+ category = "telemetry";
+ break;
+ }
+ body.try_emplace("category", category);
+ EmplaceSafeString(body, "output", output.str());
+ event.try_emplace("body", std::move(body));
+ SendJSON(llvm::json::Value(std::move(event)));
+}
+
+void __attribute__((format(printf, 3, 4)))
+VSCode::SendFormattedOutput(OutputType o, const char *format, ...) {
+ char buffer[1024];
+ va_list args;
+ va_start(args, format);
+ int actual_length = vsnprintf(buffer, sizeof(buffer), format, args);
+ va_end(args);
+ SendOutput(o, llvm::StringRef(buffer,
+ std::min<int>(actual_length, sizeof(buffer))));
+}
+
+int64_t VSCode::GetNextSourceReference() {
+ static int64_t ref = 0;
+ return ++ref;
+}
+
+ExceptionBreakpoint *
+VSCode::GetExceptionBPFromStopReason(lldb::SBThread &thread) {
+ const auto num = thread.GetStopReasonDataCount();
+ // Check to see if have hit an exception breakpoint and change the
+ // reason to "exception", but only do so if all breakpoints that were
+ // hit are exception breakpoints.
+ ExceptionBreakpoint *exc_bp = nullptr;
+ for (size_t i = 0; i < num; i += 2) {
+ // thread.GetStopReasonDataAtIndex(i) will return the bp ID and
+ // thread.GetStopReasonDataAtIndex(i+1) will return the location
+ // within that breakpoint. We only care about the bp ID so we can
+ // see if this is an exception breakpoint that is getting hit.
+ lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i);
+ exc_bp = GetExceptionBreakpoint(bp_id);
+ // If any breakpoint is not an exception breakpoint, then stop and
+ // report this as a normal breakpoint
+ if (exc_bp == nullptr)
+ return nullptr;
+ }
+ return exc_bp;
+}
+
+lldb::SBThread VSCode::GetLLDBThread(const llvm::json::Object &arguments) {
+ auto tid = GetSigned(arguments, "threadId", LLDB_INVALID_THREAD_ID);
+ return target.GetProcess().GetThreadByID(tid);
+}
+
+lldb::SBFrame VSCode::GetLLDBFrame(const llvm::json::Object &arguments) {
+ const uint64_t frame_id = GetUnsigned(arguments, "frameId", UINT64_MAX);
+ lldb::SBProcess process = target.GetProcess();
+ // Upper 32 bits is the thread index ID
+ lldb::SBThread thread =
+ process.GetThreadByIndexID(GetLLDBThreadIndexID(frame_id));
+ // Lower 32 bits is the frame index
+ return thread.GetFrameAtIndex(GetLLDBFrameID(frame_id));
+}
+
+llvm::json::Value VSCode::CreateTopLevelScopes() {
+ llvm::json::Array scopes;
+ scopes.emplace_back(CreateScope("Locals", VARREF_LOCALS, num_locals, false));
+ scopes.emplace_back(
+ CreateScope("Globals", VARREF_GLOBALS, num_globals, false));
+ scopes.emplace_back(CreateScope("Registers", VARREF_REGS, num_regs, false));
+ return llvm::json::Value(std::move(scopes));
+}
+
+void VSCode::RunLLDBCommands(llvm::StringRef prefix,
+ const std::vector<std::string> &commands) {
+ SendOutput(OutputType::Console,
+ llvm::StringRef(::RunLLDBCommands(prefix, commands)));
+}
+
+void VSCode::RunInitCommands() {
+ RunLLDBCommands("Running initCommands:", init_commands);
+}
+
+void VSCode::RunPreRunCommands() {
+ RunLLDBCommands("Running preRunCommands:", pre_run_commands);
+}
+
+void VSCode::RunStopCommands() {
+ RunLLDBCommands("Running stopCommands:", stop_commands);
+}
+
+void VSCode::RunExitCommands() {
+ RunLLDBCommands("Running exitCommands:", exit_commands);
+}
+
+} // namespace lldb_vscode
+
diff --git a/tools/lldb-vscode/VSCode.h b/tools/lldb-vscode/VSCode.h
new file mode 100644
index 000000000000..142be3318367
--- /dev/null
+++ b/tools/lldb-vscode/VSCode.h
@@ -0,0 +1,146 @@
+//===-- VSCode.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDBVSCODE_VSCODE_H_
+#define LLDBVSCODE_VSCODE_H_
+
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <stdio.h>
+#include <thread>
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+
+#include "lldb/API/SBAttachInfo.h"
+#include "lldb/API/SBBreakpoint.h"
+#include "lldb/API/SBBreakpointLocation.h"
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBCommunication.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBHostOS.h"
+#include "lldb/API/SBInstruction.h"
+#include "lldb/API/SBInstructionList.h"
+#include "lldb/API/SBLanguageRuntime.h"
+#include "lldb/API/SBLaunchInfo.h"
+#include "lldb/API/SBLineEntry.h"
+#include "lldb/API/SBListener.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStringList.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBThread.h"
+
+#include "ExceptionBreakpoint.h"
+#include "FunctionBreakpoint.h"
+#include "SourceBreakpoint.h"
+#include "SourceReference.h"
+
+#define VARREF_LOCALS (int64_t)1
+#define VARREF_GLOBALS (int64_t)2
+#define VARREF_REGS (int64_t)3
+#define VARREF_FIRST_VAR_IDX (int64_t)4
+#define VARREF_IS_SCOPE(v) (VARREF_LOCALS <= 1 && v < VARREF_FIRST_VAR_IDX)
+#define VARIDX_TO_VARREF(i) ((i) + VARREF_FIRST_VAR_IDX)
+#define VARREF_TO_VARIDX(v) ((v)-VARREF_FIRST_VAR_IDX)
+#define NO_TYPENAME "<no-type>"
+
+namespace lldb_vscode {
+
+typedef llvm::DenseMap<uint32_t, SourceBreakpoint> SourceBreakpointMap;
+typedef llvm::StringMap<FunctionBreakpoint> FunctionBreakpointMap;
+enum class OutputType { Console, Stdout, Stderr, Telemetry };
+
+struct VSCode {
+ FILE *in;
+ FILE *out;
+ lldb::SBDebugger debugger;
+ lldb::SBTarget target;
+ lldb::SBAttachInfo attach_info;
+ lldb::SBLaunchInfo launch_info;
+ lldb::SBValueList variables;
+ lldb::SBBroadcaster broadcaster;
+ int64_t num_regs;
+ int64_t num_locals;
+ int64_t num_globals;
+ std::thread event_thread;
+ std::unique_ptr<std::ofstream> log;
+ llvm::DenseMap<lldb::addr_t, int64_t> addr_to_source_ref;
+ llvm::DenseMap<int64_t, SourceReference> source_map;
+ llvm::StringMap<SourceBreakpointMap> source_breakpoints;
+ FunctionBreakpointMap function_breakpoints;
+ std::vector<ExceptionBreakpoint> exception_breakpoints;
+ std::vector<std::string> init_commands;
+ std::vector<std::string> pre_run_commands;
+ std::vector<std::string> exit_commands;
+ std::vector<std::string> stop_commands;
+ lldb::tid_t focus_tid;
+ bool sent_terminated_event;
+ bool stop_at_entry;
+ // Keep track of the last stop thread index IDs as threads won't go away
+ // unless we send a "thread" event to indicate the thread exited.
+ llvm::DenseSet<lldb::tid_t> thread_ids;
+ VSCode();
+ ~VSCode();
+ VSCode(const VSCode &rhs) = delete;
+ void operator=(const VSCode &rhs) = delete;
+ void CloseInputStream();
+ void CloseOutputStream();
+ int64_t GetLineForPC(int64_t sourceReference, lldb::addr_t pc) const;
+ ExceptionBreakpoint *GetExceptionBreakpoint(const std::string &filter);
+ ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id);
+ //----------------------------------------------------------------------
+ // Send the JSON in "json_str" to the "out" stream. Correctly send the
+ // "Content-Length:" field followed by the length, followed by the raw
+ // JSON bytes.
+ //----------------------------------------------------------------------
+ void SendJSON(const std::string &json_str);
+
+ //----------------------------------------------------------------------
+ // Serialize the JSON value into a string and send the JSON packet to
+ // the "out" stream.
+ //----------------------------------------------------------------------
+ void SendJSON(const llvm::json::Value &json);
+
+ std::string ReadJSON();
+
+ void SendOutput(OutputType o, const llvm::StringRef output);
+
+ void __attribute__((format(printf, 3, 4)))
+ SendFormattedOutput(OutputType o, const char *format, ...);
+
+ static int64_t GetNextSourceReference();
+
+ ExceptionBreakpoint *GetExceptionBPFromStopReason(lldb::SBThread &thread);
+
+ lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments);
+
+ lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments);
+
+ llvm::json::Value CreateTopLevelScopes();
+
+ void RunLLDBCommands(llvm::StringRef prefix,
+ const std::vector<std::string> &commands);
+
+ void RunInitCommands();
+ void RunPreRunCommands();
+ void RunStopCommands();
+ void RunExitCommands();
+};
+
+extern VSCode g_vsc;
+
+} // namespace lldb_vscode
+
+#endif
diff --git a/tools/lldb-vscode/VSCodeForward.h b/tools/lldb-vscode/VSCodeForward.h
new file mode 100644
index 000000000000..d5b7f8d53f77
--- /dev/null
+++ b/tools/lldb-vscode/VSCodeForward.h
@@ -0,0 +1,47 @@
+//===-- VSCodeForward.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDBVSCODE_VSCODEFORWARD_H_
+#define LLDBVSCODE_VSCODEFORWARD_H_
+
+
+namespace lldb_vscode {
+struct BreakpointBase;
+struct ExceptionBreakpoint;
+struct FunctionBreakpoint;
+struct SourceBreakpoint;
+struct SourceReference;
+} // namespace lldb_vscode
+
+namespace lldb {
+class SBAttachInfo;
+class SBBreakpoint;
+class SBBreakpointLocation;
+class SBCommandInterpreter;
+class SBCommandReturnObject;
+class SBCommunication;
+class SBDebugger;
+class SBEvent;
+class SBFrame;
+class SBHostOS;
+class SBInstruction;
+class SBInstructionList;
+class SBLanguageRuntime;
+class SBLaunchInfo;
+class SBLineEntry;
+class SBListener;
+class SBProcess;
+class SBStream;
+class SBStringList;
+class SBTarget;
+class SBThread;
+class SBValue;
+} // namespace lldb
+
+#endif
diff --git a/tools/lldb-vscode/lldb-vscode-Info.plist b/tools/lldb-vscode/lldb-vscode-Info.plist
new file mode 100644
index 000000000000..a6b824372546
--- /dev/null
+++ b/tools/lldb-vscode/lldb-vscode-Info.plist
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.lldb-vscode</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>lldb-vscode</string>
+ <key>CFBundleVersion</key>
+ <string>360.99.0</string>
+ <key>SecTaskAccess</key>
+ <array>
+ <string>allowed</string>
+ <string>debug</string>
+ </array>
+</dict>
+</plist>
diff --git a/tools/lldb-vscode/lldb-vscode.cpp b/tools/lldb-vscode/lldb-vscode.cpp
new file mode 100644
index 000000000000..2aad7977efa0
--- /dev/null
+++ b/tools/lldb-vscode/lldb-vscode.cpp
@@ -0,0 +1,2706 @@
+//===-- lldb-vscode.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#if defined(_WIN32)
+// We need to #define NOMINMAX in order to skip `min()` and `max()` macro
+// definitions that conflict with other system headers.
+// We also need to #undef GetObject (which is defined to GetObjectW) because
+// the JSON code we use also has methods named `GetObject()` and we conflict
+// against these.
+#define NOMINMAX
+#include <windows.h>
+#undef GetObject
+#else
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
+
+#include <algorithm>
+#include <chrono>
+#include <fstream>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <sstream>
+#include <thread>
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "JSONUtils.h"
+#include "LLDBUtils.h"
+#include "VSCode.h"
+
+#if defined(_WIN32)
+#define PATH_MAX MAX_PATH
+typedef int socklen_t;
+constexpr const char *dev_null_path = "nul";
+
+#else
+typedef int SOCKET;
+constexpr const char *dev_null_path = "/dev/null";
+
+#endif
+
+using namespace lldb_vscode;
+
+namespace {
+
+typedef void (*RequestCallback)(const llvm::json::Object &command);
+
+enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch };
+
+enum VSCodeBroadcasterBits { eBroadcastBitStopEventThread = 1u << 0 };
+
+int AcceptConnection(int portno) {
+ // Accept a socket connection from any host on "portno".
+ int newsockfd = -1;
+ struct sockaddr_in serv_addr, cli_addr;
+ SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockfd < 0) {
+ if (g_vsc.log)
+ *g_vsc.log << "error: opening socket (" << strerror(errno) << ")"
+ << std::endl;
+ } else {
+ memset((char *)&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ // serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ serv_addr.sin_port = htons(portno);
+ if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
+ if (g_vsc.log)
+ *g_vsc.log << "error: binding socket (" << strerror(errno) << ")"
+ << std::endl;
+ } else {
+ listen(sockfd, 5);
+ socklen_t clilen = sizeof(cli_addr);
+ newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
+ if (newsockfd < 0)
+ if (g_vsc.log)
+ *g_vsc.log << "error: accept (" << strerror(errno) << ")"
+ << std::endl;
+ }
+#if defined(_WIN32)
+ closesocket(sockfd);
+#else
+ close(sockfd);
+#endif
+ }
+ return newsockfd;
+}
+
+std::vector<const char *> MakeArgv(const llvm::ArrayRef<std::string> &strs) {
+ // Create and return an array of "const char *", one for each C string in
+ // "strs" and terminate the list with a NULL. This can be used for argument
+ // vectors (argv) or environment vectors (envp) like those passed to the
+ // "main" function in C programs.
+ std::vector<const char *> argv;
+ for (const auto &s : strs)
+ argv.push_back(s.c_str());
+ argv.push_back(nullptr);
+ return argv;
+}
+
+//----------------------------------------------------------------------
+// Send a "exited" event to indicate the process has exited.
+//----------------------------------------------------------------------
+void SendProcessExitedEvent(lldb::SBProcess &process) {
+ llvm::json::Object event(CreateEventObject("exited"));
+ llvm::json::Object body;
+ body.try_emplace("exitCode", (int64_t)process.GetExitStatus());
+ event.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(event)));
+}
+
+void SendThreadExitedEvent(lldb::tid_t tid) {
+ llvm::json::Object event(CreateEventObject("thread"));
+ llvm::json::Object body;
+ body.try_emplace("reason", "exited");
+ body.try_emplace("threadId", (int64_t)tid);
+ event.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(event)));
+}
+
+//----------------------------------------------------------------------
+// Send a "terminated" event to indicate the process is done being
+// debugged.
+//----------------------------------------------------------------------
+void SendTerminatedEvent() {
+ if (!g_vsc.sent_terminated_event) {
+ g_vsc.sent_terminated_event = true;
+ // Send a "terminated" event
+ llvm::json::Object event(CreateEventObject("terminated"));
+ g_vsc.SendJSON(llvm::json::Value(std::move(event)));
+ }
+}
+
+//----------------------------------------------------------------------
+// Send a thread stopped event for all threads as long as the process
+// is stopped.
+//----------------------------------------------------------------------
+void SendThreadStoppedEvent() {
+ lldb::SBProcess process = g_vsc.target.GetProcess();
+ if (process.IsValid()) {
+ auto state = process.GetState();
+ if (state == lldb::eStateStopped) {
+ llvm::DenseSet<lldb::tid_t> old_thread_ids;
+ old_thread_ids.swap(g_vsc.thread_ids);
+ uint32_t stop_id = process.GetStopID();
+ const uint32_t num_threads = process.GetNumThreads();
+
+ // First make a pass through the threads to see if the focused thread
+ // has a stop reason. In case the focus thread doesn't have a stop
+ // reason, remember the first thread that has a stop reason so we can
+ // set it as the focus thread if below if needed.
+ lldb::tid_t first_tid_with_reason = LLDB_INVALID_THREAD_ID;
+ uint32_t num_threads_with_reason = 0;
+ for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
+ lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
+ const lldb::tid_t tid = thread.GetThreadID();
+ const bool has_reason = ThreadHasStopReason(thread);
+ // If the focus thread doesn't have a stop reason, clear the thread ID
+ if (tid == g_vsc.focus_tid && !has_reason)
+ g_vsc.focus_tid = LLDB_INVALID_THREAD_ID;
+ if (has_reason) {
+ ++num_threads_with_reason;
+ if (first_tid_with_reason == LLDB_INVALID_THREAD_ID)
+ first_tid_with_reason = tid;
+ }
+ }
+
+ // We will have cleared g_vsc.focus_tid if he focus thread doesn't
+ // have a stop reason, so if it was cleared, or wasn't set, then set the
+ // focus thread to the first thread with a stop reason.
+ if (g_vsc.focus_tid == LLDB_INVALID_THREAD_ID)
+ g_vsc.focus_tid = first_tid_with_reason;
+
+ // If no threads stopped with a reason, then report the first one so
+ // we at least let the UI know we stopped.
+ if (num_threads_with_reason == 0) {
+ lldb::SBThread thread = process.GetThreadAtIndex(0);
+ g_vsc.SendJSON(CreateThreadStopped(thread, stop_id));
+ } else {
+ for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
+ lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
+ g_vsc.thread_ids.insert(thread.GetThreadID());
+ if (ThreadHasStopReason(thread)) {
+ g_vsc.SendJSON(CreateThreadStopped(thread, stop_id));
+ }
+ }
+ }
+
+ for (auto tid : old_thread_ids) {
+ auto end = g_vsc.thread_ids.end();
+ auto pos = g_vsc.thread_ids.find(tid);
+ if (pos == end)
+ SendThreadExitedEvent(tid);
+ }
+ } else {
+ if (g_vsc.log)
+ *g_vsc.log << "error: SendThreadStoppedEvent() when process"
+ " isn't stopped ("
+ << lldb::SBDebugger::StateAsCString(state) << ')'
+ << std::endl;
+ }
+ } else {
+ if (g_vsc.log)
+ *g_vsc.log << "error: SendThreadStoppedEvent() invalid process"
+ << std::endl;
+ }
+ g_vsc.RunStopCommands();
+}
+
+//----------------------------------------------------------------------
+// "ProcessEvent": {
+// "allOf": [
+// { "$ref": "#/definitions/Event" },
+// {
+// "type": "object",
+// "description": "Event message for 'process' event type. The event
+// indicates that the debugger has begun debugging a
+// new process. Either one that it has launched, or one
+// that it has attached to.",
+// "properties": {
+// "event": {
+// "type": "string",
+// "enum": [ "process" ]
+// },
+// "body": {
+// "type": "object",
+// "properties": {
+// "name": {
+// "type": "string",
+// "description": "The logical name of the process. This is
+// usually the full path to process's executable
+// file. Example: /home/myproj/program.js."
+// },
+// "systemProcessId": {
+// "type": "integer",
+// "description": "The system process id of the debugged process.
+// This property will be missing for non-system
+// processes."
+// },
+// "isLocalProcess": {
+// "type": "boolean",
+// "description": "If true, the process is running on the same
+// computer as the debug adapter."
+// },
+// "startMethod": {
+// "type": "string",
+// "enum": [ "launch", "attach", "attachForSuspendedLaunch" ],
+// "description": "Describes how the debug engine started
+// debugging this process.",
+// "enumDescriptions": [
+// "Process was launched under the debugger.",
+// "Debugger attached to an existing process.",
+// "A project launcher component has launched a new process in
+// a suspended state and then asked the debugger to attach."
+// ]
+// }
+// },
+// "required": [ "name" ]
+// }
+// },
+// "required": [ "event", "body" ]
+// }
+// ]
+// }
+//----------------------------------------------------------------------
+void SendProcessEvent(LaunchMethod launch_method) {
+ lldb::SBFileSpec exe_fspec = g_vsc.target.GetExecutable();
+ char exe_path[PATH_MAX];
+ exe_fspec.GetPath(exe_path, sizeof(exe_path));
+ llvm::json::Object event(CreateEventObject("process"));
+ llvm::json::Object body;
+ EmplaceSafeString(body, "name", std::string(exe_path));
+ const auto pid = g_vsc.target.GetProcess().GetProcessID();
+ body.try_emplace("systemProcessId", (int64_t)pid);
+ body.try_emplace("isLocalProcess", true);
+ const char *startMethod = nullptr;
+ switch (launch_method) {
+ case Launch:
+ startMethod = "launch";
+ break;
+ case Attach:
+ startMethod = "attach";
+ break;
+ case AttachForSuspendedLaunch:
+ startMethod = "attachForSuspendedLaunch";
+ break;
+ }
+ body.try_emplace("startMethod", startMethod);
+ event.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(event)));
+}
+
+//----------------------------------------------------------------------
+// Grab any STDOUT and STDERR from the process and send it up to VS Code
+// via an "output" event to the "stdout" and "stderr" categories.
+//----------------------------------------------------------------------
+void SendStdOutStdErr(lldb::SBProcess &process) {
+ char buffer[1024];
+ size_t count;
+ while ((count = process.GetSTDOUT(buffer, sizeof(buffer))) > 0)
+ g_vsc.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count));
+ while ((count = process.GetSTDERR(buffer, sizeof(buffer))) > 0)
+ g_vsc.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count));
+}
+
+//----------------------------------------------------------------------
+// All events from the debugger, target, process, thread and frames are
+// received in this function that runs in its own thread. We are using a
+// "FILE *" to output packets back to VS Code and they have mutexes in them
+// them prevent multiple threads from writing simultaneously so no locking
+// is required.
+//----------------------------------------------------------------------
+void EventThreadFunction() {
+ lldb::SBEvent event;
+ lldb::SBListener listener = g_vsc.debugger.GetListener();
+ bool done = false;
+ while (!done) {
+ if (listener.WaitForEvent(1, event)) {
+ const auto event_mask = event.GetType();
+ if (lldb::SBProcess::EventIsProcessEvent(event)) {
+ lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event);
+ if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) {
+ auto state = lldb::SBProcess::GetStateFromEvent(event);
+ switch (state) {
+ case lldb::eStateInvalid:
+ // Not a state event
+ break;
+ case lldb::eStateUnloaded:
+ break;
+ case lldb::eStateConnected:
+ break;
+ case lldb::eStateAttaching:
+ break;
+ case lldb::eStateLaunching:
+ break;
+ case lldb::eStateStepping:
+ break;
+ case lldb::eStateCrashed:
+ break;
+ case lldb::eStateDetached:
+ break;
+ case lldb::eStateSuspended:
+ break;
+ case lldb::eStateStopped:
+ // Only report a stopped event if the process was not restarted.
+ if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
+ SendStdOutStdErr(process);
+ SendThreadStoppedEvent();
+ }
+ break;
+ case lldb::eStateRunning:
+ break;
+ case lldb::eStateExited: {
+ // Run any exit LLDB commands the user specified in the
+ // launch.json
+ g_vsc.RunExitCommands();
+ SendProcessExitedEvent(process);
+ SendTerminatedEvent();
+ done = true;
+ } break;
+ }
+ } else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) ||
+ (event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
+ SendStdOutStdErr(process);
+ }
+ } else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) {
+ if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
+ auto event_type =
+ lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
+ const auto num_locs =
+ lldb::SBBreakpoint::GetNumBreakpointLocationsFromEvent(event);
+ auto bp = lldb::SBBreakpoint::GetBreakpointFromEvent(event);
+ bool added = event_type & lldb::eBreakpointEventTypeLocationsAdded;
+ bool removed =
+ event_type & lldb::eBreakpointEventTypeLocationsRemoved;
+ if (added || removed) {
+ for (size_t i = 0; i < num_locs; ++i) {
+ auto bp_loc =
+ lldb::SBBreakpoint::GetBreakpointLocationAtIndexFromEvent(
+ event, i);
+ auto bp_event = CreateEventObject("breakpoint");
+ llvm::json::Object body;
+ body.try_emplace("breakpoint", CreateBreakpoint(bp_loc));
+ if (added)
+ body.try_emplace("reason", "new");
+ else
+ body.try_emplace("reason", "removed");
+ bp_event.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(bp_event)));
+ }
+ }
+ }
+ } else if (event.BroadcasterMatchesRef(g_vsc.broadcaster)) {
+ if (event_mask & eBroadcastBitStopEventThread) {
+ done = true;
+ }
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Both attach and launch take a either a sourcePath or sourceMap
+// argument (or neither), from which we need to set the target.source-map.
+//----------------------------------------------------------------------
+void SetSourceMapFromArguments(const llvm::json::Object &arguments) {
+ const char *sourceMapHelp =
+ "source must be be an array of two-element arrays, "
+ "each containing a source and replacement path string.\n";
+
+ std::string sourceMapCommand;
+ llvm::raw_string_ostream strm(sourceMapCommand);
+ strm << "settings set target.source-map ";
+ auto sourcePath = GetString(arguments, "sourcePath");
+
+ // sourceMap is the new, more general form of sourcePath and overrides it.
+ auto sourceMap = arguments.getArray("sourceMap");
+ if (sourceMap) {
+ for (const auto &value : *sourceMap) {
+ auto mapping = value.getAsArray();
+ if (mapping == nullptr || mapping->size() != 2 ||
+ (*mapping)[0].kind() != llvm::json::Value::String ||
+ (*mapping)[1].kind() != llvm::json::Value::String) {
+ g_vsc.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
+ return;
+ }
+ auto mapFrom = GetAsString((*mapping)[0]);
+ auto mapTo = GetAsString((*mapping)[1]);
+ strm << "\"" << mapFrom << "\" \"" << mapTo << "\"";
+ }
+ } else {
+ if (ObjectContainsKey(arguments, "sourceMap")) {
+ g_vsc.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
+ return;
+ }
+ if (sourcePath.empty())
+ return;
+ // Do any source remapping needed before we create our targets
+ strm << "\".\" \"" << sourcePath << "\"";
+ }
+ strm.flush();
+ if (!sourceMapCommand.empty()) {
+ g_vsc.RunLLDBCommands("Setting source map:", {sourceMapCommand});
+ }
+}
+
+//----------------------------------------------------------------------
+// "AttachRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Attach request; value of command field is 'attach'.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "attach" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/AttachRequestArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "AttachRequestArguments": {
+// "type": "object",
+// "description": "Arguments for 'attach' request.\nThe attach request has no
+// standardized attributes."
+// },
+// "AttachResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'attach' request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+//----------------------------------------------------------------------
+void request_attach(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ lldb::SBError error;
+ FillResponse(request, response);
+ auto arguments = request.getObject("arguments");
+ const lldb::pid_t pid =
+ GetUnsigned(arguments, "pid", LLDB_INVALID_PROCESS_ID);
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ g_vsc.attach_info.SetProcessID(pid);
+ const auto wait_for = GetBoolean(arguments, "waitFor", false);
+ g_vsc.attach_info.SetWaitForLaunch(wait_for, false /*async*/);
+ g_vsc.init_commands = GetStrings(arguments, "initCommands");
+ g_vsc.pre_run_commands = GetStrings(arguments, "preRunCommands");
+ g_vsc.stop_commands = GetStrings(arguments, "stopCommands");
+ g_vsc.exit_commands = GetStrings(arguments, "exitCommands");
+ auto attachCommands = GetStrings(arguments, "attachCommands");
+ g_vsc.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false);
+ const auto debuggerRoot = GetString(arguments, "debuggerRoot");
+
+ // This is a hack for loading DWARF in .o files on Mac where the .o files
+ // in the debug map of the main executable have relative paths which require
+ // the lldb-vscode binary to have its working directory set to that relative
+ // root for the .o files in order to be able to load debug info.
+ if (!debuggerRoot.empty()) {
+ llvm::sys::fs::set_current_path(debuggerRoot.data());
+ }
+
+ // Run any initialize LLDB commands the user specified in the launch.json
+ g_vsc.RunInitCommands();
+
+ // Grab the name of the program we need to debug and set it as the first
+ // argument that will be passed to the program we will debug.
+ const auto program = GetString(arguments, "program");
+ if (!program.empty()) {
+ lldb::SBFileSpec program_fspec(program.data(), true /*resolve_path*/);
+
+ g_vsc.launch_info.SetExecutableFile(program_fspec,
+ false /*add_as_first_arg*/);
+ const char *target_triple = nullptr;
+ const char *uuid_cstr = nullptr;
+ // Stand alone debug info file if different from executable
+ const char *symfile = nullptr;
+ g_vsc.target.AddModule(program.data(), target_triple, uuid_cstr, symfile);
+ if (error.Fail()) {
+ response.try_emplace("success", false);
+ EmplaceSafeString(response, "message", std::string(error.GetCString()));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+ return;
+ }
+ }
+
+ const bool detatchOnError = GetBoolean(arguments, "detachOnError", false);
+ g_vsc.launch_info.SetDetachOnError(detatchOnError);
+
+ // Run any pre run LLDB commands the user specified in the launch.json
+ g_vsc.RunPreRunCommands();
+
+ if (pid == LLDB_INVALID_PROCESS_ID && wait_for) {
+ char attach_info[256];
+ auto attach_info_len =
+ snprintf(attach_info, sizeof(attach_info),
+ "Waiting to attach to \"%s\"...", program.data());
+ g_vsc.SendOutput(OutputType::Console, llvm::StringRef(attach_info,
+ attach_info_len));
+ }
+ if (attachCommands.empty()) {
+ // No "attachCommands", just attach normally.
+ // Disable async events so the attach will be successful when we return from
+ // the launch call and the launch will happen synchronously
+ g_vsc.debugger.SetAsync(false);
+ g_vsc.target.Attach(g_vsc.attach_info, error);
+ // Reenable async events
+ g_vsc.debugger.SetAsync(true);
+ } else {
+ // We have "attachCommands" that are a set of commands that are expected
+ // to execute the commands after which a process should be created. If there
+ // is no valid process after running these commands, we have failed.
+ g_vsc.RunLLDBCommands("Running attachCommands:", attachCommands);
+ // The custom commands might have created a new target so we should use the
+ // selected target after these commands are run.
+ g_vsc.target = g_vsc.debugger.GetSelectedTarget();
+ }
+
+ SetSourceMapFromArguments(*arguments);
+
+ if (error.Success()) {
+ auto attached_pid = g_vsc.target.GetProcess().GetProcessID();
+ if (attached_pid == LLDB_INVALID_PROCESS_ID) {
+ if (attachCommands.empty())
+ error.SetErrorString("failed to attach to a process");
+ else
+ error.SetErrorString("attachCommands failed to attach to a process");
+ }
+ }
+
+ if (error.Fail()) {
+ response.try_emplace("success", false);
+ EmplaceSafeString(response, "message", std::string(error.GetCString()));
+ }
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+ if (error.Success()) {
+ SendProcessEvent(Attach);
+ g_vsc.SendJSON(CreateEventObject("initialized"));
+ // SendThreadStoppedEvent();
+ }
+}
+
+//----------------------------------------------------------------------
+// "ContinueRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Continue request; value of command field is 'continue'.
+// The request starts the debuggee to run again.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "continue" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/ContinueArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "ContinueArguments": {
+// "type": "object",
+// "description": "Arguments for 'continue' request.",
+// "properties": {
+// "threadId": {
+// "type": "integer",
+// "description": "Continue execution for the specified thread (if
+// possible). If the backend cannot continue on a single
+// thread but will continue on all threads, it should
+// set the allThreadsContinued attribute in the response
+// to true."
+// }
+// },
+// "required": [ "threadId" ]
+// },
+// "ContinueResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'continue' request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "allThreadsContinued": {
+// "type": "boolean",
+// "description": "If true, the continue request has ignored the
+// specified thread and continued all threads
+// instead. If this attribute is missing a value
+// of 'true' is assumed for backward
+// compatibility."
+// }
+// }
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+void request_continue(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ lldb::SBProcess process = g_vsc.target.GetProcess();
+ auto arguments = request.getObject("arguments");
+ // Remember the thread ID that caused the resume so we can set the
+ // "threadCausedFocus" boolean value in the "stopped" events.
+ g_vsc.focus_tid = GetUnsigned(arguments, "threadId", LLDB_INVALID_THREAD_ID);
+ lldb::SBError error = process.Continue();
+ llvm::json::Object body;
+ body.try_emplace("allThreadsContinued", true);
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "ConfigurationDoneRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "ConfigurationDone request; value of command field
+// is 'configurationDone'.\nThe client of the debug protocol must
+// send this request at the end of the sequence of configuration
+// requests (which was started by the InitializedEvent).",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "configurationDone" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/ConfigurationDoneArguments"
+// }
+// },
+// "required": [ "command" ]
+// }]
+// },
+// "ConfigurationDoneArguments": {
+// "type": "object",
+// "description": "Arguments for 'configurationDone' request.\nThe
+// configurationDone request has no standardized attributes."
+// },
+// "ConfigurationDoneResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'configurationDone' request. This is
+// just an acknowledgement, so no body field is required."
+// }]
+// },
+//----------------------------------------------------------------------
+void request_configurationDone(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+ if (g_vsc.stop_at_entry)
+ SendThreadStoppedEvent();
+ else
+ g_vsc.target.GetProcess().Continue();
+}
+
+//----------------------------------------------------------------------
+// "DisconnectRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Disconnect request; value of command field is
+// 'disconnect'.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "disconnect" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/DisconnectArguments"
+// }
+// },
+// "required": [ "command" ]
+// }]
+// },
+// "DisconnectArguments": {
+// "type": "object",
+// "description": "Arguments for 'disconnect' request.",
+// "properties": {
+// "terminateDebuggee": {
+// "type": "boolean",
+// "description": "Indicates whether the debuggee should be terminated
+// when the debugger is disconnected. If unspecified,
+// the debug adapter is free to do whatever it thinks
+// is best. A client can only rely on this attribute
+// being properly honored if a debug adapter returns
+// true for the 'supportTerminateDebuggee' capability."
+// },
+// "restart": {
+// "type": "boolean",
+// "description": "Indicates whether the debuggee should be restart
+// the process."
+// }
+// }
+// },
+// "DisconnectResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'disconnect' request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+//----------------------------------------------------------------------
+void request_disconnect(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ auto arguments = request.getObject("arguments");
+
+ bool terminateDebuggee = GetBoolean(arguments, "terminateDebuggee", false);
+ lldb::SBProcess process = g_vsc.target.GetProcess();
+ auto state = process.GetState();
+
+ switch (state) {
+ case lldb::eStateInvalid:
+ case lldb::eStateUnloaded:
+ case lldb::eStateDetached:
+ case lldb::eStateExited:
+ break;
+ case lldb::eStateConnected:
+ case lldb::eStateAttaching:
+ case lldb::eStateLaunching:
+ case lldb::eStateStepping:
+ case lldb::eStateCrashed:
+ case lldb::eStateSuspended:
+ case lldb::eStateStopped:
+ case lldb::eStateRunning:
+ g_vsc.debugger.SetAsync(false);
+ if (terminateDebuggee)
+ process.Kill();
+ else
+ process.Detach();
+ g_vsc.debugger.SetAsync(true);
+ break;
+ }
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+ SendTerminatedEvent();
+ if (g_vsc.event_thread.joinable()) {
+ g_vsc.broadcaster.BroadcastEventByType(eBroadcastBitStopEventThread);
+ g_vsc.event_thread.join();
+ }
+}
+
+void request_exceptionInfo(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ auto arguments = request.getObject("arguments");
+ llvm::json::Object body;
+ lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
+ if (thread.IsValid()) {
+ auto stopReason = thread.GetStopReason();
+ if (stopReason == lldb::eStopReasonSignal)
+ body.try_emplace("exceptionId", "signal");
+ else if (stopReason == lldb::eStopReasonBreakpoint) {
+ ExceptionBreakpoint *exc_bp = g_vsc.GetExceptionBPFromStopReason(thread);
+ if (exc_bp) {
+ EmplaceSafeString(body, "exceptionId", exc_bp->filter);
+ EmplaceSafeString(body, "description", exc_bp->label);
+ } else {
+ body.try_emplace("exceptionId", "exception");
+ }
+ } else {
+ body.try_emplace("exceptionId", "exception");
+ }
+ if (!ObjectContainsKey(body, "description")) {
+ char description[1024];
+ if (thread.GetStopDescription(description, sizeof(description))) {
+ EmplaceSafeString(body, "description", std::string(description));
+ }
+ }
+ body.try_emplace("breakMode", "always");
+ // auto excInfoCount = thread.GetStopReasonDataCount();
+ // for (auto i=0; i<excInfoCount; ++i) {
+ // uint64_t exc_data = thread.GetStopReasonDataAtIndex(i);
+ // }
+ } else {
+ response.try_emplace("success", false);
+ }
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "EvaluateRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Evaluate request; value of command field is 'evaluate'.
+// Evaluates the given expression in the context of the
+// top most stack frame. The expression has access to any
+// variables and arguments that are in scope.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "evaluate" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/EvaluateArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "EvaluateArguments": {
+// "type": "object",
+// "description": "Arguments for 'evaluate' request.",
+// "properties": {
+// "expression": {
+// "type": "string",
+// "description": "The expression to evaluate."
+// },
+// "frameId": {
+// "type": "integer",
+// "description": "Evaluate the expression in the scope of this stack
+// frame. If not specified, the expression is evaluated
+// in the global scope."
+// },
+// "context": {
+// "type": "string",
+// "_enum": [ "watch", "repl", "hover" ],
+// "enumDescriptions": [
+// "evaluate is run in a watch.",
+// "evaluate is run from REPL console.",
+// "evaluate is run from a data hover."
+// ],
+// "description": "The context in which the evaluate request is run."
+// },
+// "format": {
+// "$ref": "#/definitions/ValueFormat",
+// "description": "Specifies details on how to format the Evaluate
+// result."
+// }
+// },
+// "required": [ "expression" ]
+// },
+// "EvaluateResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'evaluate' request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "result": {
+// "type": "string",
+// "description": "The result of the evaluate request."
+// },
+// "type": {
+// "type": "string",
+// "description": "The optional type of the evaluate result."
+// },
+// "presentationHint": {
+// "$ref": "#/definitions/VariablePresentationHint",
+// "description": "Properties of a evaluate result that can be
+// used to determine how to render the result in
+// the UI."
+// },
+// "variablesReference": {
+// "type": "number",
+// "description": "If variablesReference is > 0, the evaluate
+// result is structured and its children can be
+// retrieved by passing variablesReference to the
+// VariablesRequest."
+// },
+// "namedVariables": {
+// "type": "number",
+// "description": "The number of named child variables. The
+// client can use this optional information to
+// present the variables in a paged UI and fetch
+// them in chunks."
+// },
+// "indexedVariables": {
+// "type": "number",
+// "description": "The number of indexed child variables. The
+// client can use this optional information to
+// present the variables in a paged UI and fetch
+// them in chunks."
+// }
+// },
+// "required": [ "result", "variablesReference" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+void request_evaluate(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ llvm::json::Object body;
+ auto arguments = request.getObject("arguments");
+ lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments);
+ const auto expression = GetString(arguments, "expression");
+
+ if (!expression.empty() && expression[0] == '`') {
+ auto result = RunLLDBCommands(llvm::StringRef(),
+ {expression.substr(1)});
+ EmplaceSafeString(body, "result", result);
+ body.try_emplace("variablesReference", (int64_t)0);
+ } else {
+ // Always try to get the answer from the local variables if possible. If
+ // this fails, then actually evaluate an expression using the expression
+ // parser. "frame variable" is more reliable than the expression parser in
+ // many cases and it is faster.
+ lldb::SBValue value = frame.GetValueForVariablePath(
+ expression.data(), lldb::eDynamicDontRunTarget);
+ if (value.GetError().Fail())
+ value = frame.EvaluateExpression(expression.data());
+ if (value.GetError().Fail()) {
+ response.try_emplace("success", false);
+ const char *error_cstr = value.GetError().GetCString();
+ if (error_cstr && error_cstr[0])
+ EmplaceSafeString(response, "message", std::string(error_cstr));
+ else
+ EmplaceSafeString(response, "message", "evaluate failed");
+ } else {
+ SetValueForKey(value, body, "result");
+ auto value_typename = value.GetType().GetDisplayTypeName();
+ EmplaceSafeString(body, "type", value_typename ? value_typename : NO_TYPENAME);
+ if (value.MightHaveChildren()) {
+ auto variablesReference = VARIDX_TO_VARREF(g_vsc.variables.GetSize());
+ g_vsc.variables.Append(value);
+ body.try_emplace("variablesReference", variablesReference);
+ } else {
+ body.try_emplace("variablesReference", (int64_t)0);
+ }
+ }
+ }
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "InitializeRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Initialize request; value of command field is
+// 'initialize'.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "initialize" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/InitializeRequestArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "InitializeRequestArguments": {
+// "type": "object",
+// "description": "Arguments for 'initialize' request.",
+// "properties": {
+// "clientID": {
+// "type": "string",
+// "description": "The ID of the (frontend) client using this adapter."
+// },
+// "adapterID": {
+// "type": "string",
+// "description": "The ID of the debug adapter."
+// },
+// "locale": {
+// "type": "string",
+// "description": "The ISO-639 locale of the (frontend) client using
+// this adapter, e.g. en-US or de-CH."
+// },
+// "linesStartAt1": {
+// "type": "boolean",
+// "description": "If true all line numbers are 1-based (default)."
+// },
+// "columnsStartAt1": {
+// "type": "boolean",
+// "description": "If true all column numbers are 1-based (default)."
+// },
+// "pathFormat": {
+// "type": "string",
+// "_enum": [ "path", "uri" ],
+// "description": "Determines in what format paths are specified. The
+// default is 'path', which is the native format."
+// },
+// "supportsVariableType": {
+// "type": "boolean",
+// "description": "Client supports the optional type attribute for
+// variables."
+// },
+// "supportsVariablePaging": {
+// "type": "boolean",
+// "description": "Client supports the paging of variables."
+// },
+// "supportsRunInTerminalRequest": {
+// "type": "boolean",
+// "description": "Client supports the runInTerminal request."
+// }
+// },
+// "required": [ "adapterID" ]
+// },
+// "InitializeResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'initialize' request.",
+// "properties": {
+// "body": {
+// "$ref": "#/definitions/Capabilities",
+// "description": "The capabilities of this debug adapter."
+// }
+// }
+// }]
+// }
+//----------------------------------------------------------------------
+void request_initialize(const llvm::json::Object &request) {
+ g_vsc.debugger = lldb::SBDebugger::Create(true /*source_init_files*/);
+ // Create an empty target right away since we might get breakpoint requests
+ // before we are given an executable to launch in a "launch" request, or a
+ // executable when attaching to a process by process ID in a "attach"
+ // request.
+ FILE *out = fopen(dev_null_path, "w");
+ if (out) {
+ // Set the output and error file handles to redirect into nothing otherwise
+ // if any code in LLDB prints to the debugger file handles, the output and
+ // error file handles are initialized to STDOUT and STDERR and any output
+ // will kill our debug session.
+ g_vsc.debugger.SetOutputFileHandle(out, true);
+ g_vsc.debugger.SetErrorFileHandle(out, false);
+ }
+
+ g_vsc.target = g_vsc.debugger.CreateTarget(nullptr);
+ lldb::SBListener listener = g_vsc.debugger.GetListener();
+ listener.StartListeningForEvents(
+ g_vsc.target.GetBroadcaster(),
+ lldb::SBTarget::eBroadcastBitBreakpointChanged);
+ listener.StartListeningForEvents(g_vsc.broadcaster,
+ eBroadcastBitStopEventThread);
+ // Start our event thread so we can receive events from the debugger, target,
+ // process and more.
+ g_vsc.event_thread = std::thread(EventThreadFunction);
+
+ llvm::json::Object response;
+ FillResponse(request, response);
+ llvm::json::Object body;
+ // The debug adapter supports the configurationDoneRequest.
+ body.try_emplace("supportsConfigurationDoneRequest", true);
+ // The debug adapter supports function breakpoints.
+ body.try_emplace("supportsFunctionBreakpoints", true);
+ // The debug adapter supports conditional breakpoints.
+ body.try_emplace("supportsConditionalBreakpoints", true);
+ // The debug adapter supports breakpoints that break execution after a
+ // specified number of hits.
+ body.try_emplace("supportsHitConditionalBreakpoints", true);
+ // The debug adapter supports a (side effect free) evaluate request for
+ // data hovers.
+ body.try_emplace("supportsEvaluateForHovers", true);
+ // Available filters or options for the setExceptionBreakpoints request.
+ llvm::json::Array filters;
+ for (const auto &exc_bp : g_vsc.exception_breakpoints) {
+ filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp));
+ }
+ body.try_emplace("exceptionBreakpointFilters", std::move(filters));
+ // The debug adapter supports stepping back via the stepBack and
+ // reverseContinue requests.
+ body.try_emplace("supportsStepBack", false);
+ // The debug adapter supports setting a variable to a value.
+ body.try_emplace("supportsSetVariable", true);
+ // The debug adapter supports restarting a frame.
+ body.try_emplace("supportsRestartFrame", false);
+ // The debug adapter supports the gotoTargetsRequest.
+ body.try_emplace("supportsGotoTargetsRequest", false);
+ // The debug adapter supports the stepInTargetsRequest.
+ body.try_emplace("supportsStepInTargetsRequest", false);
+ // The debug adapter supports the completionsRequest.
+ body.try_emplace("supportsCompletionsRequest", false);
+ // The debug adapter supports the modules request.
+ body.try_emplace("supportsModulesRequest", false);
+ // The set of additional module information exposed by the debug adapter.
+ // body.try_emplace("additionalModuleColumns"] = ColumnDescriptor
+ // Checksum algorithms supported by the debug adapter.
+ // body.try_emplace("supportedChecksumAlgorithms"] = ChecksumAlgorithm
+ // The debug adapter supports the RestartRequest. In this case a client
+ // should not implement 'restart' by terminating and relaunching the adapter
+ // but by calling the RestartRequest.
+ body.try_emplace("supportsRestartRequest", false);
+ // The debug adapter supports 'exceptionOptions' on the
+ // setExceptionBreakpoints request.
+ body.try_emplace("supportsExceptionOptions", true);
+ // The debug adapter supports a 'format' attribute on the stackTraceRequest,
+ // variablesRequest, and evaluateRequest.
+ body.try_emplace("supportsValueFormattingOptions", true);
+ // The debug adapter supports the exceptionInfo request.
+ body.try_emplace("supportsExceptionInfoRequest", true);
+ // The debug adapter supports the 'terminateDebuggee' attribute on the
+ // 'disconnect' request.
+ body.try_emplace("supportTerminateDebuggee", true);
+ // The debug adapter supports the delayed loading of parts of the stack,
+ // which requires that both the 'startFrame' and 'levels' arguments and the
+ // 'totalFrames' result of the 'StackTrace' request are supported.
+ body.try_emplace("supportsDelayedStackTraceLoading", true);
+ // The debug adapter supports the 'loadedSources' request.
+ body.try_emplace("supportsLoadedSourcesRequest", false);
+
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "LaunchRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Launch request; value of command field is 'launch'.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "launch" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/LaunchRequestArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "LaunchRequestArguments": {
+// "type": "object",
+// "description": "Arguments for 'launch' request.",
+// "properties": {
+// "noDebug": {
+// "type": "boolean",
+// "description": "If noDebug is true the launch request should launch
+// the program without enabling debugging."
+// }
+// }
+// },
+// "LaunchResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'launch' request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+//----------------------------------------------------------------------
+void request_launch(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ lldb::SBError error;
+ FillResponse(request, response);
+ auto arguments = request.getObject("arguments");
+ g_vsc.init_commands = GetStrings(arguments, "initCommands");
+ g_vsc.pre_run_commands = GetStrings(arguments, "preRunCommands");
+ g_vsc.stop_commands = GetStrings(arguments, "stopCommands");
+ g_vsc.exit_commands = GetStrings(arguments, "exitCommands");
+ g_vsc.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false);
+ const auto debuggerRoot = GetString(arguments, "debuggerRoot");
+
+ // This is a hack for loading DWARF in .o files on Mac where the .o files
+ // in the debug map of the main executable have relative paths which require
+ // the lldb-vscode binary to have its working directory set to that relative
+ // root for the .o files in order to be able to load debug info.
+ if (!debuggerRoot.empty()) {
+ llvm::sys::fs::set_current_path(debuggerRoot.data());
+ }
+
+ SetSourceMapFromArguments(*arguments);
+
+ // Run any initialize LLDB commands the user specified in the launch.json
+ g_vsc.RunInitCommands();
+
+ // Grab the current working directory if there is one and set it in the
+ // launch info.
+ const auto cwd = GetString(arguments, "cwd");
+ if (!cwd.empty())
+ g_vsc.launch_info.SetWorkingDirectory(cwd.data());
+
+ // Grab the name of the program we need to debug and set it as the first
+ // argument that will be passed to the program we will debug.
+ const auto program = GetString(arguments, "program");
+ if (!program.empty()) {
+ lldb::SBFileSpec program_fspec(program.data(), true /*resolve_path*/);
+
+ g_vsc.launch_info.SetExecutableFile(program_fspec,
+ true /*add_as_first_arg*/);
+ const char *target_triple = nullptr;
+ const char *uuid_cstr = nullptr;
+ // Stand alone debug info file if different from executable
+ const char *symfile = nullptr;
+ g_vsc.target.AddModule(program.data(), target_triple, uuid_cstr, symfile);
+ if (error.Fail()) {
+ response.try_emplace("success", false);
+ EmplaceSafeString(response, "message", std::string(error.GetCString()));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+ }
+ }
+
+ // Extract any extra arguments and append them to our program arguments for
+ // when we launch
+ auto args = GetStrings(arguments, "args");
+ if (!args.empty())
+ g_vsc.launch_info.SetArguments(MakeArgv(args).data(), true);
+
+ // Pass any environment variables along that the user specified.
+ auto envs = GetStrings(arguments, "env");
+ if (!envs.empty())
+ g_vsc.launch_info.SetEnvironmentEntries(MakeArgv(envs).data(), true);
+
+ auto flags = g_vsc.launch_info.GetLaunchFlags();
+
+ if (GetBoolean(arguments, "disableASLR", true))
+ flags |= lldb::eLaunchFlagDisableASLR;
+ if (GetBoolean(arguments, "disableSTDIO", false))
+ flags |= lldb::eLaunchFlagDisableSTDIO;
+ if (GetBoolean(arguments, "shellExpandArguments", false))
+ flags |= lldb::eLaunchFlagShellExpandArguments;
+ const bool detatchOnError = GetBoolean(arguments, "detachOnError", false);
+ g_vsc.launch_info.SetDetachOnError(detatchOnError);
+ g_vsc.launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug |
+ lldb::eLaunchFlagStopAtEntry);
+
+ // Run any pre run LLDB commands the user specified in the launch.json
+ g_vsc.RunPreRunCommands();
+
+ // Disable async events so the launch will be successful when we return from
+ // the launch call and the launch will happen synchronously
+ g_vsc.debugger.SetAsync(false);
+ g_vsc.target.Launch(g_vsc.launch_info, error);
+ if (error.Fail()) {
+ response.try_emplace("success", false);
+ EmplaceSafeString(response, "message", std::string(error.GetCString()));
+ }
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+
+ SendProcessEvent(Launch);
+ g_vsc.SendJSON(llvm::json::Value(CreateEventObject("initialized")));
+ // Reenable async events and start the event thread to catch async events.
+ g_vsc.debugger.SetAsync(true);
+}
+
+//----------------------------------------------------------------------
+// "NextRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Next request; value of command field is 'next'. The
+// request starts the debuggee to run again for one step.
+// The debug adapter first sends the NextResponse and then
+// a StoppedEvent (event type 'step') after the step has
+// completed.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "next" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/NextArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "NextArguments": {
+// "type": "object",
+// "description": "Arguments for 'next' request.",
+// "properties": {
+// "threadId": {
+// "type": "integer",
+// "description": "Execute 'next' for this thread."
+// }
+// },
+// "required": [ "threadId" ]
+// },
+// "NextResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'next' request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+//----------------------------------------------------------------------
+void request_next(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ auto arguments = request.getObject("arguments");
+ lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
+ if (thread.IsValid()) {
+ // Remember the thread ID that caused the resume so we can set the
+ // "threadCausedFocus" boolean value in the "stopped" events.
+ g_vsc.focus_tid = thread.GetThreadID();
+ thread.StepOver();
+ } else {
+ response.try_emplace("success", false);
+ }
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "PauseRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Pause request; value of command field is 'pause'. The
+// request suspenses the debuggee. The debug adapter first sends the
+// PauseResponse and then a StoppedEvent (event type 'pause') after the
+// thread has been paused successfully.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "pause" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/PauseArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "PauseArguments": {
+// "type": "object",
+// "description": "Arguments for 'pause' request.",
+// "properties": {
+// "threadId": {
+// "type": "integer",
+// "description": "Pause execution for this thread."
+// }
+// },
+// "required": [ "threadId" ]
+// },
+// "PauseResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'pause' request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+//----------------------------------------------------------------------
+void request_pause(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ lldb::SBProcess process = g_vsc.target.GetProcess();
+ lldb::SBError error = process.Stop();
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "ScopesRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Scopes request; value of command field is 'scopes'. The
+// request returns the variable scopes for a given stackframe ID.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "scopes" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/ScopesArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "ScopesArguments": {
+// "type": "object",
+// "description": "Arguments for 'scopes' request.",
+// "properties": {
+// "frameId": {
+// "type": "integer",
+// "description": "Retrieve the scopes for this stackframe."
+// }
+// },
+// "required": [ "frameId" ]
+// },
+// "ScopesResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'scopes' request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "scopes": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/Scope"
+// },
+// "description": "The scopes of the stackframe. If the array has
+// length zero, there are no scopes available."
+// }
+// },
+// "required": [ "scopes" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+void request_scopes(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ llvm::json::Object body;
+ auto arguments = request.getObject("arguments");
+ lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments);
+ g_vsc.variables.Clear();
+ g_vsc.variables.Append(frame.GetVariables(true, // arguments
+ true, // locals
+ false, // statics
+ true)); // in_scope_only
+ g_vsc.num_locals = g_vsc.variables.GetSize();
+ g_vsc.variables.Append(frame.GetVariables(false, // arguments
+ false, // locals
+ true, // statics
+ true)); // in_scope_only
+ g_vsc.num_globals = g_vsc.variables.GetSize() - (g_vsc.num_locals);
+ g_vsc.variables.Append(frame.GetRegisters());
+ g_vsc.num_regs =
+ g_vsc.variables.GetSize() - (g_vsc.num_locals + g_vsc.num_globals);
+ body.try_emplace("scopes", g_vsc.CreateTopLevelScopes());
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "SetBreakpointsRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "SetBreakpoints request; value of command field is
+// 'setBreakpoints'. Sets multiple breakpoints for a single source and
+// clears all previous breakpoints in that source. To clear all breakpoint
+// for a source, specify an empty array. When a breakpoint is hit, a
+// StoppedEvent (event type 'breakpoint') is generated.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "setBreakpoints" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/SetBreakpointsArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "SetBreakpointsArguments": {
+// "type": "object",
+// "description": "Arguments for 'setBreakpoints' request.",
+// "properties": {
+// "source": {
+// "$ref": "#/definitions/Source",
+// "description": "The source location of the breakpoints; either
+// source.path or source.reference must be specified."
+// },
+// "breakpoints": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/SourceBreakpoint"
+// },
+// "description": "The code locations of the breakpoints."
+// },
+// "lines": {
+// "type": "array",
+// "items": {
+// "type": "integer"
+// },
+// "description": "Deprecated: The code locations of the breakpoints."
+// },
+// "sourceModified": {
+// "type": "boolean",
+// "description": "A value of true indicates that the underlying source
+// has been modified which results in new breakpoint locations."
+// }
+// },
+// "required": [ "source" ]
+// },
+// "SetBreakpointsResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'setBreakpoints' request. Returned is
+// information about each breakpoint created by this request. This includes
+// the actual code location and whether the breakpoint could be verified.
+// The breakpoints returned are in the same order as the elements of the
+// 'breakpoints' (or the deprecated 'lines') in the
+// SetBreakpointsArguments.", "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "breakpoints": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/Breakpoint"
+// },
+// "description": "Information about the breakpoints. The array
+// elements are in the same order as the elements of the
+// 'breakpoints' (or the deprecated 'lines') in the
+// SetBreakpointsArguments."
+// }
+// },
+// "required": [ "breakpoints" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// },
+// "SourceBreakpoint": {
+// "type": "object",
+// "description": "Properties of a breakpoint or logpoint passed to the
+// setBreakpoints request.", "properties": {
+// "line": {
+// "type": "integer",
+// "description": "The source line of the breakpoint or logpoint."
+// },
+// "column": {
+// "type": "integer",
+// "description": "An optional source column of the breakpoint."
+// },
+// "condition": {
+// "type": "string",
+// "description": "An optional expression for conditional breakpoints."
+// },
+// "hitCondition": {
+// "type": "string",
+// "description": "An optional expression that controls how many hits of
+// the breakpoint are ignored. The backend is expected to interpret the
+// expression as needed."
+// },
+// "logMessage": {
+// "type": "string",
+// "description": "If this attribute exists and is non-empty, the backend
+// must not 'break' (stop) but log the message instead. Expressions within
+// {} are interpolated."
+// }
+// },
+// "required": [ "line" ]
+// }
+//----------------------------------------------------------------------
+void request_setBreakpoints(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ lldb::SBError error;
+ FillResponse(request, response);
+ auto arguments = request.getObject("arguments");
+ auto source = arguments->getObject("source");
+ const auto path = GetString(source, "path");
+ auto breakpoints = arguments->getArray("breakpoints");
+ llvm::json::Array response_breakpoints;
+ // Decode the source breakpoint infos for this "setBreakpoints" request
+ SourceBreakpointMap request_bps;
+ for (const auto &bp : *breakpoints) {
+ auto bp_obj = bp.getAsObject();
+ if (bp_obj) {
+ SourceBreakpoint src_bp(*bp_obj);
+ request_bps[src_bp.line] = std::move(src_bp);
+ }
+ }
+
+ // See if we already have breakpoints set for this source file from a
+ // previous "setBreakpoints" request
+ auto old_src_bp_pos = g_vsc.source_breakpoints.find(path);
+ if (old_src_bp_pos != g_vsc.source_breakpoints.end()) {
+
+ // We have already set breakpoints in this source file and they are giving
+ // use a new list of lines to set breakpoints on. Some breakpoints might
+ // already be set, and some might not. We need to remove any breakpoints
+ // whose lines are not contained in the any breakpoints lines in in the
+ // "breakpoints" array.
+
+ // Delete any breakpoints in this source file that aren't in the
+ // request_bps set. There is no call to remove breakpoints other than
+ // calling this function with a smaller or empty "breakpoints" list.
+ std::vector<uint32_t> remove_lines;
+ for (auto &pair: old_src_bp_pos->second) {
+ auto request_pos = request_bps.find(pair.first);
+ if (request_pos == request_bps.end()) {
+ // This breakpoint no longer exists in this source file, delete it
+ g_vsc.target.BreakpointDelete(pair.second.bp.GetID());
+ remove_lines.push_back(pair.first);
+ } else {
+ pair.second.UpdateBreakpoint(request_pos->second);
+ // Remove this breakpoint from the request breakpoints since we have
+ // handled it here and we don't need to set a new breakpoint below.
+ request_bps.erase(request_pos);
+ // Add this breakpoint info to the response
+ AppendBreakpoint(pair.second.bp, response_breakpoints);
+ }
+ }
+ // Remove any lines from this existing source breakpoint map
+ for (auto line: remove_lines)
+ old_src_bp_pos->second.erase(line);
+
+ // Now add any breakpoint infos left over in request_bps are the
+ // breakpoints that weren't set in this source file yet. We need to update
+ // thread source breakpoint info for the source file in the variable
+ // "old_src_bp_pos->second" so the info for this source file is up to date.
+ for (auto &pair : request_bps) {
+ pair.second.SetBreakpoint(path.data());
+ // Add this breakpoint info to the response
+ AppendBreakpoint(pair.second.bp, response_breakpoints);
+ old_src_bp_pos->second[pair.first] = std::move(pair.second);
+ }
+ } else {
+ // No breakpoints were set for this source file yet. Set all breakpoints
+ // for each line and add them to the response and create an entry in
+ // g_vsc.source_breakpoints for this source file.
+ for (auto &pair : request_bps) {
+ pair.second.SetBreakpoint(path.data());
+ // Add this breakpoint info to the response
+ AppendBreakpoint(pair.second.bp, response_breakpoints);
+ }
+ g_vsc.source_breakpoints[path] = std::move(request_bps);
+ }
+
+ llvm::json::Object body;
+ body.try_emplace("breakpoints", std::move(response_breakpoints));
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "SetExceptionBreakpointsRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "SetExceptionBreakpoints request; value of command field
+// is 'setExceptionBreakpoints'. The request configures the debuggers
+// response to thrown exceptions. If an exception is configured to break, a
+// StoppedEvent is fired (event type 'exception').", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "setExceptionBreakpoints" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/SetExceptionBreakpointsArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "SetExceptionBreakpointsArguments": {
+// "type": "object",
+// "description": "Arguments for 'setExceptionBreakpoints' request.",
+// "properties": {
+// "filters": {
+// "type": "array",
+// "items": {
+// "type": "string"
+// },
+// "description": "IDs of checked exception options. The set of IDs is
+// returned via the 'exceptionBreakpointFilters' capability."
+// },
+// "exceptionOptions": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/ExceptionOptions"
+// },
+// "description": "Configuration options for selected exceptions."
+// }
+// },
+// "required": [ "filters" ]
+// },
+// "SetExceptionBreakpointsResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'setExceptionBreakpoints' request. This is
+// just an acknowledgement, so no body field is required."
+// }]
+// }
+//----------------------------------------------------------------------
+void request_setExceptionBreakpoints(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ lldb::SBError error;
+ FillResponse(request, response);
+ auto arguments = request.getObject("arguments");
+ auto filters = arguments->getArray("filters");
+ // Keep a list of any exception breakpoint filter names that weren't set
+ // so we can clear any exception breakpoints if needed.
+ std::set<std::string> unset_filters;
+ for (const auto &bp : g_vsc.exception_breakpoints)
+ unset_filters.insert(bp.filter);
+
+ for (const auto &value : *filters) {
+ const auto filter = GetAsString(value);
+ auto exc_bp = g_vsc.GetExceptionBreakpoint(filter);
+ if (exc_bp) {
+ exc_bp->SetBreakpoint();
+ unset_filters.erase(filter);
+ }
+ }
+ for (const auto &filter : unset_filters) {
+ auto exc_bp = g_vsc.GetExceptionBreakpoint(filter);
+ if (exc_bp)
+ exc_bp->ClearBreakpoint();
+ }
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "SetFunctionBreakpointsRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "SetFunctionBreakpoints request; value of command field is
+// 'setFunctionBreakpoints'. Sets multiple function breakpoints and clears
+// all previous function breakpoints. To clear all function breakpoint,
+// specify an empty array. When a function breakpoint is hit, a StoppedEvent
+// (event type 'function breakpoint') is generated.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "setFunctionBreakpoints" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/SetFunctionBreakpointsArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "SetFunctionBreakpointsArguments": {
+// "type": "object",
+// "description": "Arguments for 'setFunctionBreakpoints' request.",
+// "properties": {
+// "breakpoints": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/FunctionBreakpoint"
+// },
+// "description": "The function names of the breakpoints."
+// }
+// },
+// "required": [ "breakpoints" ]
+// },
+// "FunctionBreakpoint": {
+// "type": "object",
+// "description": "Properties of a breakpoint passed to the
+// setFunctionBreakpoints request.", "properties": {
+// "name": {
+// "type": "string",
+// "description": "The name of the function."
+// },
+// "condition": {
+// "type": "string",
+// "description": "An optional expression for conditional breakpoints."
+// },
+// "hitCondition": {
+// "type": "string",
+// "description": "An optional expression that controls how many hits of
+// the breakpoint are ignored. The backend is expected to interpret the
+// expression as needed."
+// }
+// },
+// "required": [ "name" ]
+// },
+// "SetFunctionBreakpointsResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'setFunctionBreakpoints' request. Returned is
+// information about each breakpoint created by this request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "breakpoints": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/Breakpoint"
+// },
+// "description": "Information about the breakpoints. The array
+// elements correspond to the elements of the 'breakpoints' array."
+// }
+// },
+// "required": [ "breakpoints" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+void request_setFunctionBreakpoints(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ lldb::SBError error;
+ FillResponse(request, response);
+ auto arguments = request.getObject("arguments");
+ auto breakpoints = arguments->getArray("breakpoints");
+ FunctionBreakpointMap request_bps;
+ llvm::json::Array response_breakpoints;
+ for (const auto &value : *breakpoints) {
+ auto bp_obj = value.getAsObject();
+ if (bp_obj == nullptr)
+ continue;
+ FunctionBreakpoint func_bp(*bp_obj);
+ request_bps[func_bp.functionName] = std::move(func_bp);
+ }
+
+ std::vector<llvm::StringRef> remove_names;
+ // Disable any function breakpoints that aren't in the request_bps.
+ // There is no call to remove function breakpoints other than calling this
+ // function with a smaller or empty "breakpoints" list.
+ for (auto &pair: g_vsc.function_breakpoints) {
+ auto request_pos = request_bps.find(pair.first());
+ if (request_pos == request_bps.end()) {
+ // This function breakpoint no longer exists delete it from LLDB
+ g_vsc.target.BreakpointDelete(pair.second.bp.GetID());
+ remove_names.push_back(pair.first());
+ } else {
+ // Update the existing breakpoint as any setting withing the function
+ // breakpoint might have changed.
+ pair.second.UpdateBreakpoint(request_pos->second);
+ // Remove this breakpoint from the request breakpoints since we have
+ // handled it here and we don't need to set a new breakpoint below.
+ request_bps.erase(request_pos);
+ // Add this breakpoint info to the response
+ AppendBreakpoint(pair.second.bp, response_breakpoints);
+ }
+ }
+ // Remove any breakpoints that are no longer in our list
+ for (const auto &name: remove_names)
+ g_vsc.function_breakpoints.erase(name);
+
+ // Any breakpoints that are left in "request_bps" are breakpoints that
+ // need to be set.
+ for (auto &pair : request_bps) {
+ pair.second.SetBreakpoint();
+ // Add this breakpoint info to the response
+ AppendBreakpoint(pair.second.bp, response_breakpoints);
+ g_vsc.function_breakpoints[pair.first()] = std::move(pair.second);
+ }
+
+ llvm::json::Object body;
+ body.try_emplace("breakpoints", std::move(response_breakpoints));
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "SourceRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Source request; value of command field is 'source'. The
+// request retrieves the source code for a given source reference.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "source" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/SourceArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "SourceArguments": {
+// "type": "object",
+// "description": "Arguments for 'source' request.",
+// "properties": {
+// "source": {
+// "$ref": "#/definitions/Source",
+// "description": "Specifies the source content to load. Either
+// source.path or source.sourceReference must be specified."
+// },
+// "sourceReference": {
+// "type": "integer",
+// "description": "The reference to the source. This is the same as
+// source.sourceReference. This is provided for backward compatibility
+// since old backends do not understand the 'source' attribute."
+// }
+// },
+// "required": [ "sourceReference" ]
+// },
+// "SourceResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'source' request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "content": {
+// "type": "string",
+// "description": "Content of the source reference."
+// },
+// "mimeType": {
+// "type": "string",
+// "description": "Optional content type (mime type) of the source."
+// }
+// },
+// "required": [ "content" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+void request_source(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ llvm::json::Object body;
+
+ auto arguments = request.getObject("arguments");
+ auto source = arguments->getObject("source");
+ auto sourceReference = GetSigned(source, "sourceReference", -1);
+ auto pos = g_vsc.source_map.find((lldb::addr_t)sourceReference);
+ if (pos != g_vsc.source_map.end()) {
+ EmplaceSafeString(body, "content", pos->second.content);
+ } else {
+ response.try_emplace("success", false);
+ }
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "StackTraceRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "StackTrace request; value of command field is
+// 'stackTrace'. The request returns a stacktrace from the current execution
+// state.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "stackTrace" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/StackTraceArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "StackTraceArguments": {
+// "type": "object",
+// "description": "Arguments for 'stackTrace' request.",
+// "properties": {
+// "threadId": {
+// "type": "integer",
+// "description": "Retrieve the stacktrace for this thread."
+// },
+// "startFrame": {
+// "type": "integer",
+// "description": "The index of the first frame to return; if omitted
+// frames start at 0."
+// },
+// "levels": {
+// "type": "integer",
+// "description": "The maximum number of frames to return. If levels is
+// not specified or 0, all frames are returned."
+// },
+// "format": {
+// "$ref": "#/definitions/StackFrameFormat",
+// "description": "Specifies details on how to format the stack frames."
+// }
+// },
+// "required": [ "threadId" ]
+// },
+// "StackTraceResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'stackTrace' request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "stackFrames": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/StackFrame"
+// },
+// "description": "The frames of the stackframe. If the array has
+// length zero, there are no stackframes available. This means that
+// there is no location information available."
+// },
+// "totalFrames": {
+// "type": "integer",
+// "description": "The total number of frames available."
+// }
+// },
+// "required": [ "stackFrames" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+void request_stackTrace(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ lldb::SBError error;
+ auto arguments = request.getObject("arguments");
+ lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
+ llvm::json::Array stackFrames;
+ llvm::json::Object body;
+
+ if (thread.IsValid()) {
+ const auto startFrame = GetUnsigned(arguments, "startFrame", 0);
+ const auto levels = GetUnsigned(arguments, "levels", 0);
+ const auto endFrame = (levels == 0) ? INT64_MAX : (startFrame + levels);
+ for (uint32_t i = startFrame; i < endFrame; ++i) {
+ auto frame = thread.GetFrameAtIndex(i);
+ if (!frame.IsValid())
+ break;
+ stackFrames.emplace_back(CreateStackFrame(frame));
+ }
+ }
+ body.try_emplace("stackFrames", std::move(stackFrames));
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "StepInRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "StepIn request; value of command field is 'stepIn'. The
+// request starts the debuggee to step into a function/method if possible.
+// If it cannot step into a target, 'stepIn' behaves like 'next'. The debug
+// adapter first sends the StepInResponse and then a StoppedEvent (event
+// type 'step') after the step has completed. If there are multiple
+// function/method calls (or other targets) on the source line, the optional
+// argument 'targetId' can be used to control into which target the 'stepIn'
+// should occur. The list of possible targets for a given source line can be
+// retrieved via the 'stepInTargets' request.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "stepIn" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/StepInArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "StepInArguments": {
+// "type": "object",
+// "description": "Arguments for 'stepIn' request.",
+// "properties": {
+// "threadId": {
+// "type": "integer",
+// "description": "Execute 'stepIn' for this thread."
+// },
+// "targetId": {
+// "type": "integer",
+// "description": "Optional id of the target to step into."
+// }
+// },
+// "required": [ "threadId" ]
+// },
+// "StepInResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'stepIn' request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+//----------------------------------------------------------------------
+void request_stepIn(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ auto arguments = request.getObject("arguments");
+ lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
+ if (thread.IsValid()) {
+ // Remember the thread ID that caused the resume so we can set the
+ // "threadCausedFocus" boolean value in the "stopped" events.
+ g_vsc.focus_tid = thread.GetThreadID();
+ thread.StepInto();
+ } else {
+ response.try_emplace("success", false);
+ }
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "StepOutRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "StepOut request; value of command field is 'stepOut'. The
+// request starts the debuggee to run again for one step. The debug adapter
+// first sends the StepOutResponse and then a StoppedEvent (event type
+// 'step') after the step has completed.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "stepOut" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/StepOutArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "StepOutArguments": {
+// "type": "object",
+// "description": "Arguments for 'stepOut' request.",
+// "properties": {
+// "threadId": {
+// "type": "integer",
+// "description": "Execute 'stepOut' for this thread."
+// }
+// },
+// "required": [ "threadId" ]
+// },
+// "StepOutResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'stepOut' request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+//----------------------------------------------------------------------
+void request_stepOut(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ auto arguments = request.getObject("arguments");
+ lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
+ if (thread.IsValid()) {
+ // Remember the thread ID that caused the resume so we can set the
+ // "threadCausedFocus" boolean value in the "stopped" events.
+ g_vsc.focus_tid = thread.GetThreadID();
+ thread.StepOut();
+ } else {
+ response.try_emplace("success", false);
+ }
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "ThreadsRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Thread request; value of command field is 'threads'. The
+// request retrieves a list of all threads.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "threads" ]
+// }
+// },
+// "required": [ "command" ]
+// }]
+// },
+// "ThreadsResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'threads' request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "threads": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/Thread"
+// },
+// "description": "All threads."
+// }
+// },
+// "required": [ "threads" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+void request_threads(const llvm::json::Object &request) {
+
+ lldb::SBProcess process = g_vsc.target.GetProcess();
+ llvm::json::Object response;
+ FillResponse(request, response);
+
+ const uint32_t num_threads = process.GetNumThreads();
+ llvm::json::Array threads;
+ for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
+ lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
+ threads.emplace_back(CreateThread(thread));
+ }
+ if (threads.size() == 0) {
+ response.try_emplace("success", false);
+ }
+ llvm::json::Object body;
+ body.try_emplace("threads", std::move(threads));
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "SetVariableRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "setVariable request; value of command field is
+// 'setVariable'. Set the variable with the given name in the variable
+// container to a new value.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "setVariable" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/SetVariableArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "SetVariableArguments": {
+// "type": "object",
+// "description": "Arguments for 'setVariable' request.",
+// "properties": {
+// "variablesReference": {
+// "type": "integer",
+// "description": "The reference of the variable container."
+// },
+// "name": {
+// "type": "string",
+// "description": "The name of the variable."
+// },
+// "value": {
+// "type": "string",
+// "description": "The value of the variable."
+// },
+// "format": {
+// "$ref": "#/definitions/ValueFormat",
+// "description": "Specifies details on how to format the response value."
+// }
+// },
+// "required": [ "variablesReference", "name", "value" ]
+// },
+// "SetVariableResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'setVariable' request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "value": {
+// "type": "string",
+// "description": "The new value of the variable."
+// },
+// "type": {
+// "type": "string",
+// "description": "The type of the new value. Typically shown in the
+// UI when hovering over the value."
+// },
+// "variablesReference": {
+// "type": "number",
+// "description": "If variablesReference is > 0, the new value is
+// structured and its children can be retrieved by passing
+// variablesReference to the VariablesRequest."
+// },
+// "namedVariables": {
+// "type": "number",
+// "description": "The number of named child variables. The client
+// can use this optional information to present the variables in a
+// paged UI and fetch them in chunks."
+// },
+// "indexedVariables": {
+// "type": "number",
+// "description": "The number of indexed child variables. The client
+// can use this optional information to present the variables in a
+// paged UI and fetch them in chunks."
+// }
+// },
+// "required": [ "value" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+void request_setVariable(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ llvm::json::Array variables;
+ llvm::json::Object body;
+ auto arguments = request.getObject("arguments");
+ // This is a reference to the containing variable/scope
+ const auto variablesReference =
+ GetUnsigned(arguments, "variablesReference", 0);
+ const auto name = GetString(arguments, "name");
+ const auto value = GetString(arguments, "value");
+ // Set success to false just in case we don't find the variable by name
+ response.try_emplace("success", false);
+
+ lldb::SBValue variable;
+ int64_t newVariablesReference = 0;
+
+ // The "id" is the unique integer ID that is unique within the enclosing
+ // variablesReference. It is optionally added to any "interface Variable"
+ // objects to uniquely identify a variable within an enclosing
+ // variablesReference. It helps to disambiguate between two variables that
+ // have the same name within the same scope since the "setVariables" request
+ // only specifies the variable reference of the enclosing scope/variable, and
+ // the name of the variable. We could have two shadowed variables with the
+ // same name in "Locals" or "Globals". In our case the "id" absolute index
+ // of the variable within the g_vsc.variables list.
+ const auto id_value = GetUnsigned(arguments, "id", UINT64_MAX);
+ if (id_value != UINT64_MAX) {
+ variable = g_vsc.variables.GetValueAtIndex(id_value);
+ } else if (VARREF_IS_SCOPE(variablesReference)) {
+ // variablesReference is one of our scopes, not an actual variable it is
+ // asking for a variable in locals or globals or registers
+ int64_t start_idx = 0;
+ int64_t end_idx = 0;
+ switch (variablesReference) {
+ case VARREF_LOCALS:
+ start_idx = 0;
+ end_idx = start_idx + g_vsc.num_locals;
+ break;
+ case VARREF_GLOBALS:
+ start_idx = g_vsc.num_locals;
+ end_idx = start_idx + g_vsc.num_globals;
+ break;
+ case VARREF_REGS:
+ start_idx = g_vsc.num_locals + g_vsc.num_globals;
+ end_idx = start_idx + g_vsc.num_regs;
+ break;
+ default:
+ break;
+ }
+
+ // Find the variable by name in the correct scope and hope we don't have
+ // multiple variables with the same name. We search backwards because
+ // the list of variables has the top most variables first and variables
+ // in deeper scopes are last. This means we will catch the deepest
+ // variable whose name matches which is probably what the user wants.
+ for (int64_t i = end_idx - 1; i >= start_idx; --i) {
+ auto curr_variable = g_vsc.variables.GetValueAtIndex(i);
+ llvm::StringRef variable_name(curr_variable.GetName());
+ if (variable_name == name) {
+ variable = curr_variable;
+ if (curr_variable.MightHaveChildren())
+ newVariablesReference = i;
+ break;
+ }
+ }
+ } else {
+ // We have a named item within an actual variable so we need to find it
+ // withing the container variable by name.
+ const int64_t var_idx = VARREF_TO_VARIDX(variablesReference);
+ lldb::SBValue container = g_vsc.variables.GetValueAtIndex(var_idx);
+ variable = container.GetChildMemberWithName(name.data());
+ if (!variable.IsValid()) {
+ if (name.startswith("[")) {
+ llvm::StringRef index_str(name.drop_front(1));
+ uint64_t index = 0;
+ if (!index_str.consumeInteger(0, index)) {
+ if (index_str == "]")
+ variable = container.GetChildAtIndex(index);
+ }
+ }
+ }
+
+ // We don't know the index of the variable in our g_vsc.variables
+ if (variable.IsValid()) {
+ if (variable.MightHaveChildren()) {
+ newVariablesReference = VARIDX_TO_VARREF(g_vsc.variables.GetSize());
+ g_vsc.variables.Append(variable);
+ }
+ }
+ }
+
+ if (variable.IsValid()) {
+ lldb::SBError error;
+ bool success = variable.SetValueFromCString(value.data(), error);
+ if (success) {
+ SetValueForKey(variable, body, "value");
+ EmplaceSafeString(body, "type", variable.GetType().GetDisplayTypeName());
+ body.try_emplace("variablesReference", newVariablesReference);
+ } else {
+ EmplaceSafeString(body, "message", std::string(error.GetCString()));
+ }
+ response.try_emplace("success", success);
+ }
+
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+//----------------------------------------------------------------------
+// "VariablesRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Variables request; value of command field is 'variables'.
+// Retrieves all child variables for the given variable reference. An
+// optional filter can be used to limit the fetched children to either named
+// or indexed children.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "variables" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/VariablesArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "VariablesArguments": {
+// "type": "object",
+// "description": "Arguments for 'variables' request.",
+// "properties": {
+// "variablesReference": {
+// "type": "integer",
+// "description": "The Variable reference."
+// },
+// "filter": {
+// "type": "string",
+// "enum": [ "indexed", "named" ],
+// "description": "Optional filter to limit the child variables to either
+// named or indexed. If ommited, both types are fetched."
+// },
+// "start": {
+// "type": "integer",
+// "description": "The index of the first variable to return; if omitted
+// children start at 0."
+// },
+// "count": {
+// "type": "integer",
+// "description": "The number of variables to return. If count is missing
+// or 0, all variables are returned."
+// },
+// "format": {
+// "$ref": "#/definitions/ValueFormat",
+// "description": "Specifies details on how to format the Variable
+// values."
+// }
+// },
+// "required": [ "variablesReference" ]
+// },
+// "VariablesResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'variables' request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "variables": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/Variable"
+// },
+// "description": "All (or a range) of variables for the given
+// variable reference."
+// }
+// },
+// "required": [ "variables" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+//----------------------------------------------------------------------
+void request_variables(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ llvm::json::Array variables;
+ auto arguments = request.getObject("arguments");
+ const auto variablesReference =
+ GetUnsigned(arguments, "variablesReference", 0);
+ const int64_t start = GetSigned(arguments, "start", 0);
+ const int64_t count = GetSigned(arguments, "count", 0);
+ bool hex = false;
+ auto format = arguments->getObject("format");
+ if (format)
+ hex = GetBoolean(format, "hex", false);
+
+ if (VARREF_IS_SCOPE(variablesReference)) {
+ // variablesReference is one of our scopes, not an actual variable it is
+ // asking for the list of args, locals or globals.
+ int64_t start_idx = 0;
+ int64_t num_children = 0;
+ switch (variablesReference) {
+ case VARREF_LOCALS:
+ start_idx = start;
+ num_children = g_vsc.num_locals;
+ break;
+ case VARREF_GLOBALS:
+ start_idx = start + g_vsc.num_locals + start;
+ num_children = g_vsc.num_globals;
+ break;
+ case VARREF_REGS:
+ start_idx = start + g_vsc.num_locals + g_vsc.num_globals;
+ num_children = g_vsc.num_regs;
+ break;
+ default:
+ break;
+ }
+ const int64_t end_idx = start_idx + ((count == 0) ? num_children : count);
+ for (auto i = start_idx; i < end_idx; ++i) {
+ lldb::SBValue variable = g_vsc.variables.GetValueAtIndex(i);
+ if (!variable.IsValid())
+ break;
+ variables.emplace_back(
+ CreateVariable(variable, VARIDX_TO_VARREF(i), i, hex));
+ }
+ } else {
+ // We are expanding a variable that has children, so we will return its
+ // children.
+ const int64_t var_idx = VARREF_TO_VARIDX(variablesReference);
+ lldb::SBValue variable = g_vsc.variables.GetValueAtIndex(var_idx);
+ if (variable.IsValid()) {
+ const auto num_children = variable.GetNumChildren();
+ const int64_t end_idx = start + ((count == 0) ? num_children : count);
+ for (auto i = start; i < end_idx; ++i) {
+ lldb::SBValue child = variable.GetChildAtIndex(i);
+ if (!child.IsValid())
+ break;
+ if (child.MightHaveChildren()) {
+ const int64_t var_idx = g_vsc.variables.GetSize();
+ auto childVariablesReferences = VARIDX_TO_VARREF(var_idx);
+ variables.emplace_back(
+ CreateVariable(child, childVariablesReferences, var_idx, hex));
+ g_vsc.variables.Append(child);
+ } else {
+ variables.emplace_back(CreateVariable(child, 0, INT64_MAX, hex));
+ }
+ }
+ }
+ }
+ llvm::json::Object body;
+ body.try_emplace("variables", std::move(variables));
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+// A request used in testing to get the details on all breakpoints that are
+// currently set in the target. This helps us to test "setBreakpoints" and
+// "setFunctionBreakpoints" requests to verify we have the correct set of
+// breakpoints currently set in LLDB.
+void request__testGetTargetBreakpoints(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ llvm::json::Array response_breakpoints;
+ for (uint32_t i = 0; g_vsc.target.GetBreakpointAtIndex(i).IsValid(); ++i) {
+ auto bp = g_vsc.target.GetBreakpointAtIndex(i);
+ AppendBreakpoint(bp, response_breakpoints);
+ }
+ llvm::json::Object body;
+ body.try_emplace("breakpoints", std::move(response_breakpoints));
+ response.try_emplace("body", std::move(body));
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+const std::map<std::string, RequestCallback> &GetRequestHandlers() {
+#define REQUEST_CALLBACK(name) \
+ { #name, request_##name }
+ static std::map<std::string, RequestCallback> g_request_handlers = {
+ // VSCode Debug Adaptor requests
+ REQUEST_CALLBACK(attach),
+ REQUEST_CALLBACK(continue),
+ REQUEST_CALLBACK(configurationDone),
+ REQUEST_CALLBACK(disconnect),
+ REQUEST_CALLBACK(evaluate),
+ REQUEST_CALLBACK(exceptionInfo),
+ REQUEST_CALLBACK(initialize),
+ REQUEST_CALLBACK(launch),
+ REQUEST_CALLBACK(next),
+ REQUEST_CALLBACK(pause),
+ REQUEST_CALLBACK(scopes),
+ REQUEST_CALLBACK(setBreakpoints),
+ REQUEST_CALLBACK(setExceptionBreakpoints),
+ REQUEST_CALLBACK(setFunctionBreakpoints),
+ REQUEST_CALLBACK(setVariable),
+ REQUEST_CALLBACK(source),
+ REQUEST_CALLBACK(stackTrace),
+ REQUEST_CALLBACK(stepIn),
+ REQUEST_CALLBACK(stepOut),
+ REQUEST_CALLBACK(threads),
+ REQUEST_CALLBACK(variables),
+ // Testing requests
+ REQUEST_CALLBACK(_testGetTargetBreakpoints),
+ };
+#undef REQUEST_CALLBACK
+ return g_request_handlers;
+}
+
+} // anonymous namespace
+
+int main(int argc, char *argv[]) {
+
+ // Initialize LLDB first before we do anything.
+ lldb::SBDebugger::Initialize();
+
+ if (argc == 2) {
+ const char *arg = argv[1];
+#if !defined(_WIN32)
+ if (strcmp(arg, "-g") == 0) {
+ printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid());
+ pause();
+ } else {
+#else
+ {
+#endif
+ int portno = atoi(arg);
+ printf("Listening on port %i...\n", portno);
+ int socket_fd = AcceptConnection(portno);
+ if (socket_fd >= 0) {
+ // We must open two FILE objects, one for reading and one for writing
+ // the FILE objects have a mutex in them that won't allow reading and
+ // writing to the socket stream.
+ g_vsc.in = fdopen(socket_fd, "r");
+ g_vsc.out = fdopen(socket_fd, "w");
+ if (g_vsc.in == nullptr || g_vsc.out == nullptr) {
+ if (g_vsc.log)
+ *g_vsc.log << "fdopen failed (" << strerror(errno) << ")"
+ << std::endl;
+ exit(1);
+ }
+ } else {
+ exit(1);
+ }
+ }
+ }
+ auto request_handlers = GetRequestHandlers();
+ uint32_t packet_idx = 0;
+ while (true) {
+ std::string json = g_vsc.ReadJSON();
+ if (json.empty())
+ break;
+
+ llvm::StringRef json_sref(json);
+ llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
+ if (!json_value) {
+ auto error = json_value.takeError();
+ if (g_vsc.log) {
+ std::string error_str;
+ llvm::raw_string_ostream strm(error_str);
+ strm << error;
+ strm.flush();
+
+ *g_vsc.log << "error: failed to parse JSON: " << error_str << std::endl
+ << json << std::endl;
+ }
+ return 1;
+ }
+
+ auto object = json_value->getAsObject();
+ if (!object) {
+ if (g_vsc.log)
+ *g_vsc.log << "error: json packet isn't a object" << std::endl;
+ return 1;
+ }
+
+ const auto packet_type = GetString(object, "type");
+ if (packet_type == "request") {
+ const auto command = GetString(object, "command");
+ auto handler_pos = request_handlers.find(command);
+ if (handler_pos != request_handlers.end()) {
+ handler_pos->second(*object);
+ } else {
+ if (g_vsc.log)
+ *g_vsc.log << "error: unhandled command \"" << command.data() << std::endl;
+ return 1;
+ }
+ }
+ ++packet_idx;
+ }
+
+ // We must terminate the debugger in a thread before the C++ destructor
+ // chain messes everything up.
+ lldb::SBDebugger::Terminate();
+ return 0;
+}
diff --git a/tools/lldb-vscode/package.json b/tools/lldb-vscode/package.json
new file mode 100644
index 000000000000..aa3de65c172f
--- /dev/null
+++ b/tools/lldb-vscode/package.json
@@ -0,0 +1,242 @@
+{
+ "name": "lldb-vscode",
+ "displayName": "LLDB native Debug stub",
+ "version": "0.1.0",
+ "publisher": "llvm.org",
+ "description": "Debug adapter for LLDB which uses a C++ tool to interface directly with LLDB.",
+ "author": {
+ "name": "Greg Clayton",
+ "email": "clayborg@gmail.com"
+ },
+ "license": "LLVM",
+ "keywords": [
+ "multi-root ready"
+ ],
+ "engines": {
+ "vscode": "^1.18.0",
+ "node": "^7.9.0"
+ },
+ "icon": "images/lldb.png",
+ "categories": [
+ "Debuggers"
+ ],
+ "private": true,
+ "devDependencies": {
+ "@types/node": "7.0.43",
+ "@types/mocha": "2.2.45",
+ "typescript": "2.6.2",
+ "mocha": "4.0.1",
+ "vscode": "1.1.10",
+ "vscode-debugadapter-testsupport": "1.25.0",
+ "tslint": "5.8.0",
+ "vsce": "1.35.0"
+ },
+ "contributes": {
+ "debuggers": [
+ {
+ "type": "lldb-vscode",
+ "label": "Native LLDB Debugger",
+ "enableBreakpointsFor": {
+ "languageIds": [
+ "ada",
+ "arm",
+ "asm",
+ "c",
+ "cpp",
+ "crystal",
+ "d",
+ "fortan",
+ "fortran-modern",
+ "nim",
+ "objective-c",
+ "objectpascal",
+ "pascal",
+ "rust",
+ "swift"
+ ]
+ },
+ "program": "./bin/lldb-vscode",
+ "configurationAttributes": {
+ "launch": {
+ "required": [
+ "program"
+ ],
+ "properties": {
+ "program": {
+ "type": "string",
+ "description": "Path to the program to debug."
+ },
+ "args": {
+ "type": [ "array", "string" ],
+ "description": "Program arguments.",
+ "default": []
+ },
+ "cwd": {
+ "type": "string",
+ "description": "Program working directory.",
+ "default": "${workspaceRoot}"
+ },
+ "env": {
+ "type": "array",
+ "description": "Additional environment variables.",
+ "default": []
+ },
+ "stopOnEntry": {
+ "type": "boolean",
+ "description": "Automatically stop after launch.",
+ "default": false
+ },
+ "disableASLR": {
+ "type": "boolean",
+ "description": "Enable or disable Address space layout randomization if the debugger supports it.",
+ "default": true
+ },
+ "disableSTDIO": {
+ "type": "boolean",
+ "description": "Don't retrieve STDIN, STDOUT and STDERR as the program is running.",
+ "default": false
+ },
+ "shellExpandArguments": {
+ "type": "boolean",
+ "description": "Expand program arguments as a shell would without actually launching the program in a shell.",
+ "default": false
+ },
+ "detachOnError": {
+ "type": "boolean",
+ "description": "Detach from the program.",
+ "default": false
+ },
+ "trace": {
+ "type": "boolean",
+ "description": "Enable logging of the Debug Adapter Protocol.",
+ "default": true
+ },
+ "sourcePath": {
+ "type": "string",
+ "description": "Specify a source path to remap \"./\" to allow full paths to be used when setting breakpoints in binaries that have relative source paths."
+ },
+ "sourceMap": {
+ "type": "array",
+ "description": "Specify an array of path remappings; each element must itself be a two element array containing a source and desination pathname. Overrides sourcePath.",
+ "default": []
+ },
+ "debuggerRoot": {
+ "type": "string",
+ "description": "Specify a working directory to set the debug adaptor to so relative object files can be located."
+ },
+ "initCommands": {
+ "type": "array",
+ "description": "Initialization commands executed upon debugger startup.",
+ "default": []
+ },
+ "preRunCommands": {
+ "type": "array",
+ "description": "Commands executed just before the program is launched.",
+ "default": []
+ },
+ "stopCommands": {
+ "type": "array",
+ "description": "Commands executed each time the program stops.",
+ "default": []
+ },
+ "exitCommands": {
+ "type": "array",
+ "description": "Commands executed at the end of debugging session.",
+ "default": []
+ }
+ }
+ },
+ "attach": {
+ "properties": {
+ "program": {
+ "type": "string",
+ "description": "Path to the program to attach to."
+ },
+ "pid": {
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "System process ID to attach to."
+ },
+ "waitFor": {
+ "type": "boolean",
+ "description": "If set to true, then wait for the process to launch by looking for a process with a basename that matches `program`. No process ID needs to be specified when using this flag.",
+ "default": true
+ },
+ "trace": {
+ "type": "boolean",
+ "description": "Enable logging of the Debug Adapter Protocol.",
+ "default": true
+ },
+ "sourcePath": {
+ "type": "string",
+ "description": "Specify a source path to remap \"./\" to allow full paths to be used when setting breakpoints in binaries that have relative source paths."
+ },
+ "sourceMap": {
+ "type": "array",
+ "description": "Specify an array of path remappings; each element must itself be a two element array containing a source and desination pathname. Overrides sourcePath.",
+ "default": []
+ },
+ "debuggerRoot": {
+ "type": "string",
+ "description": "Specify a working directory to set the debug adaptor to so relative object files can be located."
+ },
+ "attachCommands": {
+ "type": "array",
+ "description": "Custom commands that are executed instead of attaching to a process ID or to a process by name. These commands may optionally create a new target and must perform an attach. A valid process must exist after these commands complete or the \"attach\" will fail.",
+ "default": []
+ },
+ "initCommands": {
+ "type": "array",
+ "description": "Initialization commands executed upon debugger startup.",
+ "default": []
+ },
+ "preRunCommands": {
+ "type": "array",
+ "description": "Commands executed just before the program is attached to.",
+ "default": []
+ },
+ "stopCommands": {
+ "type": "array",
+ "description": "Commands executed each time the program stops.",
+ "default": []
+ },
+ "exitCommands": {
+ "type": "array",
+ "description": "Commands executed at the end of debugging session.",
+ "default": []
+ }
+ }
+ }
+ },
+ "initialConfigurations": [
+ {
+ "type": "lldb-vscode",
+ "request": "launch",
+ "name": "Debug",
+ "program": "${workspaceRoot}/<your program>",
+ "args": [],
+ "env": [],
+ "cwd": "${workspaceRoot}"
+ }
+ ],
+ "configurationSnippets": [
+ {
+ "label": "LLDB: Launch",
+ "description": "",
+ "body": {
+ "type": "lldb-vscode",
+ "request": "launch",
+ "name": "${2:Launch}",
+ "program": "^\"\\${workspaceRoot}/${1:<your program>}\"",
+ "args": [],
+ "env": [],
+ "cwd": "^\"\\${workspaceRoot}\""
+ }
+ }
+ ]
+ }
+ ]
+ }
+}