aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-06-26 20:33:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-06-26 20:33:56 +0000
commitfdea456ad833fbab0d3a296a58250950f11a498c (patch)
tree3db481072633e348326ee97c01d69518ed66b145
parent4befb1f96d641a958548654b2c3b674f0ce8404c (diff)
downloadsrc-fdea456ad833fbab0d3a296a58250950f11a498c.tar.gz
src-fdea456ad833fbab0d3a296a58250950f11a498c.zip
Vendor import of lldb trunk r306325:vendor/lldb/lldb-trunk-r306325
Notes
Notes: svn path=/vendor/lldb/dist/; revision=320384 svn path=/vendor/lldb/lldb-trunk-r306325/; revision=320385; tag=vendor/lldb/lldb-trunk-r306325
-rw-r--r--include/lldb/Host/Host.h55
-rw-r--r--include/lldb/Host/common/NativeProcessProtocol.h13
-rw-r--r--include/lldb/Host/posix/ProcessLauncherPosix.h24
-rw-r--r--include/lldb/lldb-enumerations.h2
-rw-r--r--include/lldb/lldb-private-enumerations.h13
-rw-r--r--lldb.xcodeproj/project.pbxproj28
-rw-r--r--packages/Python/lldbsuite/test/decorators.py47
-rw-r--r--packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py15
-rw-r--r--packages/Python/lldbsuite/test/functionalities/ubsan/basic/Makefile6
-rw-r--r--packages/Python/lldbsuite/test/functionalities/ubsan/basic/TestUbsanBasic.py90
-rw-r--r--packages/Python/lldbsuite/test/functionalities/ubsan/basic/main.c4
-rw-r--r--packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py4
-rw-r--r--scripts/Python/python-wrapper.swig3
-rw-r--r--source/API/SBThread.cpp4
-rw-r--r--source/API/SystemInitializerFull.cpp10
-rw-r--r--source/Commands/CommandObjectFrame.cpp46
-rw-r--r--source/Core/IOHandler.cpp2
-rw-r--r--source/Core/Mangled.cpp2
-rw-r--r--source/Core/Timer.cpp44
-rw-r--r--source/Host/CMakeLists.txt6
-rw-r--r--source/Host/common/Host.cpp423
-rw-r--r--source/Host/common/NativeProcessProtocol.cpp38
-rw-r--r--source/Host/macosx/Host.mm299
-rw-r--r--source/Host/posix/ProcessLauncherPosix.cpp34
-rw-r--r--source/Host/posix/ProcessLauncherPosixFork.cpp8
-rw-r--r--source/Host/windows/Host.cpp13
-rw-r--r--source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp6
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp31
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h6
-rw-r--r--source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp (renamed from source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp)11
-rw-r--r--source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h (renamed from source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h)0
-rw-r--r--source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt (renamed from source/Plugins/InstrumentationRuntime/AddressSanitizer/CMakeLists.txt)4
-rw-r--r--source/Plugins/InstrumentationRuntime/CMakeLists.txt6
-rw-r--r--source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt13
-rw-r--r--source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp273
-rw-r--r--source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h68
-rw-r--r--source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt (renamed from source/Plugins/InstrumentationRuntime/ThreadSanitizer/CMakeLists.txt)4
-rw-r--r--source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp (renamed from source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp)9
-rw-r--r--source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h (renamed from source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h)0
-rw-r--r--source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt13
-rw-r--r--source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp340
-rw-r--r--source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h69
-rw-r--r--source/Plugins/Language/ObjC/Cocoa.cpp116
-rw-r--r--source/Plugins/Language/ObjC/NSArray.cpp280
-rw-r--r--source/Plugins/Language/ObjC/NSDictionary.cpp230
-rw-r--r--source/Plugins/Language/ObjC/ObjCLanguage.cpp5
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp101
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.h16
-rw-r--r--source/Plugins/Process/Darwin/NativeProcessDarwin.cpp19
-rw-r--r--source/Plugins/Process/Linux/NativeProcessLinux.cpp74
-rw-r--r--source/Plugins/Process/Linux/NativeProcessLinux.h2
-rw-r--r--source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp71
-rw-r--r--source/Plugins/Process/NetBSD/NativeProcessNetBSD.h2
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp50
-rw-r--r--unittests/Host/CMakeLists.txt1
-rw-r--r--unittests/Host/HostTest.cpp22
-rw-r--r--unittests/Process/gdb-remote/CMakeLists.txt3
-rw-r--r--unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp212
-rw-r--r--unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp109
-rw-r--r--unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp31
-rw-r--r--unittests/Process/gdb-remote/GDBRemoteTestUtils.h7
-rw-r--r--unittests/tools/lldb-server/tests/TestClient.cpp1
62 files changed, 2268 insertions, 1170 deletions
diff --git a/include/lldb/Host/Host.h b/include/lldb/Host/Host.h
index c474dccab5db..bf48e207f1f2 100644
--- a/include/lldb/Host/Host.h
+++ b/include/lldb/Host/Host.h
@@ -29,6 +29,27 @@ class FileAction;
class ProcessLaunchInfo;
//----------------------------------------------------------------------
+// Exit Type for inferior processes
+//----------------------------------------------------------------------
+struct WaitStatus {
+ enum Type : uint8_t {
+ Exit, // The status represents the return code from normal
+ // program exit (i.e. WIFEXITED() was true)
+ Signal, // The status represents the signal number that caused
+ // the program to exit (i.e. WIFSIGNALED() was true)
+ Stop, // The status represents the signal number that caused the
+ // program to stop (i.e. WIFSTOPPED() was true)
+ };
+
+ Type type;
+ uint8_t status;
+
+ WaitStatus(Type type, uint8_t status) : type(type), status(status) {}
+
+ static WaitStatus Decode(int wstatus);
+};
+
+//----------------------------------------------------------------------
/// @class Host Host.h "lldb/Host/Host.h"
/// @brief A class that provides host computer information.
///
@@ -111,15 +132,6 @@ public:
static const char *GetSignalAsCString(int signo);
- typedef void (*ThreadLocalStorageCleanupCallback)(void *p);
-
- static lldb::thread_key_t
- ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback);
-
- static void *ThreadLocalStorageGet(lldb::thread_key_t key);
-
- static void ThreadLocalStorageSet(lldb::thread_key_t key, void *value);
-
//------------------------------------------------------------------
/// Given an address in the current process (the process that
/// is running the LLDB code), return the name of the module that
@@ -184,22 +196,6 @@ public:
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info);
-#if (defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || \
- defined(__GLIBC__) || defined(__NetBSD__) || defined(__OpenBSD__)) && \
- !defined(__ANDROID__)
-
- static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info);
-
- static Status LaunchProcessPosixSpawn(const char *exe_path,
- const ProcessLaunchInfo &launch_info,
- lldb::pid_t &pid);
-
- static bool AddPosixSpawnFileAction(void *file_actions,
- const FileAction *info, Log *log,
- Status &error);
-
-#endif
-
static const lldb::UnixSignalsSP &GetUnixSignals();
static Status LaunchProcess(ProcessLaunchInfo &launch_info);
@@ -246,5 +242,14 @@ public:
} // namespace lldb_private
+namespace llvm {
+template <> struct format_provider<lldb_private::WaitStatus> {
+ /// Options = "" gives a human readable description of the status
+ /// Options = "g" gives a gdb-remote protocol status (e.g., X09)
+ static void format(const lldb_private::WaitStatus &WS, raw_ostream &OS,
+ llvm::StringRef Options);
+};
+} // namespace llvm
+
#endif // #if defined(__cplusplus)
#endif // liblldb_Host_h_
diff --git a/include/lldb/Host/common/NativeProcessProtocol.h b/include/lldb/Host/common/NativeProcessProtocol.h
index 55eca0fa0b65..c43299a1df3d 100644
--- a/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/include/lldb/Host/common/NativeProcessProtocol.h
@@ -11,6 +11,7 @@
#define liblldb_NativeProcessProtocol_h_
#include "lldb/Core/TraceOptions.h"
+#include "lldb/Host/Host.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-forward.h"
@@ -158,12 +159,9 @@ public:
//----------------------------------------------------------------------
// Exit Status
//----------------------------------------------------------------------
- virtual bool GetExitStatus(lldb_private::ExitType *exit_type, int *status,
- std::string &exit_description);
+ virtual llvm::Optional<WaitStatus> GetExitStatus();
- virtual bool SetExitStatus(lldb_private::ExitType exit_type, int status,
- const char *exit_description,
- bool bNotifyStateChange);
+ virtual bool SetExitStatus(WaitStatus status, bool bNotifyStateChange);
//----------------------------------------------------------------------
// Access to threads
@@ -421,9 +419,8 @@ protected:
lldb::StateType m_state;
mutable std::recursive_mutex m_state_mutex;
- lldb_private::ExitType m_exit_type;
- int m_exit_status;
- std::string m_exit_description;
+ llvm::Optional<WaitStatus> m_exit_status;
+
std::recursive_mutex m_delegates_mutex;
std::vector<NativeDelegate *> m_delegates;
NativeBreakpointList m_breakpoint_list;
diff --git a/include/lldb/Host/posix/ProcessLauncherPosix.h b/include/lldb/Host/posix/ProcessLauncherPosix.h
deleted file mode 100644
index 4800c4066049..000000000000
--- a/include/lldb/Host/posix/ProcessLauncherPosix.h
+++ /dev/null
@@ -1,24 +0,0 @@
-//===-- ProcessLauncherPosix.h ----------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef lldb_Host_posix_ProcessLauncherPosix_h_
-#define lldb_Host_posix_ProcessLauncherPosix_h_
-
-#include "lldb/Host/ProcessLauncher.h"
-
-namespace lldb_private {
-
-class ProcessLauncherPosix : public ProcessLauncher {
-public:
- HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info,
- Status &error) override;
-};
-}
-
-#endif
diff --git a/include/lldb/lldb-enumerations.h b/include/lldb/lldb-enumerations.h
index f62b3cc0b19b..3c60873f6796 100644
--- a/include/lldb/lldb-enumerations.h
+++ b/include/lldb/lldb-enumerations.h
@@ -454,6 +454,8 @@ enum LanguageType {
enum InstrumentationRuntimeType {
eInstrumentationRuntimeTypeAddressSanitizer = 0x0000,
eInstrumentationRuntimeTypeThreadSanitizer = 0x0001,
+ eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer = 0x0002,
+ eInstrumentationRuntimeTypeMainThreadChecker = 0x0003,
eNumInstrumentationRuntimeTypes
};
diff --git a/include/lldb/lldb-private-enumerations.h b/include/lldb/lldb-private-enumerations.h
index 332265665237..983ddf3d23d6 100644
--- a/include/lldb/lldb-private-enumerations.h
+++ b/include/lldb/lldb-private-enumerations.h
@@ -212,19 +212,6 @@ enum class LineStatus {
};
//----------------------------------------------------------------------
-// Exit Type for inferior processes
-//----------------------------------------------------------------------
-typedef enum ExitType {
- eExitTypeInvalid,
- eExitTypeExit, // The exit status represents the return code from normal
- // program exit (i.e. WIFEXITED() was true)
- eExitTypeSignal, // The exit status represents the signal number that caused
- // the program to exit (i.e. WIFSIGNALED() was true)
- eExitTypeStop, // The exit status represents the stop signal that caused the
- // program to exit (i.e. WIFSTOPPED() was true)
-} ExitType;
-
-//----------------------------------------------------------------------
// Boolean result of running a Type Validator
//----------------------------------------------------------------------
enum class TypeValidatorResult : bool { Success = true, Failure = false };
diff --git a/lldb.xcodeproj/project.pbxproj b/lldb.xcodeproj/project.pbxproj
index a01a1798ce9a..f4c5c7a0e842 100644
--- a/lldb.xcodeproj/project.pbxproj
+++ b/lldb.xcodeproj/project.pbxproj
@@ -744,6 +744,7 @@
4CF3D80C15AF4DC800845BF3 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDB919B414F6F10D008FF64B /* Security.framework */; };
4CF52AF51428291E0051E832 /* SBFileSpecList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CF52AF41428291E0051E832 /* SBFileSpecList.h */; settings = {ATTRIBUTES = (Public, ); }; };
4CF52AF8142829390051E832 /* SBFileSpecList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CF52AF7142829390051E832 /* SBFileSpecList.cpp */; };
+ 54067BF11DF2041B00749AA5 /* UndefinedBehaviorSanitizerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 54067BEC1DF2034B00749AA5 /* UndefinedBehaviorSanitizerRuntime.cpp */; };
6D0F61431C80AAAE00A4ECEE /* JavaASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0F61411C80AAAA00A4ECEE /* JavaASTContext.cpp */; };
6D0F61481C80AAD600A4ECEE /* DWARFASTParserJava.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0F61441C80AACF00A4ECEE /* DWARFASTParserJava.cpp */; };
6D0F614E1C80AB0700A4ECEE /* JavaLanguageRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0F614A1C80AB0400A4ECEE /* JavaLanguageRuntime.cpp */; };
@@ -766,6 +767,7 @@
8C26C4261C3EA5F90031DF7C /* ThreadSanitizerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C26C4241C3EA4340031DF7C /* ThreadSanitizerRuntime.cpp */; };
8C2D6A53197A1EAF006989C9 /* MemoryHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */; };
8C2D6A5E197A250F006989C9 /* MemoryHistoryASan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */; };
+ 8C3BD9961EF45DA50016C343 /* MainThreadCheckerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */; };
8CCB017E19BA28A80009FD44 /* ThreadCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CCB017A19BA283D0009FD44 /* ThreadCollection.cpp */; };
8CCB018219BA4E270009FD44 /* SBThreadCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CCB018119BA4E210009FD44 /* SBThreadCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
8CCB018319BA51BF0009FD44 /* SBThreadCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CCB017F19BA4DD00009FD44 /* SBThreadCollection.cpp */; };
@@ -2576,6 +2578,8 @@
4CEDAED311754F5E00E875A6 /* ThreadPlanStepUntil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepUntil.h; path = include/lldb/Target/ThreadPlanStepUntil.h; sourceTree = "<group>"; };
4CF52AF41428291E0051E832 /* SBFileSpecList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBFileSpecList.h; path = include/lldb/API/SBFileSpecList.h; sourceTree = "<group>"; };
4CF52AF7142829390051E832 /* SBFileSpecList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBFileSpecList.cpp; path = source/API/SBFileSpecList.cpp; sourceTree = "<group>"; };
+ 54067BEC1DF2034B00749AA5 /* UndefinedBehaviorSanitizerRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = UndefinedBehaviorSanitizerRuntime.cpp; path = UndefinedBehaviorSanitizer/UndefinedBehaviorSanitizerRuntime.cpp; sourceTree = "<group>"; };
+ 54067BED1DF2034B00749AA5 /* UndefinedBehaviorSanitizerRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UndefinedBehaviorSanitizerRuntime.h; path = UndefinedBehaviorSanitizer/UndefinedBehaviorSanitizerRuntime.h; sourceTree = "<group>"; };
69A01E1C1236C5D400C660B5 /* Host.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Host.cpp; sourceTree = "<group>"; };
69A01E1F1236C5D400C660B5 /* Symbols.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Symbols.cpp; sourceTree = "<group>"; };
6D0F613C1C80AA8900A4ECEE /* DebugMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DebugMacros.h; path = include/lldb/Symbol/DebugMacros.h; sourceTree = "<group>"; };
@@ -2624,6 +2628,8 @@
8C2D6A54197A1EBE006989C9 /* MemoryHistory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MemoryHistory.h; path = include/lldb/Target/MemoryHistory.h; sourceTree = "<group>"; };
8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryHistoryASan.cpp; sourceTree = "<group>"; };
8C2D6A5B197A1FDC006989C9 /* MemoryHistoryASan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryHistoryASan.h; sourceTree = "<group>"; };
+ 8C3BD9931EF45D9B0016C343 /* MainThreadCheckerRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MainThreadCheckerRuntime.h; sourceTree = "<group>"; };
+ 8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MainThreadCheckerRuntime.cpp; sourceTree = "<group>"; };
8CCB017A19BA283D0009FD44 /* ThreadCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadCollection.cpp; path = source/Target/ThreadCollection.cpp; sourceTree = "<group>"; };
8CCB017C19BA289B0009FD44 /* ThreadCollection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ThreadCollection.h; path = include/lldb/Target/ThreadCollection.h; sourceTree = "<group>"; };
8CCB017F19BA4DD00009FD44 /* SBThreadCollection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SBThreadCollection.cpp; path = source/API/SBThreadCollection.cpp; sourceTree = "<group>"; };
@@ -5912,6 +5918,15 @@
path = "gdb-remote";
sourceTree = "<group>";
};
+ 54067BEA1DF2033700749AA5 /* UndefinedBehaviorSanitizer */ = {
+ isa = PBXGroup;
+ children = (
+ 54067BEC1DF2034B00749AA5 /* UndefinedBehaviorSanitizerRuntime.cpp */,
+ 54067BED1DF2034B00749AA5 /* UndefinedBehaviorSanitizerRuntime.h */,
+ );
+ name = UndefinedBehaviorSanitizer;
+ sourceTree = "<group>";
+ };
69A01E1A1236C5D400C660B5 /* common */ = {
isa = PBXGroup;
children = (
@@ -6011,11 +6026,22 @@
path = asan;
sourceTree = "<group>";
};
+ 8C3BD9911EF45D9B0016C343 /* MainThreadChecker */ = {
+ isa = PBXGroup;
+ children = (
+ 8C3BD9931EF45D9B0016C343 /* MainThreadCheckerRuntime.h */,
+ 8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */,
+ );
+ path = MainThreadChecker;
+ sourceTree = "<group>";
+ };
8CF02ADD19DCBEC200B14BE0 /* InstrumentationRuntime */ = {
isa = PBXGroup;
children = (
+ 54067BEA1DF2033700749AA5 /* UndefinedBehaviorSanitizer */,
8C26C4221C3EA4050031DF7C /* ThreadSanitizer */,
8CF02ADE19DCBEE600B14BE0 /* AddressSanitizer */,
+ 8C3BD9911EF45D9B0016C343 /* MainThreadChecker */,
);
path = InstrumentationRuntime;
sourceTree = "<group>";
@@ -7133,6 +7159,7 @@
2689001213353DDE00698AC0 /* CommandObjectApropos.cpp in Sources */,
4C88BC2A1BA3722B00AA0964 /* Expression.cpp in Sources */,
AE44FB4C1BB4BB540033EB62 /* GoFormatterFunctions.cpp in Sources */,
+ 8C3BD9961EF45DA50016C343 /* MainThreadCheckerRuntime.cpp in Sources */,
23042D121976CA1D00621B2C /* PlatformKalimba.cpp in Sources */,
2689001313353DDE00698AC0 /* CommandObjectArgs.cpp in Sources */,
2689001413353DDE00698AC0 /* CommandObjectBreakpoint.cpp in Sources */,
@@ -7623,6 +7650,7 @@
26954EBE1401EE8B00294D09 /* DynamicRegisterInfo.cpp in Sources */,
6D9AB3DD1BB2B74E003F2289 /* TypeMap.cpp in Sources */,
255EFF761AFABA950069F277 /* LockFilePosix.cpp in Sources */,
+ 54067BF11DF2041B00749AA5 /* UndefinedBehaviorSanitizerRuntime.cpp in Sources */,
3FBA69EC1B6067430008F44A /* PythonDataObjects.cpp in Sources */,
26274FA714030F79006BA130 /* DynamicLoaderDarwinKernel.cpp in Sources */,
94FA3DE01405D50400833217 /* ValueObjectConstResultChild.cpp in Sources */,
diff --git a/packages/Python/lldbsuite/test/decorators.py b/packages/Python/lldbsuite/test/decorators.py
index 866923607867..2a36ee4b3707 100644
--- a/packages/Python/lldbsuite/test/decorators.py
+++ b/packages/Python/lldbsuite/test/decorators.py
@@ -681,6 +681,53 @@ def skipUnlessThreadSanitizer(func):
return None
return skipTestIfFn(is_compiler_clang_with_thread_sanitizer)(func)
+def skipUnlessUndefinedBehaviorSanitizer(func):
+ """Decorate the item to skip test unless -fsanitize=undefined is supported."""
+
+ def is_compiler_clang_with_ubsan(self):
+ # Write out a temp file which exhibits UB.
+ inputf = tempfile.NamedTemporaryFile(suffix='.c')
+ inputf.write('int main() { int x = 0; return x / x; }\n')
+ inputf.flush()
+
+ # We need to write out the object into a named temp file for inspection.
+ outputf = tempfile.NamedTemporaryFile()
+
+ # Try to compile with ubsan turned on.
+ cmd = '%s -fsanitize=undefined %s -o %s' % (self.getCompiler(), inputf.name, outputf.name)
+ if os.popen(cmd).close() is not None:
+ return "Compiler cannot compile with -fsanitize=undefined"
+
+ # Check that we actually see ubsan instrumentation in the binary.
+ cmd = 'nm %s' % outputf.name
+ with os.popen(cmd) as nm_output:
+ if '___ubsan_handle_divrem_overflow' not in nm_output.read():
+ return "Division by zero instrumentation is missing"
+
+ # Find the ubsan dylib.
+ # FIXME: This check should go away once compiler-rt gains support for __ubsan_on_report.
+ cmd = '%s -fsanitize=undefined -x c - -o - -### 2>&1' % self.getCompiler()
+ with os.popen(cmd) as cc_output:
+ driver_jobs = cc_output.read()
+ m = re.search(r'"([^"]+libclang_rt.ubsan_osx_dynamic.dylib)"', driver_jobs)
+ if not m:
+ return "Could not find the ubsan dylib used by the driver"
+ ubsan_dylib = m.group(1)
+
+ # Check that the ubsan dylib has special monitor hooks.
+ cmd = 'nm -gU %s' % ubsan_dylib
+ with os.popen(cmd) as nm_output:
+ syms = nm_output.read()
+ if '___ubsan_on_report' not in syms:
+ return "Missing ___ubsan_on_report"
+ if '___ubsan_get_current_report_data' not in syms:
+ return "Missing ___ubsan_get_current_report_data"
+
+ # OK, this dylib + compiler works for us.
+ return None
+
+ return skipTestIfFn(is_compiler_clang_with_ubsan)(func)
+
def skipUnlessAddressSanitizer(func):
"""Decorate the item to skip test unless Clang -fsanitize=thread is supported."""
diff --git a/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py b/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py
index d0a1728b87e6..bc39d8d7b152 100644
--- a/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py
+++ b/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py
@@ -186,16 +186,27 @@ class ObjCDataFormatterTestCase(TestBase):
def nsnumber_data_formatter_commands(self):
# Now enable AppKit and check we are displaying Cocoa classes correctly
- self.expect('frame variable num1 num2 num3 num4 num5 num6 num7 num9',
+ self.expect('frame variable num1 num2 num3 num5 num6 num7 num9',
substrs=['(NSNumber *) num1 = ', ' (int)5',
'(NSNumber *) num2 = ', ' (float)3.1',
'(NSNumber *) num3 = ', ' (double)3.14',
- '(NSNumber *) num4 = ', ' (long)-2',
'(NSNumber *) num5 = ', ' (char)65',
'(NSNumber *) num6 = ', ' (long)255',
'(NSNumber *) num7 = ', '2000000',
'(NSNumber *) num9 = ', ' (short)-31616'])
+
+ self.runCmd('frame variable num4', check=True)
+ output = self.res.GetOutput()
+ i128_handled_correctly = False
+
+ if output.find('long') >= 0:
+ i128_handled_correctly = (output.find('(long)-2') >= 0)
+ if output.find('int128_t') >= 0:
+ i128_handled_correctly = (output.find('(int128_t)18446744073709551614') >= 0) # deliberately broken, should be ..14
+
+ self.assertTrue(i128_handled_correctly, "Expected valid output for int128_t; got " + output)
+
self.expect('frame variable num_at1 num_at2 num_at3 num_at4',
substrs=['(NSNumber *) num_at1 = ', ' (int)12',
'(NSNumber *) num_at2 = ', ' (int)-12',
diff --git a/packages/Python/lldbsuite/test/functionalities/ubsan/basic/Makefile b/packages/Python/lldbsuite/test/functionalities/ubsan/basic/Makefile
new file mode 100644
index 000000000000..6e7d19b6f48c
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/ubsan/basic/Makefile
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+CFLAGS_EXTRAS := -fsanitize=undefined -g
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/ubsan/basic/TestUbsanBasic.py b/packages/Python/lldbsuite/test/functionalities/ubsan/basic/TestUbsanBasic.py
new file mode 100644
index 000000000000..8dcee97e32f5
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/ubsan/basic/TestUbsanBasic.py
@@ -0,0 +1,90 @@
+"""
+Tests basic UndefinedBehaviorSanitizer support (detecting an alignment error).
+"""
+
+import os
+import time
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+import json
+
+
+class UbsanBasicTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipUnlessUndefinedBehaviorSanitizer
+ def test(self):
+ self.build()
+ self.ubsan_tests()
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ self.line_align = line_number('main.c', '// align line')
+
+ def ubsan_tests(self):
+ # Load the test
+ exe = os.path.join(os.getcwd(), "a.out")
+ self.expect(
+ "file " + exe,
+ patterns=["Current executable set to .*a.out"])
+
+ self.runCmd("run")
+
+ process = self.dbg.GetSelectedTarget().process
+ thread = process.GetSelectedThread()
+ frame = thread.GetSelectedFrame()
+
+ # the stop reason of the thread should be breakpoint.
+ self.expect("thread list", "A ubsan issue should be detected",
+ substrs=['stopped', 'stop reason ='])
+
+ stop_reason = thread.GetStopReason()
+ self.assertEqual(stop_reason, lldb.eStopReasonInstrumentation)
+
+ # test that the UBSan dylib is present
+ self.expect(
+ "image lookup -n __ubsan_on_report",
+ "__ubsan_on_report should be present",
+ substrs=['1 match found'])
+
+ # We should be stopped in __ubsan_on_report
+ self.assertTrue("__ubsan_on_report" in frame.GetFunctionName())
+
+ # The stopped thread backtrace should contain either 'align line'
+ found = False
+ for i in range(thread.GetNumFrames()):
+ frame = thread.GetFrameAtIndex(i)
+ if frame.GetLineEntry().GetFileSpec().GetFilename() == "main.c":
+ if frame.GetLineEntry().GetLine() == self.line_align:
+ found = True
+ self.assertTrue(found)
+
+ backtraces = thread.GetStopReasonExtendedBacktraces(
+ lldb.eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer)
+ self.assertTrue(backtraces.GetSize() == 1)
+
+ self.expect(
+ "thread info -s",
+ "The extended stop info should contain the UBSan provided fields",
+ substrs=[
+ "instrumentation_class",
+ "memory_address",
+ "description",
+ "filename",
+ "line",
+ "col"])
+
+ output_lines = self.res.GetOutput().split('\n')
+ json_line = '\n'.join(output_lines[2:])
+ data = json.loads(json_line)
+
+ self.assertEqual(data["instrumentation_class"], "UndefinedBehaviorSanitizer")
+ self.assertEqual(data["description"], "misaligned-pointer-use")
+ self.assertEqual(data["filename"], "main.c")
+ self.assertEqual(data["line"], self.line_align)
+
+ self.runCmd("continue")
diff --git a/packages/Python/lldbsuite/test/functionalities/ubsan/basic/main.c b/packages/Python/lldbsuite/test/functionalities/ubsan/basic/main.c
new file mode 100644
index 000000000000..4991fc074d09
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/ubsan/basic/main.c
@@ -0,0 +1,4 @@
+int main() {
+ int data[4];
+ return *(int *)(((char *)&data[0]) + 2); // align line
+}
diff --git a/packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py b/packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py
index 57f373545380..96c5a33f14b0 100644
--- a/packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py
+++ b/packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py
@@ -121,8 +121,6 @@ class ObjCNewSyntaxTestCase(TestBase):
'7.0.0'])
@skipIf(macos_version=["<", "10.12"])
@expectedFailureAll(archs=["i[3-6]86"])
- @expectedFailureAll(
- bugnumber="rdar://32777981")
def test_update_dictionary(self):
self.runToBreakpoint()
@@ -165,8 +163,6 @@ class ObjCNewSyntaxTestCase(TestBase):
'7.0.0'])
@skipIf(macos_version=["<", "10.12"])
@expectedFailureAll(archs=["i[3-6]86"])
- @expectedFailureAll(
- bugnumber="rdar://32777981")
def test_dictionary_literal(self):
self.runToBreakpoint()
diff --git a/scripts/Python/python-wrapper.swig b/scripts/Python/python-wrapper.swig
index a92102e32838..96b8dda80f82 100644
--- a/scripts/Python/python-wrapper.swig
+++ b/scripts/Python/python-wrapper.swig
@@ -929,7 +929,8 @@ void LLDBSwigPythonCallPythonLogOutputCallback(const char *str, void *baton);
void LLDBSwigPythonCallPythonLogOutputCallback(const char *str, void *baton) {
if (baton != Py_None) {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
- PyObject_CallFunction(reinterpret_cast<PyObject*>(baton), const_cast<char*>("s"), str);
+ PyObject *result = PyObject_CallFunction(reinterpret_cast<PyObject*>(baton), const_cast<char*>("s"), str);
+ Py_XDECREF(result);
SWIG_PYTHON_THREAD_END_BLOCK;
}
}
diff --git a/source/API/SBThread.cpp b/source/API/SBThread.cpp
index 65ccb465c8da..d9ce6be3f893 100644
--- a/source/API/SBThread.cpp
+++ b/source/API/SBThread.cpp
@@ -293,10 +293,6 @@ SBThread::GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type) {
ThreadCollectionSP threads;
threads.reset(new ThreadCollection());
- // We currently only support ThreadSanitizer.
- if (type != eInstrumentationRuntimeTypeThreadSanitizer)
- return threads;
-
std::unique_lock<std::recursive_mutex> lock;
ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
diff --git a/source/API/SystemInitializerFull.cpp b/source/API/SystemInitializerFull.cpp
index 6be352567e8b..7be37898c5aa 100644
--- a/source/API/SystemInitializerFull.cpp
+++ b/source/API/SystemInitializerFull.cpp
@@ -49,8 +49,10 @@
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
-#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h"
-#include "Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h"
+#include "Plugins/InstrumentationRuntime/ASan/ASanRuntime.h"
+#include "Plugins/InstrumentationRuntime/TSan/TSanRuntime.h"
+#include "Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h"
+#include "Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h"
#include "Plugins/JITLoader/GDB/JITLoaderGDB.h"
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/Go/GoLanguage.h"
@@ -310,6 +312,8 @@ void SystemInitializerFull::Initialize() {
MemoryHistoryASan::Initialize();
AddressSanitizerRuntime::Initialize();
ThreadSanitizerRuntime::Initialize();
+ UndefinedBehaviorSanitizerRuntime::Initialize();
+ MainThreadCheckerRuntime::Initialize();
SymbolVendorELF::Initialize();
SymbolFileDWARF::Initialize();
@@ -434,6 +438,8 @@ void SystemInitializerFull::Terminate() {
MemoryHistoryASan::Terminate();
AddressSanitizerRuntime::Terminate();
ThreadSanitizerRuntime::Terminate();
+ UndefinedBehaviorSanitizerRuntime::Terminate();
+ MainThreadCheckerRuntime::Terminate();
SymbolVendorELF::Terminate();
SymbolFileDWARF::Terminate();
SymbolFilePDB::Terminate();
diff --git a/source/Commands/CommandObjectFrame.cpp b/source/Commands/CommandObjectFrame.cpp
index 8b981a93ad7f..9e1805f2eed6 100644
--- a/source/Commands/CommandObjectFrame.cpp
+++ b/source/Commands/CommandObjectFrame.cpp
@@ -655,32 +655,30 @@ protected:
if (num_variables > 0) {
for (size_t i = 0; i < num_variables; i++) {
var_sp = variable_list->GetVariableAtIndex(i);
- switch (var_sp->GetScope())
- {
- case eValueTypeVariableGlobal:
- if (!m_option_variable.show_globals)
- continue;
- break;
- case eValueTypeVariableStatic:
- if (!m_option_variable.show_globals)
- continue;
- break;
- case eValueTypeVariableArgument:
- if (!m_option_variable.show_args)
- continue;
- break;
- case eValueTypeVariableLocal:
- if (!m_option_variable.show_locals)
- continue;
- break;
- default:
+ switch (var_sp->GetScope()) {
+ case eValueTypeVariableGlobal:
+ if (!m_option_variable.show_globals)
+ continue;
+ break;
+ case eValueTypeVariableStatic:
+ if (!m_option_variable.show_globals)
+ continue;
+ break;
+ case eValueTypeVariableArgument:
+ if (!m_option_variable.show_args)
+ continue;
+ break;
+ case eValueTypeVariableLocal:
+ if (!m_option_variable.show_locals)
continue;
- break;
-
+ break;
+ default:
+ continue;
+ break;
}
- std::string scope_string;
- if (m_option_variable.show_scope)
- scope_string = GetScopeString(var_sp).str();
+ std::string scope_string;
+ if (m_option_variable.show_scope)
+ scope_string = GetScopeString(var_sp).str();
// Use the variable object code to make sure we are
// using the same APIs as the public API will be
diff --git a/source/Core/IOHandler.cpp b/source/Core/IOHandler.cpp
index 3cb1ffab3a0e..194fec8a8798 100644
--- a/source/Core/IOHandler.cpp
+++ b/source/Core/IOHandler.cpp
@@ -58,7 +58,7 @@
#include "llvm/ADT/StringRef.h" // for StringRef
#ifdef _MSC_VER
-#include <windows.h>
+#include "lldb/Host/windows/windows.h"
#endif
#include <memory> // for shared_ptr
diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp
index c2e9b8904a0a..4dac0b8f3bf1 100644
--- a/source/Core/Mangled.cpp
+++ b/source/Core/Mangled.cpp
@@ -10,7 +10,7 @@
#include "lldb/Core/Mangled.h"
#if defined(_WIN32)
-#include <windows.h>
+#include "lldb/Host/windows/windows.h"
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
diff --git a/source/Core/Timer.cpp b/source/Core/Timer.cpp
index 6de4516f721d..59c3e13a717e 100644
--- a/source/Core/Timer.cpp
+++ b/source/Core/Timer.cpp
@@ -38,20 +38,9 @@ static std::mutex &GetFileMutex() {
return *g_file_mutex_ptr;
}
-static void ThreadSpecificCleanup(void *p) {
- delete static_cast<TimerStack *>(p);
-}
-
-static TimerStack *GetTimerStackForCurrentThread() {
- static lldb::thread_key_t g_key =
- Host::ThreadLocalStorageCreate(ThreadSpecificCleanup);
-
- void *timer_stack = Host::ThreadLocalStorageGet(g_key);
- if (timer_stack == NULL) {
- Host::ThreadLocalStorageSet(g_key, new TimerStack);
- timer_stack = Host::ThreadLocalStorageGet(g_key);
- }
- return (TimerStack *)timer_stack;
+static TimerStack &GetTimerStackForCurrentThread() {
+ static thread_local TimerStack g_stack;
+ return g_stack;
}
Timer::Category::Category(const char *cat) : m_name(cat) {
@@ -66,16 +55,14 @@ void Timer::SetQuiet(bool value) { g_quiet = value; }
Timer::Timer(Timer::Category &category, const char *format, ...)
: m_category(category), m_total_start(std::chrono::steady_clock::now()) {
- TimerStack *stack = GetTimerStackForCurrentThread();
- if (!stack)
- return;
+ TimerStack &stack = GetTimerStackForCurrentThread();
- stack->push_back(this);
- if (g_quiet && stack->size() <= g_display_depth) {
+ stack.push_back(this);
+ if (g_quiet && stack.size() <= g_display_depth) {
std::lock_guard<std::mutex> lock(GetFileMutex());
// Indent
- ::fprintf(stdout, "%*s", int(stack->size() - 1) * TIMER_INDENT_AMOUNT, "");
+ ::fprintf(stdout, "%*s", int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "");
// Print formatted string
va_list args;
va_start(args, format);
@@ -90,26 +77,23 @@ Timer::Timer(Timer::Category &category, const char *format, ...)
Timer::~Timer() {
using namespace std::chrono;
- TimerStack *stack = GetTimerStackForCurrentThread();
- if (!stack)
- return;
-
auto stop_time = steady_clock::now();
auto total_dur = stop_time - m_total_start;
auto timer_dur = total_dur - m_child_duration;
- if (g_quiet && stack->size() <= g_display_depth) {
+ TimerStack &stack = GetTimerStackForCurrentThread();
+ if (g_quiet && stack.size() <= g_display_depth) {
std::lock_guard<std::mutex> lock(GetFileMutex());
::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n",
- int(stack->size() - 1) * TIMER_INDENT_AMOUNT, "",
+ int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "",
duration<double>(total_dur).count(),
duration<double>(timer_dur).count());
}
- assert(stack->back() == this);
- stack->pop_back();
- if (!stack->empty())
- stack->back()->ChildDuration(total_dur);
+ assert(stack.back() == this);
+ stack.pop_back();
+ if (!stack.empty())
+ stack.back()->ChildDuration(total_dur);
// Keep total results for each category so we can dump results.
m_category.m_nanos += std::chrono::nanoseconds(timer_dur).count();
diff --git a/source/Host/CMakeLists.txt b/source/Host/CMakeLists.txt
index 2a73c30f8524..b9079ce26a2c 100644
--- a/source/Host/CMakeLists.txt
+++ b/source/Host/CMakeLists.txt
@@ -90,12 +90,6 @@ else()
posix/ProcessLauncherPosixFork.cpp
)
- if (NOT (CMAKE_SYSTEM_NAME MATCHES "Android"))
- add_host_subdirectory(posix
- posix/ProcessLauncherPosix.cpp
- )
- endif()
-
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR})
add_host_subdirectory(macosx
diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp
index d78961e5bffc..af0b57248922 100644
--- a/source/Host/common/Host.cpp
+++ b/source/Host/common/Host.cpp
@@ -68,15 +68,14 @@
#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-forward.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#if defined(_WIN32)
#include "lldb/Host/windows/ProcessLauncherWindows.h"
-#elif defined(__linux__) || defined(__NetBSD__)
-#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
#else
-#include "lldb/Host/posix/ProcessLauncherPosix.h"
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
#endif
#if defined(__APPLE__)
@@ -407,25 +406,6 @@ const char *Host::GetSignalAsCString(int signo) {
#endif
-#ifndef _WIN32
-
-lldb::thread_key_t
-Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) {
- pthread_key_t key;
- ::pthread_key_create(&key, callback);
- return key;
-}
-
-void *Host::ThreadLocalStorageGet(lldb::thread_key_t key) {
- return ::pthread_getspecific(key);
-}
-
-void Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) {
- ::pthread_setspecific(key, value);
-}
-
-#endif
-
#if !defined(__APPLE__) // see Host.mm
bool Host::GetBundleDirectory(const FileSpec &file, FileSpec &bundle) {
@@ -602,359 +582,14 @@ Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir,
return error;
}
-// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD, NetBSD and other GLIBC
-// systems
-
-#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || \
- defined(__GLIBC__) || defined(__NetBSD__)
-#if !defined(__ANDROID__)
-// this method needs to be visible to macosx/Host.cpp and
-// common/Host.cpp.
-
-short Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) {
- short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
-
-#if defined(__APPLE__)
- if (launch_info.GetFlags().Test(eLaunchFlagExec))
- flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag
-
- if (launch_info.GetFlags().Test(eLaunchFlagDebug))
- flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag
-
- if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
- flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag
-
- if (launch_info.GetLaunchInSeparateProcessGroup())
- flags |= POSIX_SPAWN_SETPGROUP;
-
-#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
-#if defined(__APPLE__) && (defined(__x86_64__) || defined(__i386__))
- static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;
- if (g_use_close_on_exec_flag == eLazyBoolCalculate) {
- g_use_close_on_exec_flag = eLazyBoolNo;
-
- uint32_t major, minor, update;
- if (HostInfo::GetOSVersion(major, minor, update)) {
- // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or
- // earlier
- if (major > 10 || (major == 10 && minor > 7)) {
- // Only enable for 10.8 and later OS versions
- g_use_close_on_exec_flag = eLazyBoolYes;
- }
- }
- }
-#else
- static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;
-#endif
- // Close all files exception those with file actions if this is supported.
- if (g_use_close_on_exec_flag == eLazyBoolYes)
- flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
-#endif
-#endif // #if defined (__APPLE__)
- return flags;
-}
-
-Status Host::LaunchProcessPosixSpawn(const char *exe_path,
- const ProcessLaunchInfo &launch_info,
- lldb::pid_t &pid) {
- Status error;
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST |
- LIBLLDB_LOG_PROCESS));
-
- posix_spawnattr_t attr;
- error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX);
-
- if (error.Fail()) {
- LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error);
- return error;
- }
-
- // Make a quick class that will cleanup the posix spawn attributes in case
- // we return in the middle of this function.
- lldb_utility::CleanUp<posix_spawnattr_t *, int> posix_spawnattr_cleanup(
- &attr, posix_spawnattr_destroy);
-
- sigset_t no_signals;
- sigset_t all_signals;
- sigemptyset(&no_signals);
- sigfillset(&all_signals);
- ::posix_spawnattr_setsigmask(&attr, &no_signals);
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
- ::posix_spawnattr_setsigdefault(&attr, &no_signals);
-#else
- ::posix_spawnattr_setsigdefault(&attr, &all_signals);
-#endif
-
- short flags = GetPosixspawnFlags(launch_info);
-
- error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX);
- if (error.Fail()) {
- LLDB_LOG(log,
- "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )",
- error, flags);
- return error;
- }
-
-// posix_spawnattr_setbinpref_np appears to be an Apple extension per:
-// http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/
-#if defined(__APPLE__) && !defined(__arm__)
-
- // Don't set the binpref if a shell was provided. After all, that's only
- // going to affect what version of the shell
- // is launched, not what fork of the binary is launched. We insert "arch
- // --arch <ARCH> as part of the shell invocation
- // to do that job on OSX.
-
- if (launch_info.GetShell() == nullptr) {
- // We don't need to do this for ARM, and we really shouldn't now that we
- // have multiple CPU subtypes and no posix_spawnattr call that allows us
- // to set which CPU subtype to launch...
- const ArchSpec &arch_spec = launch_info.GetArchitecture();
- cpu_type_t cpu = arch_spec.GetMachOCPUType();
- cpu_type_t sub = arch_spec.GetMachOCPUSubType();
- if (cpu != 0 && cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
- cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
- !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try
- // to set the CPU type or we will fail
- {
- size_t ocount = 0;
- error.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &ocount),
- eErrorTypePOSIX);
- if (error.Fail())
- LLDB_LOG(log, "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "
- "cpu_type = {1:x}, count => {2} )",
- error, cpu, ocount);
-
- if (error.Fail() || ocount != 1)
- return error;
- }
- }
-
-#endif
-
- const char *tmp_argv[2];
- char *const *argv = const_cast<char *const *>(
- launch_info.GetArguments().GetConstArgumentVector());
- char *const *envp = const_cast<char *const *>(
- launch_info.GetEnvironmentEntries().GetConstArgumentVector());
- if (argv == NULL) {
- // posix_spawn gets very unhappy if it doesn't have at least the program
- // name in argv[0]. One of the side affects I have noticed is the
- // environment
- // variables don't make it into the child process if "argv == NULL"!!!
- tmp_argv[0] = exe_path;
- tmp_argv[1] = NULL;
- argv = const_cast<char *const *>(tmp_argv);
- }
-
+// The functions below implement process launching for non-Apple-based platforms
#if !defined(__APPLE__)
- // manage the working directory
- char current_dir[PATH_MAX];
- current_dir[0] = '\0';
-#endif
-
- FileSpec working_dir{launch_info.GetWorkingDirectory()};
- if (working_dir) {
-#if defined(__APPLE__)
- // Set the working directory on this thread only
- if (__pthread_chdir(working_dir.GetCString()) < 0) {
- if (errno == ENOENT) {
- error.SetErrorStringWithFormat("No such file or directory: %s",
- working_dir.GetCString());
- } else if (errno == ENOTDIR) {
- error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
- working_dir.GetCString());
- } else {
- error.SetErrorStringWithFormat("An unknown error occurred when "
- "changing directory for process "
- "execution.");
- }
- return error;
- }
-#else
- if (::getcwd(current_dir, sizeof(current_dir)) == NULL) {
- error.SetError(errno, eErrorTypePOSIX);
- LLDB_LOG(log, "error: {0}, unable to save the current directory", error);
- return error;
- }
-
- if (::chdir(working_dir.GetCString()) == -1) {
- error.SetError(errno, eErrorTypePOSIX);
- LLDB_LOG(log, "error: {0}, unable to change working directory to {1}",
- error, working_dir);
- return error;
- }
-#endif
- }
-
- ::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
- const size_t num_file_actions = launch_info.GetNumFileActions();
- if (num_file_actions > 0) {
- posix_spawn_file_actions_t file_actions;
- error.SetError(::posix_spawn_file_actions_init(&file_actions),
- eErrorTypePOSIX);
- if (error.Fail()) {
- LLDB_LOG(log,
- "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )",
- error);
- return error;
- }
-
- // Make a quick class that will cleanup the posix spawn attributes in case
- // we return in the middle of this function.
- lldb_utility::CleanUp<posix_spawn_file_actions_t *, int>
- posix_spawn_file_actions_cleanup(&file_actions,
- posix_spawn_file_actions_destroy);
-
- for (size_t i = 0; i < num_file_actions; ++i) {
- const FileAction *launch_file_action =
- launch_info.GetFileActionAtIndex(i);
- if (launch_file_action) {
- if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log,
- error))
- return error;
- }
- }
-
- error.SetError(
- ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp),
- eErrorTypePOSIX);
-
- if (error.Fail()) {
- LLDB_LOG(log, "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "
- "file_actions = {3}, "
- "attr = {4}, argv = {5}, envp = {6} )",
- error, result_pid, exe_path, &file_actions, &attr, argv, envp);
- if (log) {
- for (int ii = 0; argv[ii]; ++ii)
- LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
- }
- }
-
- } else {
- error.SetError(
- ::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp),
- eErrorTypePOSIX);
-
- if (error.Fail()) {
- LLDB_LOG(log, "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "
- "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",
- error, result_pid, exe_path, &attr, argv, envp);
- if (log) {
- for (int ii = 0; argv[ii]; ++ii)
- LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
- }
- }
- }
- pid = result_pid;
-
- if (working_dir) {
-#if defined(__APPLE__)
- // No more thread specific current working directory
- __pthread_fchdir(-1);
-#else
- if (::chdir(current_dir) == -1 && error.Success()) {
- error.SetError(errno, eErrorTypePOSIX);
- LLDB_LOG(log,
- "error: {0}, unable to change current directory back to {1}",
- error, current_dir);
- }
-#endif
- }
-
- return error;
-}
-
-bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info,
- Log *log, Status &error) {
- if (info == NULL)
- return false;
-
- posix_spawn_file_actions_t *file_actions =
- reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions);
-
- switch (info->GetAction()) {
- case FileAction::eFileActionNone:
- error.Clear();
- break;
-
- case FileAction::eFileActionClose:
- if (info->GetFD() == -1)
- error.SetErrorString(
- "invalid fd for posix_spawn_file_actions_addclose(...)");
- else {
- error.SetError(
- ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()),
- eErrorTypePOSIX);
- if (error.Fail())
- LLDB_LOG(log, "error: {0}, posix_spawn_file_actions_addclose "
- "(action={1}, fd={2})",
- error, file_actions, info->GetFD());
- }
- break;
-
- case FileAction::eFileActionDuplicate:
- if (info->GetFD() == -1)
- error.SetErrorString(
- "invalid fd for posix_spawn_file_actions_adddup2(...)");
- else if (info->GetActionArgument() == -1)
- error.SetErrorString(
- "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
- else {
- error.SetError(
- ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(),
- info->GetActionArgument()),
- eErrorTypePOSIX);
- if (error.Fail())
- LLDB_LOG(log, "error: {0}, posix_spawn_file_actions_adddup2 "
- "(action={1}, fd={2}, dup_fd={3})",
- error, file_actions, info->GetFD(), info->GetActionArgument());
- }
- break;
-
- case FileAction::eFileActionOpen:
- if (info->GetFD() == -1)
- error.SetErrorString(
- "invalid fd in posix_spawn_file_actions_addopen(...)");
- else {
- int oflag = info->GetActionArgument();
-
- mode_t mode = 0;
-
- if (oflag & O_CREAT)
- mode = 0640;
-
- error.SetError(::posix_spawn_file_actions_addopen(
- file_actions, info->GetFD(),
- info->GetPath().str().c_str(), oflag, mode),
- eErrorTypePOSIX);
- if (error.Fail())
- LLDB_LOG(
- log, "error: {0}, posix_spawn_file_actions_addopen (action={1}, "
- "fd={2}, path='{3}', oflag={4}, mode={5})",
- error, file_actions, info->GetFD(), info->GetPath(), oflag, mode);
- }
- break;
- }
- return error.Success();
-}
-#endif // !defined(__ANDROID__)
-#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) ||
- // defined (__GLIBC__) || defined(__NetBSD__)
-
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || \
- defined(__NetBSD__) || defined(_WIN32)
-// The functions below implement process launching via posix_spawn() for Linux,
-// FreeBSD and NetBSD.
-
Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
std::unique_ptr<ProcessLauncher> delegate_launcher;
#if defined(_WIN32)
delegate_launcher.reset(new ProcessLauncherWindows());
-#elif defined(__linux__) || defined(__NetBSD__)
- delegate_launcher.reset(new ProcessLauncherPosixFork());
#else
- delegate_launcher.reset(new ProcessLauncherPosix());
+ delegate_launcher.reset(new ProcessLauncherPosixFork());
#endif
MonitoringProcessLauncher launcher(std::move(delegate_launcher));
@@ -968,7 +603,7 @@ Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
return error;
}
-#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
+#endif // !defined(__APPLE__)
#ifndef _WIN32
void Host::Kill(lldb::pid_t pid, int signo) { ::kill(pid, signo); }
@@ -988,3 +623,51 @@ const UnixSignalsSP &Host::GetUnixSignals() {
UnixSignals::Create(HostInfo::GetArchitecture());
return s_unix_signals_sp;
}
+
+#if defined(LLVM_ON_UNIX)
+WaitStatus WaitStatus::Decode(int wstatus) {
+ if (WIFEXITED(wstatus))
+ return {Exit, uint8_t(WEXITSTATUS(wstatus))};
+ else if (WIFSIGNALED(wstatus))
+ return {Signal, uint8_t(WTERMSIG(wstatus))};
+ else if (WIFSTOPPED(wstatus))
+ return {Stop, uint8_t(WSTOPSIG(wstatus))};
+ llvm_unreachable("Unknown wait status");
+}
+#endif
+
+void llvm::format_provider<WaitStatus>::format(const WaitStatus &WS,
+ raw_ostream &OS,
+ StringRef Options) {
+ if (Options == "g") {
+ char type;
+ switch (WS.type) {
+ case WaitStatus::Exit:
+ type = 'W';
+ break;
+ case WaitStatus::Signal:
+ type = 'X';
+ break;
+ case WaitStatus::Stop:
+ type = 'S';
+ break;
+ }
+ OS << formatv("{0}{1:x-2}", type, WS.status);
+ return;
+ }
+
+ assert(Options.empty());
+ const char *desc;
+ switch(WS.type) {
+ case WaitStatus::Exit:
+ desc = "Exited with status";
+ break;
+ case WaitStatus::Signal:
+ desc = "Killed by signal";
+ break;
+ case WaitStatus::Stop:
+ desc = "Stopped by signal";
+ break;
+ }
+ OS << desc << " " << int(WS.status);
+}
diff --git a/source/Host/common/NativeProcessProtocol.cpp b/source/Host/common/NativeProcessProtocol.cpp
index 6f1a9f895b61..341c301dc9c5 100644
--- a/source/Host/common/NativeProcessProtocol.cpp
+++ b/source/Host/common/NativeProcessProtocol.cpp
@@ -32,7 +32,6 @@ using namespace lldb_private;
NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid)
: m_pid(pid), m_threads(), m_current_thread_id(LLDB_INVALID_THREAD_ID),
m_threads_mutex(), m_state(lldb::eStateInvalid), m_state_mutex(),
- m_exit_type(eExitTypeInvalid), m_exit_status(0), m_exit_description(),
m_delegates_mutex(), m_delegates(), m_breakpoint_list(),
m_watchpoint_list(), m_terminal_fd(-1), m_stop_id(0) {}
@@ -59,46 +58,29 @@ NativeProcessProtocol::GetMemoryRegionInfo(lldb::addr_t load_addr,
return Status("not implemented");
}
-bool NativeProcessProtocol::GetExitStatus(ExitType *exit_type, int *status,
- std::string &exit_description) {
- if (m_state == lldb::eStateExited) {
- *exit_type = m_exit_type;
- *status = m_exit_status;
- exit_description = m_exit_description;
- return true;
- }
+llvm::Optional<WaitStatus> NativeProcessProtocol::GetExitStatus() {
+ if (m_state == lldb::eStateExited)
+ return m_exit_status;
- *status = 0;
- return false;
+ return llvm::None;
}
-bool NativeProcessProtocol::SetExitStatus(ExitType exit_type, int status,
- const char *exit_description,
+bool NativeProcessProtocol::SetExitStatus(WaitStatus status,
bool bNotifyStateChange) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("NativeProcessProtocol::%s(%d, %d, %s, %s) called",
- __FUNCTION__, exit_type, status,
- exit_description ? exit_description : "nullptr",
- bNotifyStateChange ? "true" : "false");
+ LLDB_LOG(log, "status = {0}, notify = {1}", status, bNotifyStateChange);
// Exit status already set
if (m_state == lldb::eStateExited) {
- if (log)
- log->Printf("NativeProcessProtocol::%s exit status already set to %d, "
- "ignoring new set to %d",
- __FUNCTION__, m_exit_status, status);
+ if (m_exit_status)
+ LLDB_LOG(log, "exit status already set to {0}", *m_exit_status);
+ else
+ LLDB_LOG(log, "state is exited, but status not set");
return false;
}
m_state = lldb::eStateExited;
-
- m_exit_type = exit_type;
m_exit_status = status;
- if (exit_description && exit_description[0])
- m_exit_description = exit_description;
- else
- m_exit_description.clear();
if (bNotifyStateChange)
SynchronouslyNotifyProcessStateChanged(lldb::eStateExited);
diff --git a/source/Host/macosx/Host.mm b/source/Host/macosx/Host.mm
index be205f953862..919b35624e60 100644
--- a/source/Host/macosx/Host.mm
+++ b/source/Host/macosx/Host.mm
@@ -1024,6 +1024,47 @@ static Status getXPCAuthorization(ProcessLaunchInfo &launch_info) {
}
#endif
+static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) {
+ short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
+
+ if (launch_info.GetFlags().Test(eLaunchFlagExec))
+ flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag
+
+ if (launch_info.GetFlags().Test(eLaunchFlagDebug))
+ flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag
+
+ if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
+ flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag
+
+ if (launch_info.GetLaunchInSeparateProcessGroup())
+ flags |= POSIX_SPAWN_SETPGROUP;
+
+#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
+#if defined(__x86_64__) || defined(__i386__)
+ static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;
+ if (g_use_close_on_exec_flag == eLazyBoolCalculate) {
+ g_use_close_on_exec_flag = eLazyBoolNo;
+
+ uint32_t major, minor, update;
+ if (HostInfo::GetOSVersion(major, minor, update)) {
+ // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or
+ // earlier
+ if (major > 10 || (major == 10 && minor > 7)) {
+ // Only enable for 10.8 and later OS versions
+ g_use_close_on_exec_flag = eLazyBoolYes;
+ }
+ }
+ }
+#else
+ static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;
+#endif // defined(__x86_64__) || defined(__i386__)
+ // Close all files exception those with file actions if this is supported.
+ if (g_use_close_on_exec_flag == eLazyBoolYes)
+ flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
+#endif // ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
+ return flags;
+}
+
static Status LaunchProcessXPC(const char *exe_path,
ProcessLaunchInfo &launch_info,
lldb::pid_t &pid) {
@@ -1107,7 +1148,7 @@ static Status LaunchProcessXPC(const char *exe_path,
xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey,
launch_info.GetArchitecture().GetMachOCPUType());
xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey,
- Host::GetPosixspawnFlags(launch_info));
+ GetPosixspawnFlags(launch_info));
const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
if (file_action && !file_action->GetPath().empty()) {
xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey,
@@ -1161,6 +1202,262 @@ static Status LaunchProcessXPC(const char *exe_path,
#endif
}
+static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info,
+ Log *log, Status &error) {
+ if (info == NULL)
+ return false;
+
+ posix_spawn_file_actions_t *file_actions =
+ reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions);
+
+ switch (info->GetAction()) {
+ case FileAction::eFileActionNone:
+ error.Clear();
+ break;
+
+ case FileAction::eFileActionClose:
+ if (info->GetFD() == -1)
+ error.SetErrorString(
+ "invalid fd for posix_spawn_file_actions_addclose(...)");
+ else {
+ error.SetError(
+ ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()),
+ eErrorTypePOSIX);
+ if (error.Fail())
+ LLDB_LOG(log,
+ "error: {0}, posix_spawn_file_actions_addclose "
+ "(action={1}, fd={2})",
+ error, file_actions, info->GetFD());
+ }
+ break;
+
+ case FileAction::eFileActionDuplicate:
+ if (info->GetFD() == -1)
+ error.SetErrorString(
+ "invalid fd for posix_spawn_file_actions_adddup2(...)");
+ else if (info->GetActionArgument() == -1)
+ error.SetErrorString(
+ "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
+ else {
+ error.SetError(
+ ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(),
+ info->GetActionArgument()),
+ eErrorTypePOSIX);
+ if (error.Fail())
+ LLDB_LOG(log,
+ "error: {0}, posix_spawn_file_actions_adddup2 "
+ "(action={1}, fd={2}, dup_fd={3})",
+ error, file_actions, info->GetFD(), info->GetActionArgument());
+ }
+ break;
+
+ case FileAction::eFileActionOpen:
+ if (info->GetFD() == -1)
+ error.SetErrorString(
+ "invalid fd in posix_spawn_file_actions_addopen(...)");
+ else {
+ int oflag = info->GetActionArgument();
+
+ mode_t mode = 0;
+
+ if (oflag & O_CREAT)
+ mode = 0640;
+
+ error.SetError(::posix_spawn_file_actions_addopen(
+ file_actions, info->GetFD(),
+ info->GetPath().str().c_str(), oflag, mode),
+ eErrorTypePOSIX);
+ if (error.Fail())
+ LLDB_LOG(log,
+ "error: {0}, posix_spawn_file_actions_addopen (action={1}, "
+ "fd={2}, path='{3}', oflag={4}, mode={5})",
+ error, file_actions, info->GetFD(), info->GetPath(), oflag,
+ mode);
+ }
+ break;
+ }
+ return error.Success();
+}
+
+static Status LaunchProcessPosixSpawn(const char *exe_path,
+ const ProcessLaunchInfo &launch_info,
+ lldb::pid_t &pid) {
+ Status error;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST |
+ LIBLLDB_LOG_PROCESS));
+
+ posix_spawnattr_t attr;
+ error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX);
+
+ if (error.Fail()) {
+ LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error);
+ return error;
+ }
+
+ // Make a quick class that will cleanup the posix spawn attributes in case
+ // we return in the middle of this function.
+ lldb_utility::CleanUp<posix_spawnattr_t *, int> posix_spawnattr_cleanup(
+ &attr, posix_spawnattr_destroy);
+
+ sigset_t no_signals;
+ sigset_t all_signals;
+ sigemptyset(&no_signals);
+ sigfillset(&all_signals);
+ ::posix_spawnattr_setsigmask(&attr, &no_signals);
+ ::posix_spawnattr_setsigdefault(&attr, &all_signals);
+
+ short flags = GetPosixspawnFlags(launch_info);
+
+ error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX);
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )",
+ error, flags);
+ return error;
+ }
+
+// posix_spawnattr_setbinpref_np appears to be an Apple extension per:
+// http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/
+#if !defined(__arm__)
+
+ // Don't set the binpref if a shell was provided. After all, that's only
+ // going to affect what version of the shell
+ // is launched, not what fork of the binary is launched. We insert "arch
+ // --arch <ARCH> as part of the shell invocation
+ // to do that job on OSX.
+
+ if (launch_info.GetShell() == nullptr) {
+ // We don't need to do this for ARM, and we really shouldn't now that we
+ // have multiple CPU subtypes and no posix_spawnattr call that allows us
+ // to set which CPU subtype to launch...
+ const ArchSpec &arch_spec = launch_info.GetArchitecture();
+ cpu_type_t cpu = arch_spec.GetMachOCPUType();
+ cpu_type_t sub = arch_spec.GetMachOCPUSubType();
+ if (cpu != 0 && cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
+ cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
+ !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try
+ // to set the CPU type or we will fail
+ {
+ size_t ocount = 0;
+ error.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &ocount),
+ eErrorTypePOSIX);
+ if (error.Fail())
+ LLDB_LOG(log,
+ "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "
+ "cpu_type = {1:x}, count => {2} )",
+ error, cpu, ocount);
+
+ if (error.Fail() || ocount != 1)
+ return error;
+ }
+ }
+#endif // !defined(__arm__)
+
+ const char *tmp_argv[2];
+ char *const *argv = const_cast<char *const *>(
+ launch_info.GetArguments().GetConstArgumentVector());
+ char *const *envp = const_cast<char *const *>(
+ launch_info.GetEnvironmentEntries().GetConstArgumentVector());
+ if (argv == NULL) {
+ // posix_spawn gets very unhappy if it doesn't have at least the program
+ // name in argv[0]. One of the side affects I have noticed is the
+ // environment
+ // variables don't make it into the child process if "argv == NULL"!!!
+ tmp_argv[0] = exe_path;
+ tmp_argv[1] = NULL;
+ argv = const_cast<char *const *>(tmp_argv);
+ }
+
+ FileSpec working_dir{launch_info.GetWorkingDirectory()};
+ if (working_dir) {
+ // Set the working directory on this thread only
+ if (__pthread_chdir(working_dir.GetCString()) < 0) {
+ if (errno == ENOENT) {
+ error.SetErrorStringWithFormat("No such file or directory: %s",
+ working_dir.GetCString());
+ } else if (errno == ENOTDIR) {
+ error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
+ working_dir.GetCString());
+ } else {
+ error.SetErrorStringWithFormat("An unknown error occurred when "
+ "changing directory for process "
+ "execution.");
+ }
+ return error;
+ }
+ }
+
+ ::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
+ const size_t num_file_actions = launch_info.GetNumFileActions();
+ if (num_file_actions > 0) {
+ posix_spawn_file_actions_t file_actions;
+ error.SetError(::posix_spawn_file_actions_init(&file_actions),
+ eErrorTypePOSIX);
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )",
+ error);
+ return error;
+ }
+
+ // Make a quick class that will cleanup the posix spawn attributes in case
+ // we return in the middle of this function.
+ lldb_utility::CleanUp<posix_spawn_file_actions_t *, int>
+ posix_spawn_file_actions_cleanup(&file_actions,
+ posix_spawn_file_actions_destroy);
+
+ for (size_t i = 0; i < num_file_actions; ++i) {
+ const FileAction *launch_file_action =
+ launch_info.GetFileActionAtIndex(i);
+ if (launch_file_action) {
+ if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log,
+ error))
+ return error;
+ }
+ }
+
+ error.SetError(
+ ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp),
+ eErrorTypePOSIX);
+
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "
+ "file_actions = {3}, "
+ "attr = {4}, argv = {5}, envp = {6} )",
+ error, result_pid, exe_path, &file_actions, &attr, argv, envp);
+ if (log) {
+ for (int ii = 0; argv[ii]; ++ii)
+ LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
+ }
+ }
+
+ } else {
+ error.SetError(
+ ::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp),
+ eErrorTypePOSIX);
+
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "
+ "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",
+ error, result_pid, exe_path, &attr, argv, envp);
+ if (log) {
+ for (int ii = 0; argv[ii]; ++ii)
+ LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
+ }
+ }
+ }
+ pid = result_pid;
+
+ if (working_dir) {
+ // No more thread specific current working directory
+ __pthread_fchdir(-1);
+ }
+
+ return error;
+}
+
static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) {
bool result = false;
diff --git a/source/Host/posix/ProcessLauncherPosix.cpp b/source/Host/posix/ProcessLauncherPosix.cpp
deleted file mode 100644
index 6d07be1eec64..000000000000
--- a/source/Host/posix/ProcessLauncherPosix.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//===-- ProcessLauncherPosix.cpp --------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/posix/ProcessLauncherPosix.h"
-#include "lldb/Host/Host.h"
-#include "lldb/Host/HostProcess.h"
-
-#include "lldb/Target/ProcessLaunchInfo.h"
-
-#include <limits.h>
-
-using namespace lldb;
-using namespace lldb_private;
-
-HostProcess
-ProcessLauncherPosix::LaunchProcess(const ProcessLaunchInfo &launch_info,
- Status &error) {
- lldb::pid_t pid;
- char exe_path[PATH_MAX];
-
- launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
-
- // TODO(zturner): Move the code from LaunchProcessPosixSpawn to here, and make
- // MacOSX re-use this
- // ProcessLauncher when it wants a posix_spawn launch.
- error = Host::LaunchProcessPosixSpawn(exe_path, launch_info, pid);
- return HostProcess(pid);
-}
diff --git a/source/Host/posix/ProcessLauncherPosixFork.cpp b/source/Host/posix/ProcessLauncherPosixFork.cpp
index 1eace5cd24cd..0b40c24256ef 100644
--- a/source/Host/posix/ProcessLauncherPosixFork.cpp
+++ b/source/Host/posix/ProcessLauncherPosixFork.cpp
@@ -52,10 +52,10 @@ static void FixupEnvironment(Args &env) {
static void LLVM_ATTRIBUTE_NORETURN ExitWithError(int error_fd,
const char *operation) {
- std::ostringstream os;
- os << operation << " failed: " << strerror(errno);
- write(error_fd, os.str().data(), os.str().size());
- close(error_fd);
+ int err = errno;
+ llvm::raw_fd_ostream os(error_fd, true);
+ os << operation << " failed: " << llvm::sys::StrError(err);
+ os.flush();
_exit(1);
}
diff --git a/source/Host/windows/Host.cpp b/source/Host/windows/Host.cpp
index e1acd23d5c81..69a7c2ef4f74 100644
--- a/source/Host/windows/Host.cpp
+++ b/source/Host/windows/Host.cpp
@@ -101,19 +101,6 @@ lldb::thread_t Host::GetCurrentThread() {
return lldb::thread_t(::GetCurrentThread());
}
-lldb::thread_key_t
-Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) {
- return TlsAlloc();
-}
-
-void *Host::ThreadLocalStorageGet(lldb::thread_key_t key) {
- return ::TlsGetValue(key);
-}
-
-void Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) {
- ::TlsSetValue(key, value);
-}
-
void Host::Kill(lldb::pid_t pid, int signo) {
TerminateProcess((HANDLE)pid, 1);
}
diff --git a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
index b202c8395776..ce8f8a65e3e3 100644
--- a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
+++ b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
@@ -1951,22 +1951,20 @@ bool ABISysV_arm64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
uint32_t lr_reg_num = arm64_dwarf::lr;
uint32_t sp_reg_num = arm64_dwarf::sp;
- uint32_t pc_reg_num = arm64_dwarf::pc;
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our previous Call Frame Address is the stack pointer
row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0);
- // Our previous PC is in the LR
- row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
-
unwind_plan.AppendRow(row);
+ unwind_plan.SetReturnAddressRegister(lr_reg_num);
// All other registers are the same.
unwind_plan.SetSourceName("arm64 at-func-entry default");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
return true;
}
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index 5f56bfc027a4..0092535648bd 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -21,6 +21,7 @@
#include "lldb/Core/Section.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
@@ -484,6 +485,27 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread,
return thread_plan_sp;
}
+void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) {
+ if (m_vdso_base == LLDB_INVALID_ADDRESS)
+ return;
+
+ FileSpec file("[vdso]", false);
+
+ MemoryRegionInfo info;
+ Status status = m_process->GetMemoryRegionInfo(m_vdso_base, info);
+ if (status.Fail()) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ LLDB_LOG(log, "Failed to get vdso region info: {0}", status);
+ return;
+ }
+
+ if (ModuleSP module_sp = m_process->ReadModuleFromMemory(
+ file, m_vdso_base, info.GetRange().GetByteSize())) {
+ UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_vdso_base, false);
+ m_process->GetTarget().GetImages().AppendIfNeeded(module_sp);
+ }
+}
+
void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
DYLDRendezvous::iterator I;
DYLDRendezvous::iterator E;
@@ -502,14 +524,7 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
// that ourselves here.
ModuleSP executable = GetTargetExecutable();
m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
- if (m_vdso_base != LLDB_INVALID_ADDRESS) {
- FileSpec file_spec("[vdso]", false);
- ModuleSP module_sp = LoadModuleAtAddress(file_spec, LLDB_INVALID_ADDRESS,
- m_vdso_base, false);
- if (module_sp.get()) {
- module_list.Append(module_sp);
- }
- }
+ LoadVDSO(module_list);
std::vector<FileSpec> module_names;
for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
index 86e0311c2919..2e9670587e66 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
@@ -17,11 +17,11 @@
// Other libraries and framework includes
// Project includes
+#include "DYLDRendezvous.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/ModuleList.h"
#include "lldb/Target/DynamicLoader.h"
-#include "DYLDRendezvous.h"
-
class AuxVector;
class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader {
@@ -138,6 +138,8 @@ protected:
/// of all dependent modules.
virtual void LoadAllCurrentModules();
+ void LoadVDSO(lldb_private::ModuleList &modules);
+
/// Computes a value for m_load_offset returning the computed address on
/// success and LLDB_INVALID_ADDRESS on failure.
lldb::addr_t ComputeLoadOffset();
diff --git a/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp b/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp
index 91c5d6ce3d60..af242d786a5f 100644
--- a/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp
+++ b/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp
@@ -1,4 +1,4 @@
-//===-- AddressSanitizerRuntime.cpp -----------------------------*- C++ -*-===//
+//===-- ASanRuntime.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "AddressSanitizerRuntime.h"
+#include "ASanRuntime.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
@@ -308,13 +308,6 @@ void AddressSanitizerRuntime::Activate() {
breakpoint->SetBreakpointKind("address-sanitizer-report");
SetBreakpointID(breakpoint->GetID());
- StreamFileSP stream_sp(process_sp->GetTarget().GetDebugger().GetOutputFile());
- if (stream_sp) {
- stream_sp->Printf("AddressSanitizer debugger support is active. Memory "
- "error breakpoint has been installed and you can now use "
- "the 'memory history' command.\n");
- }
-
SetActive(true);
}
diff --git a/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h b/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h
index 9fd21c06f30c..9fd21c06f30c 100644
--- a/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h
+++ b/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h
diff --git a/source/Plugins/InstrumentationRuntime/AddressSanitizer/CMakeLists.txt b/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt
index 1adfc6ba5322..dc7464fd1939 100644
--- a/source/Plugins/InstrumentationRuntime/AddressSanitizer/CMakeLists.txt
+++ b/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt
@@ -1,5 +1,5 @@
-add_lldb_library(lldbPluginInstrumentationRuntimeAddressSanitizer PLUGIN
- AddressSanitizerRuntime.cpp
+add_lldb_library(lldbPluginInstrumentationRuntimeASan PLUGIN
+ ASanRuntime.cpp
LINK_LIBS
lldbBreakpoint
diff --git a/source/Plugins/InstrumentationRuntime/CMakeLists.txt b/source/Plugins/InstrumentationRuntime/CMakeLists.txt
index ae7c6e5972d3..55e8752e7424 100644
--- a/source/Plugins/InstrumentationRuntime/CMakeLists.txt
+++ b/source/Plugins/InstrumentationRuntime/CMakeLists.txt
@@ -1,2 +1,4 @@
-add_subdirectory(AddressSanitizer)
-add_subdirectory(ThreadSanitizer)
+add_subdirectory(ASan)
+add_subdirectory(MainThreadChecker)
+add_subdirectory(TSan)
+add_subdirectory(UBSan)
diff --git a/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt b/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt
new file mode 100644
index 000000000000..440b176b2709
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeMainThreadChecker PLUGIN
+ MainThreadCheckerRuntime.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbExpression
+ lldbInterpreter
+ lldbSymbol
+ lldbTarget
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp b/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp
new file mode 100644
index 000000000000..3c22b81df7a4
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp
@@ -0,0 +1,273 @@
+//===-- MainThreadCheckerRuntime.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MainThreadCheckerRuntime.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "Plugins/Process/Utility/HistoryThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+MainThreadCheckerRuntime::~MainThreadCheckerRuntime() {
+ Deactivate();
+}
+
+lldb::InstrumentationRuntimeSP
+MainThreadCheckerRuntime::CreateInstance(const lldb::ProcessSP &process_sp) {
+ return InstrumentationRuntimeSP(new MainThreadCheckerRuntime(process_sp));
+}
+
+void MainThreadCheckerRuntime::Initialize() {
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(), "MainThreadChecker instrumentation runtime plugin.",
+ CreateInstance, GetTypeStatic);
+}
+
+void MainThreadCheckerRuntime::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::ConstString MainThreadCheckerRuntime::GetPluginNameStatic() {
+ return ConstString("MainThreadChecker");
+}
+
+lldb::InstrumentationRuntimeType MainThreadCheckerRuntime::GetTypeStatic() {
+ return eInstrumentationRuntimeTypeMainThreadChecker;
+}
+
+const RegularExpression &
+MainThreadCheckerRuntime::GetPatternForRuntimeLibrary() {
+ static RegularExpression regex(llvm::StringRef("libMainThreadChecker.dylib"));
+ return regex;
+}
+
+bool MainThreadCheckerRuntime::CheckIfRuntimeIsValid(
+ const lldb::ModuleSP module_sp) {
+ static ConstString test_sym("__main_thread_checker_on_report");
+ const Symbol *symbol =
+ module_sp->FindFirstSymbolWithNameAndType(test_sym, lldb::eSymbolTypeAny);
+ return symbol != nullptr;
+}
+
+StructuredData::ObjectSP
+MainThreadCheckerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) {
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp)
+ return StructuredData::ObjectSP();
+
+ ThreadSP thread_sp = exe_ctx_ref.GetThreadSP();
+ StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
+ ModuleSP runtime_module_sp = GetRuntimeModuleSP();
+ Target &target = process_sp->GetTarget();
+
+ if (!frame_sp)
+ return StructuredData::ObjectSP();
+
+ RegisterContextSP regctx_sp = frame_sp->GetRegisterContext();
+ if (!regctx_sp)
+ return StructuredData::ObjectSP();
+
+ const RegisterInfo *reginfo = regctx_sp->GetRegisterInfoByName("arg1");
+ if (!reginfo)
+ return StructuredData::ObjectSP();
+
+ uint64_t apiname_ptr = regctx_sp->ReadRegisterAsUnsigned(reginfo, 0);
+ if (!apiname_ptr)
+ return StructuredData::ObjectSP();
+
+ std::string apiName = "";
+ Status read_error;
+ target.ReadCStringFromMemory(apiname_ptr, apiName, read_error);
+ if (read_error.Fail())
+ return StructuredData::ObjectSP();
+
+ std::string className = "";
+ std::string selector = "";
+ if (apiName.substr(0, 2) == "-[") {
+ size_t spacePos = apiName.find(" ");
+ if (spacePos != std::string::npos) {
+ className = apiName.substr(2, spacePos - 2);
+ selector = apiName.substr(spacePos + 1, apiName.length() - spacePos - 2);
+ }
+ }
+
+ // Gather the PCs of the user frames in the backtrace.
+ StructuredData::Array *trace = new StructuredData::Array();
+ auto trace_sp = StructuredData::ObjectSP(trace);
+ StackFrameSP responsible_frame;
+ for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) {
+ StackFrameSP frame = thread_sp->GetStackFrameAtIndex(I);
+ Address addr = frame->GetFrameCodeAddress();
+ if (addr.GetModule() == runtime_module_sp) // Skip PCs from the runtime.
+ continue;
+
+ // The first non-runtime frame is responsible for the bug.
+ if (!responsible_frame)
+ responsible_frame = frame;
+
+ // First frame in stacktrace should point to a real PC, not return address.
+ if (I != 0 && trace->GetSize() == 0) {
+ addr.Slide(-1);
+ }
+
+ lldb::addr_t PC = addr.GetLoadAddress(&target);
+ trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC)));
+ }
+
+ auto *d = new StructuredData::Dictionary();
+ auto dict_sp = StructuredData::ObjectSP(d);
+ d->AddStringItem("instrumentation_class", "MainThreadChecker");
+ d->AddStringItem("api_name", apiName);
+ d->AddStringItem("class_name", className);
+ d->AddStringItem("selector", selector);
+ d->AddStringItem("description",
+ apiName + " must be called from main thread only");
+ d->AddIntegerItem("tid", thread_sp->GetIndexID());
+ d->AddItem("trace", trace_sp);
+ return dict_sp;
+}
+
+bool MainThreadCheckerRuntime::NotifyBreakpointHit(
+ void *baton, StoppointCallbackContext *context, user_id_t break_id,
+ user_id_t break_loc_id) {
+ assert(baton && "null baton");
+ if (!baton)
+ return false; //< false => resume execution.
+
+ MainThreadCheckerRuntime *const instance =
+ static_cast<MainThreadCheckerRuntime *>(baton);
+
+ ProcessSP process_sp = instance->GetProcessSP();
+ ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
+ if (!process_sp || !thread_sp ||
+ process_sp != context->exe_ctx_ref.GetProcessSP())
+ return false;
+
+ StructuredData::ObjectSP report =
+ instance->RetrieveReportData(context->exe_ctx_ref);
+
+ if (report) {
+ std::string description = report->GetAsDictionary()
+ ->GetValueForKey("description")
+ ->GetAsString()
+ ->GetValue();
+ thread_sp->SetStopInfo(
+ InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
+ *thread_sp, description, report));
+ return true;
+ }
+
+ return false;
+}
+
+void MainThreadCheckerRuntime::Activate() {
+ if (IsActive())
+ return;
+
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp)
+ return;
+
+ ModuleSP runtime_module_sp = GetRuntimeModuleSP();
+
+ ConstString symbol_name("__main_thread_checker_on_report");
+ const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType(
+ symbol_name, eSymbolTypeCode);
+
+ if (symbol == nullptr)
+ return;
+
+ if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
+ return;
+
+ Target &target = process_sp->GetTarget();
+ addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
+
+ if (symbol_address == LLDB_INVALID_ADDRESS)
+ return;
+
+ Breakpoint *breakpoint =
+ process_sp->GetTarget()
+ .CreateBreakpoint(symbol_address, /*internal=*/true,
+ /*hardware=*/false)
+ .get();
+ breakpoint->SetCallback(MainThreadCheckerRuntime::NotifyBreakpointHit, this,
+ true);
+ breakpoint->SetBreakpointKind("main-thread-checker-report");
+ SetBreakpointID(breakpoint->GetID());
+
+ SetActive(true);
+}
+
+void MainThreadCheckerRuntime::Deactivate() {
+ SetActive(false);
+
+ auto BID = GetBreakpointID();
+ if (BID == LLDB_INVALID_BREAK_ID)
+ return;
+
+ if (ProcessSP process_sp = GetProcessSP()) {
+ process_sp->GetTarget().RemoveBreakpointByID(BID);
+ SetBreakpointID(LLDB_INVALID_BREAK_ID);
+ }
+}
+
+lldb::ThreadCollectionSP
+MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo(
+ StructuredData::ObjectSP info) {
+ ThreadCollectionSP threads;
+ threads.reset(new ThreadCollection());
+
+ ProcessSP process_sp = GetProcessSP();
+
+ if (info->GetObjectForDotSeparatedPath("instrumentation_class")
+ ->GetStringValue() != "MainThreadChecker")
+ return threads;
+
+ std::vector<lldb::addr_t> PCs;
+ auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray();
+ trace->ForEach([&PCs](StructuredData::Object *PC) -> bool {
+ PCs.push_back(PC->GetAsInteger()->GetValue());
+ return true;
+ });
+
+ if (PCs.empty())
+ return threads;
+
+ StructuredData::ObjectSP thread_id_obj =
+ info->GetObjectForDotSeparatedPath("tid");
+ tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;
+
+ uint32_t stop_id = 0;
+ bool stop_id_is_valid = false;
+ HistoryThread *history_thread =
+ new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid);
+ ThreadSP new_thread_sp(history_thread);
+
+ // Save this in the Process' ExtendedThreadList so a strong pointer
+ // retains the object
+ process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
+ threads->AddThread(new_thread_sp);
+
+ return threads;
+}
diff --git a/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h b/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h
new file mode 100644
index 000000000000..87440a2489e6
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h
@@ -0,0 +1,68 @@
+//===-- MainThreadCheckerRuntime.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MainThreadCheckerRuntime_h_
+#define liblldb_MainThreadCheckerRuntime_h_
+
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+ class MainThreadCheckerRuntime : public lldb_private::InstrumentationRuntime {
+ public:
+ ~MainThreadCheckerRuntime() override;
+
+ static lldb::InstrumentationRuntimeSP
+ CreateInstance(const lldb::ProcessSP &process_sp);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static lldb_private::ConstString GetPluginNameStatic();
+
+ static lldb::InstrumentationRuntimeType GetTypeStatic();
+
+ lldb_private::ConstString GetPluginName() override {
+ return GetPluginNameStatic();
+ }
+
+ virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); }
+
+ uint32_t GetPluginVersion() override { return 1; }
+
+ lldb::ThreadCollectionSP
+ GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override;
+
+ private:
+ MainThreadCheckerRuntime(const lldb::ProcessSP &process_sp)
+ : lldb_private::InstrumentationRuntime(process_sp) {}
+
+ const RegularExpression &GetPatternForRuntimeLibrary() override;
+
+ bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override;
+
+ void Activate() override;
+
+ void Deactivate();
+
+ static bool NotifyBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ StructuredData::ObjectSP RetrieveReportData(ExecutionContextRef exe_ctx_ref);
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_MainThreadCheckerRuntime_h_
diff --git a/source/Plugins/InstrumentationRuntime/ThreadSanitizer/CMakeLists.txt b/source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt
index db7c4a2518a1..4dcd34131b8e 100644
--- a/source/Plugins/InstrumentationRuntime/ThreadSanitizer/CMakeLists.txt
+++ b/source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt
@@ -1,5 +1,5 @@
-add_lldb_library(lldbPluginInstrumentationRuntimeThreadSanitizer PLUGIN
- ThreadSanitizerRuntime.cpp
+add_lldb_library(lldbPluginInstrumentationRuntimeTSan PLUGIN
+ TSanRuntime.cpp
LINK_LIBS
lldbBreakpoint
diff --git a/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp b/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp
index d7b518982fcf..f60df0463346 100644
--- a/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp
+++ b/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadSanitizerRuntime.cpp ------------------------------*- C++ -*-===//
+//===-- TSanRuntime.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "ThreadSanitizerRuntime.h"
+#include "TSanRuntime.h"
#include "Plugins/Process/Utility/HistoryThread.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
@@ -921,11 +921,6 @@ void ThreadSanitizerRuntime::Activate() {
breakpoint->SetBreakpointKind("thread-sanitizer-report");
SetBreakpointID(breakpoint->GetID());
- StreamFileSP stream_sp(process_sp->GetTarget().GetDebugger().GetOutputFile());
- if (stream_sp) {
- stream_sp->Printf("ThreadSanitizer debugger support is active.\n");
- }
-
SetActive(true);
}
diff --git a/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h b/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h
index 2a10582b65d2..2a10582b65d2 100644
--- a/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h
+++ b/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h
diff --git a/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt b/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt
new file mode 100644
index 000000000000..984bf86f83b5
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeUBSan PLUGIN
+ UBSanRuntime.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbExpression
+ lldbInterpreter
+ lldbSymbol
+ lldbTarget
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp b/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp
new file mode 100644
index 000000000000..023af84179aa
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp
@@ -0,0 +1,340 @@
+//===-- UBSanRuntime.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UBSanRuntime.h"
+
+#include "Plugins/Process/Utility/HistoryThread.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/UserExpression.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include <ctype.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+UndefinedBehaviorSanitizerRuntime::~UndefinedBehaviorSanitizerRuntime() {
+ Deactivate();
+}
+
+lldb::InstrumentationRuntimeSP
+UndefinedBehaviorSanitizerRuntime::CreateInstance(
+ const lldb::ProcessSP &process_sp) {
+ return InstrumentationRuntimeSP(
+ new UndefinedBehaviorSanitizerRuntime(process_sp));
+}
+
+void UndefinedBehaviorSanitizerRuntime::Initialize() {
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(),
+ "UndefinedBehaviorSanitizer instrumentation runtime plugin.",
+ CreateInstance, GetTypeStatic);
+}
+
+void UndefinedBehaviorSanitizerRuntime::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::ConstString
+UndefinedBehaviorSanitizerRuntime::GetPluginNameStatic() {
+ return ConstString("UndefinedBehaviorSanitizer");
+}
+
+lldb::InstrumentationRuntimeType
+UndefinedBehaviorSanitizerRuntime::GetTypeStatic() {
+ return eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer;
+}
+
+static const char *ub_sanitizer_retrieve_report_data_prefix = R"(
+extern "C" {
+void
+__ubsan_get_current_report_data(const char **OutIssueKind,
+ const char **OutMessage, const char **OutFilename, unsigned *OutLine,
+ unsigned *OutCol, char **OutMemoryAddr);
+}
+
+struct data {
+ const char *issue_kind;
+ const char *message;
+ const char *filename;
+ unsigned line;
+ unsigned col;
+ char *memory_addr;
+};
+)";
+
+static const char *ub_sanitizer_retrieve_report_data_command = R"(
+data t;
+__ubsan_get_current_report_data(&t.issue_kind, &t.message, &t.filename, &t.line,
+ &t.col, &t.memory_addr);
+t;
+)";
+
+static addr_t RetrieveUnsigned(ValueObjectSP return_value_sp,
+ ProcessSP process_sp,
+ const std::string &expression_path) {
+ return return_value_sp->GetValueForExpressionPath(expression_path.c_str())
+ ->GetValueAsUnsigned(0);
+}
+
+static std::string RetrieveString(ValueObjectSP return_value_sp,
+ ProcessSP process_sp,
+ const std::string &expression_path) {
+ addr_t ptr = RetrieveUnsigned(return_value_sp, process_sp, expression_path);
+ std::string str;
+ Status error;
+ process_sp->ReadCStringFromMemory(ptr, str, error);
+ return str;
+}
+
+StructuredData::ObjectSP UndefinedBehaviorSanitizerRuntime::RetrieveReportData(
+ ExecutionContextRef exe_ctx_ref) {
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp)
+ return StructuredData::ObjectSP();
+
+ ThreadSP thread_sp = exe_ctx_ref.GetThreadSP();
+ StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
+ ModuleSP runtime_module_sp = GetRuntimeModuleSP();
+ Target &target = process_sp->GetTarget();
+
+ if (!frame_sp)
+ return StructuredData::ObjectSP();
+
+ StreamFileSP Stream(target.GetDebugger().GetOutputFile());
+
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError(true);
+ options.SetTryAllThreads(true);
+ options.SetStopOthers(true);
+ options.SetIgnoreBreakpoints(true);
+ options.SetTimeout(std::chrono::seconds(2));
+ options.SetPrefix(ub_sanitizer_retrieve_report_data_prefix);
+ options.SetAutoApplyFixIts(false);
+ options.SetLanguage(eLanguageTypeObjC_plus_plus);
+
+ ValueObjectSP main_value;
+ ExecutionContext exe_ctx;
+ Status eval_error;
+ frame_sp->CalculateExecutionContext(exe_ctx);
+ ExpressionResults result = UserExpression::Evaluate(
+ exe_ctx, options, ub_sanitizer_retrieve_report_data_command, "",
+ main_value, eval_error);
+ if (result != eExpressionCompleted) {
+ target.GetDebugger().GetAsyncOutputStream()->Printf(
+ "Warning: Cannot evaluate UndefinedBehaviorSanitizer expression:\n%s\n",
+ eval_error.AsCString());
+ return StructuredData::ObjectSP();
+ }
+
+ // Gather the PCs of the user frames in the backtrace.
+ StructuredData::Array *trace = new StructuredData::Array();
+ auto trace_sp = StructuredData::ObjectSP(trace);
+ for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) {
+ const Address FCA =
+ thread_sp->GetStackFrameAtIndex(I)->GetFrameCodeAddress();
+ if (FCA.GetModule() == runtime_module_sp) // Skip PCs from the runtime.
+ continue;
+
+ lldb::addr_t PC = FCA.GetLoadAddress(&target);
+ trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC)));
+ }
+
+ std::string IssueKind = RetrieveString(main_value, process_sp, ".issue_kind");
+ std::string ErrMessage = RetrieveString(main_value, process_sp, ".message");
+ std::string Filename = RetrieveString(main_value, process_sp, ".filename");
+ unsigned Line = RetrieveUnsigned(main_value, process_sp, ".line");
+ unsigned Col = RetrieveUnsigned(main_value, process_sp, ".col");
+ uintptr_t MemoryAddr =
+ RetrieveUnsigned(main_value, process_sp, ".memory_addr");
+
+ auto *d = new StructuredData::Dictionary();
+ auto dict_sp = StructuredData::ObjectSP(d);
+ d->AddStringItem("instrumentation_class", "UndefinedBehaviorSanitizer");
+ d->AddStringItem("description", IssueKind);
+ d->AddStringItem("summary", ErrMessage);
+ d->AddStringItem("filename", Filename);
+ d->AddIntegerItem("line", Line);
+ d->AddIntegerItem("col", Col);
+ d->AddIntegerItem("memory_address", MemoryAddr);
+ d->AddIntegerItem("tid", thread_sp->GetID());
+ d->AddItem("trace", trace_sp);
+ return dict_sp;
+}
+
+static std::string GetStopReasonDescription(StructuredData::ObjectSP report) {
+ llvm::StringRef stop_reason_description_ref;
+ report->GetAsDictionary()->GetValueForKeyAsString("description",
+ stop_reason_description_ref);
+ std::string stop_reason_description = stop_reason_description_ref;
+
+ if (!stop_reason_description.size()) {
+ stop_reason_description = "Undefined behavior detected";
+ } else {
+ stop_reason_description[0] = toupper(stop_reason_description[0]);
+ for (unsigned I = 1; I < stop_reason_description.size(); ++I)
+ if (stop_reason_description[I] == '-')
+ stop_reason_description[I] = ' ';
+ }
+ return stop_reason_description;
+}
+
+bool UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit(
+ void *baton, StoppointCallbackContext *context, user_id_t break_id,
+ user_id_t break_loc_id) {
+ assert(baton && "null baton");
+ if (!baton)
+ return false; //< false => resume execution.
+
+ UndefinedBehaviorSanitizerRuntime *const instance =
+ static_cast<UndefinedBehaviorSanitizerRuntime *>(baton);
+
+ ProcessSP process_sp = instance->GetProcessSP();
+ ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
+ if (!process_sp || !thread_sp ||
+ process_sp != context->exe_ctx_ref.GetProcessSP())
+ return false;
+
+ StructuredData::ObjectSP report =
+ instance->RetrieveReportData(context->exe_ctx_ref);
+
+ if (report) {
+ thread_sp->SetStopInfo(
+ InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
+ *thread_sp, GetStopReasonDescription(report), report));
+ return true;
+ }
+
+ return false;
+}
+
+const RegularExpression &
+UndefinedBehaviorSanitizerRuntime::GetPatternForRuntimeLibrary() {
+ static RegularExpression regex(llvm::StringRef("libclang_rt\\.(a|t|ub)san_"));
+ return regex;
+}
+
+bool UndefinedBehaviorSanitizerRuntime::CheckIfRuntimeIsValid(
+ const lldb::ModuleSP module_sp) {
+ static ConstString ubsan_test_sym("__ubsan_on_report");
+ const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(
+ ubsan_test_sym, lldb::eSymbolTypeAny);
+ return symbol != nullptr;
+}
+
+// FIXME: Factor out all the logic we have in common with the {a,t}san plugins.
+void UndefinedBehaviorSanitizerRuntime::Activate() {
+ if (IsActive())
+ return;
+
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp)
+ return;
+
+ ModuleSP runtime_module_sp = GetRuntimeModuleSP();
+
+ ConstString symbol_name("__ubsan_on_report");
+ const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType(
+ symbol_name, eSymbolTypeCode);
+
+ if (symbol == nullptr)
+ return;
+
+ if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
+ return;
+
+ Target &target = process_sp->GetTarget();
+ addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
+
+ if (symbol_address == LLDB_INVALID_ADDRESS)
+ return;
+
+ Breakpoint *breakpoint =
+ process_sp->GetTarget()
+ .CreateBreakpoint(symbol_address, /*internal=*/true,
+ /*hardware=*/false)
+ .get();
+ breakpoint->SetCallback(
+ UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit, this, true);
+ breakpoint->SetBreakpointKind("undefined-behavior-sanitizer-report");
+ SetBreakpointID(breakpoint->GetID());
+
+ SetActive(true);
+}
+
+void UndefinedBehaviorSanitizerRuntime::Deactivate() {
+ SetActive(false);
+
+ auto BID = GetBreakpointID();
+ if (BID == LLDB_INVALID_BREAK_ID)
+ return;
+
+ if (ProcessSP process_sp = GetProcessSP()) {
+ process_sp->GetTarget().RemoveBreakpointByID(BID);
+ SetBreakpointID(LLDB_INVALID_BREAK_ID);
+ }
+}
+
+lldb::ThreadCollectionSP
+UndefinedBehaviorSanitizerRuntime::GetBacktracesFromExtendedStopInfo(
+ StructuredData::ObjectSP info) {
+ ThreadCollectionSP threads;
+ threads.reset(new ThreadCollection());
+
+ ProcessSP process_sp = GetProcessSP();
+
+ if (info->GetObjectForDotSeparatedPath("instrumentation_class")
+ ->GetStringValue() != "UndefinedBehaviorSanitizer")
+ return threads;
+
+ std::vector<lldb::addr_t> PCs;
+ auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray();
+ trace->ForEach([&PCs](StructuredData::Object *PC) -> bool {
+ PCs.push_back(PC->GetAsInteger()->GetValue());
+ return true;
+ });
+
+ if (PCs.empty())
+ return threads;
+
+ StructuredData::ObjectSP thread_id_obj =
+ info->GetObjectForDotSeparatedPath("tid");
+ tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;
+
+ uint32_t stop_id = 0;
+ bool stop_id_is_valid = false;
+ HistoryThread *history_thread =
+ new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid);
+ ThreadSP new_thread_sp(history_thread);
+ std::string stop_reason_description = GetStopReasonDescription(info);
+ new_thread_sp->SetName(stop_reason_description.c_str());
+
+ // Save this in the Process' ExtendedThreadList so a strong pointer
+ // retains the object
+ process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
+ threads->AddThread(new_thread_sp);
+
+ return threads;
+}
diff --git a/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h b/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h
new file mode 100644
index 000000000000..0c478bd57e82
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h
@@ -0,0 +1,69 @@
+//===-- UndefinedBehaviorSanitizerRuntime.h ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_UndefinedBehaviorSanitizerRuntime_h_
+#define liblldb_UndefinedBehaviorSanitizerRuntime_h_
+
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class UndefinedBehaviorSanitizerRuntime
+ : public lldb_private::InstrumentationRuntime {
+public:
+ ~UndefinedBehaviorSanitizerRuntime() override;
+
+ static lldb::InstrumentationRuntimeSP
+ CreateInstance(const lldb::ProcessSP &process_sp);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static lldb_private::ConstString GetPluginNameStatic();
+
+ static lldb::InstrumentationRuntimeType GetTypeStatic();
+
+ lldb_private::ConstString GetPluginName() override {
+ return GetPluginNameStatic();
+ }
+
+ virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); }
+
+ uint32_t GetPluginVersion() override { return 1; }
+
+ lldb::ThreadCollectionSP
+ GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override;
+
+private:
+ UndefinedBehaviorSanitizerRuntime(const lldb::ProcessSP &process_sp)
+ : lldb_private::InstrumentationRuntime(process_sp) {}
+
+ const RegularExpression &GetPatternForRuntimeLibrary() override;
+
+ bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override;
+
+ void Activate() override;
+
+ void Deactivate();
+
+ static bool NotifyBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ StructuredData::ObjectSP RetrieveReportData(ExecutionContextRef exe_ctx_ref);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_UndefinedBehaviorSanitizerRuntime_h_
diff --git a/source/Plugins/Language/ObjC/Cocoa.cpp b/source/Plugins/Language/ObjC/Cocoa.cpp
index dd3dc434f753..6aaf66cbb486 100644
--- a/source/Plugins/Language/ObjC/Cocoa.cpp
+++ b/source/Plugins/Language/ObjC/Cocoa.cpp
@@ -31,6 +31,8 @@
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/APInt.h"
+
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
#include "NSString.h"
@@ -369,6 +371,28 @@ static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream,
stream.Printf("%s%" PRId64 "%s", prefix.c_str(), value, suffix.c_str());
}
+static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream,
+ const llvm::APInt &value,
+ lldb::LanguageType lang) {
+ static ConstString g_TypeHint("NSNumber:int128_t");
+
+ std::string prefix, suffix;
+ if (Language *language = Language::FindPlugin(lang)) {
+ if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
+ suffix)) {
+ prefix.clear();
+ suffix.clear();
+ }
+ }
+
+ stream.PutCString(prefix.c_str());
+ const int radix = 10;
+ const bool isSigned = true;
+ std::string str = value.toString(radix, isSigned);
+ stream.PutCString(str.c_str());
+ stream.PutCString(suffix.c_str());
+}
+
static void NSNumber_FormatFloat(ValueObject &valobj, Stream &stream,
float value, lldb::LanguageType lang) {
static ConstString g_TypeHint("NSNumber:float");
@@ -462,22 +486,72 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
return true;
} else {
Status error;
- uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(
- valobj_addr + ptr_size, 1, 0, error) &
- 0x1F);
+
+ AppleObjCRuntime *runtime =
+ llvm::dyn_cast_or_null<AppleObjCRuntime>(
+ process_sp->GetObjCLanguageRuntime());
+
+ const bool new_format =
+ (runtime && runtime->GetFoundationVersion() >= 1400);
+
+ enum class TypeCodes : int {
+ sint8 = 0x0,
+ sint16 = 0x1,
+ sint32 = 0x2,
+ sint64 = 0x3,
+ f32 = 0x4,
+ f64 = 0x5,
+ sint128 = 0x6
+ };
+
uint64_t data_location = valobj_addr + 2 * ptr_size;
+ TypeCodes type_code;
+
+ if (new_format) {
+ uint64_t cfinfoa =
+ process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+
+ if (error.Fail())
+ return false;
+
+ bool is_preserved_number = cfinfoa & 0x8;
+ if (is_preserved_number) {
+ lldbassert(!"We should handle preserved numbers!");
+ return false;
+ }
+
+ type_code = (TypeCodes)(cfinfoa & 0x7);
+ } else {
+ uint8_t data_type =
+ process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1,
+ 0, error) & 0x1F;
+
+ if (error.Fail())
+ return false;
+
+ switch (data_type) {
+ case 1: type_code = TypeCodes::sint8; break;
+ case 2: type_code = TypeCodes::sint16; break;
+ case 3: type_code = TypeCodes::sint32; break;
+ case 17: data_location += 8; LLVM_FALLTHROUGH;
+ case 4: type_code = TypeCodes::sint64; break;
+ case 5: type_code = TypeCodes::f32; break;
+ case 6: type_code = TypeCodes::f64; break;
+ default: return false;
+ }
+ }
+
uint64_t value = 0;
- if (error.Fail())
- return false;
- switch (data_type) {
- case 1: // 0B00001
+ switch (type_code) {
+ case TypeCodes::sint8:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0,
error);
if (error.Fail())
return false;
NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
break;
- case 2: // 0B0010
+ case TypeCodes::sint16:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0,
error);
if (error.Fail())
@@ -485,24 +559,21 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
NSNumber_FormatShort(valobj, stream, (short)value,
options.GetLanguage());
break;
- case 3: // 0B0011
+ case TypeCodes::sint32:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0,
error);
if (error.Fail())
return false;
NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
break;
- case 17: // 0B10001
- data_location += 8;
- LLVM_FALLTHROUGH;
- case 4: // 0B0100
+ case TypeCodes::sint64:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0,
error);
if (error.Fail())
return false;
NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
break;
- case 5: // 0B0101
+ case TypeCodes::f32:
{
uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(
data_location, 4, 0, error);
@@ -513,7 +584,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
break;
}
- case 6: // 0B0110
+ case TypeCodes::f64:
{
uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(
data_location, 8, 0, error);
@@ -524,6 +595,21 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
break;
}
+ case TypeCodes::sint128: // internally, this is the same
+ {
+ uint64_t words[2];
+ words[1] = process_sp->ReadUnsignedIntegerFromMemory(
+ data_location, 8, 0, error);
+ if (error.Fail())
+ return false;
+ words[0] = process_sp->ReadUnsignedIntegerFromMemory(
+ data_location + 8, 8, 0, error);
+ if (error.Fail())
+ return false;
+ llvm::APInt i128_value(128, words);
+ NSNumber_FormatInt128(valobj, stream, i128_value, options.GetLanguage());
+ break;
+ }
default:
return false;
}
diff --git a/source/Plugins/Language/ObjC/NSArray.cpp b/source/Plugins/Language/ObjC/NSArray.cpp
index b07b9ba5888f..27cb9558c482 100644
--- a/source/Plugins/Language/ObjC/NSArray.cpp
+++ b/source/Plugins/Language/ObjC/NSArray.cpp
@@ -160,11 +160,47 @@ private:
DataDescriptor_64 *m_data_64;
};
-class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+class NSArrayMSyntheticFrontEnd_1400 : public NSArrayMSyntheticFrontEnd {
public:
- NSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+ NSArrayMSyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp);
- ~NSArrayISyntheticFrontEnd() override = default;
+ ~NSArrayMSyntheticFrontEnd_1400() override;
+
+ bool Update() override;
+
+protected:
+ lldb::addr_t GetDataAddress() override;
+
+ uint64_t GetUsedCount() override;
+
+ uint64_t GetOffset() override;
+
+ uint64_t GetSize() override;
+
+private:
+ struct DataDescriptor_32 {
+ uint32_t used;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t list;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t used;
+ uint64_t offset;
+ uint64_t size;
+ uint64_t list;
+ };
+
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+};
+
+class NSArrayISyntheticFrontEnd_1300 : public SyntheticChildrenFrontEnd {
+public:
+ NSArrayISyntheticFrontEnd_1300(lldb::ValueObjectSP valobj_sp);
+
+ ~NSArrayISyntheticFrontEnd_1300() override = default;
size_t CalculateNumChildren() override;
@@ -184,6 +220,45 @@ private:
CompilerType m_id_type;
};
+class NSArrayISyntheticFrontEnd_1400 : public SyntheticChildrenFrontEnd {
+public:
+ NSArrayISyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp);
+
+ ~NSArrayISyntheticFrontEnd_1400() override;
+
+ size_t CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+ bool Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(const ConstString &name) override;
+
+private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+
+ struct DataDescriptor_32 {
+ uint32_t used;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t list;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t used;
+ uint64_t offset;
+ uint64_t size;
+ uint64_t list;
+ };
+
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ CompilerType m_id_type;
+};
+
class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
@@ -257,6 +332,8 @@ bool lldb_private::formatters::NSArraySummaryProvider(
static const ConstString g_NSArray0("__NSArray0");
static const ConstString g_NSArray1("__NSSingleObjectArrayI");
static const ConstString g_NSArrayCF("__NSCFArray");
+ static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
+ static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
if (class_name.IsEmpty())
return false;
@@ -273,6 +350,18 @@ bool lldb_private::formatters::NSArraySummaryProvider(
ptr_size, 0, error);
if (error.Fail())
return false;
+ } else if (class_name == g_NSArrayMLegacy) {
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_NSArrayMImmutable) {
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
} else if (class_name == g_NSArray0) {
value = 0;
} else if (class_name == g_NSArray1) {
@@ -332,6 +421,11 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::
: NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr),
m_data_64(nullptr) {}
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::
+ NSArrayMSyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp)
+ : NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr),
+ m_data_64(nullptr) {}
+
size_t
lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren() {
return GetUsedCount();
@@ -416,6 +510,37 @@ bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::Update() {
return false;
}
+bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::Update() {
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
+ error);
+ } else {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
+ error);
+ }
+ if (error.Fail())
+ return false;
+ return false;
+}
+
bool lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren() {
return true;
}
@@ -498,7 +623,42 @@ uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetSize() {
return m_data_32 ? m_data_32->_size : m_data_64->_size;
}
-lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd(
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::
+ ~NSArrayMSyntheticFrontEnd_1400() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+lldb::addr_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetDataAddress() {
+ if (!m_data_32 && !m_data_64)
+ return LLDB_INVALID_ADDRESS;
+ return m_data_32 ? m_data_32->list : m_data_64->list;
+}
+
+uint64_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetUsedCount() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->used : m_data_64->used;
+}
+
+uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetOffset() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->offset : m_data_64->offset;
+}
+
+uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetSize() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->size : m_data_64->size;
+}
+
+
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::NSArrayISyntheticFrontEnd_1300(
lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
m_items(0), m_data_ptr(0) {
@@ -516,7 +676,7 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd(
}
size_t
-lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName(
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::GetIndexOfChildWithName(
const ConstString &name) {
const char *item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
@@ -526,11 +686,11 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName(
}
size_t
-lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren() {
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::CalculateNumChildren() {
return m_items;
}
-bool lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() {
+bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::Update() {
m_ptr_size = 0;
m_items = 0;
m_data_ptr = 0;
@@ -552,12 +712,12 @@ bool lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() {
return false;
}
-bool lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren() {
+bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::MightHaveChildren() {
return true;
}
lldb::ValueObjectSP
-lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex(
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::GetChildAtIndex(
size_t idx) {
if (idx >= CalculateNumChildren())
return lldb::ValueObjectSP();
@@ -575,6 +735,99 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex(
m_exe_ctx_ref, m_id_type);
}
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::NSArrayISyntheticFrontEnd_1400(
+ lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
+ m_data_32(nullptr), m_data_64(nullptr) {
+ if (valobj_sp) {
+ CompilerType type = valobj_sp->GetCompilerType();
+ if (type) {
+ ClangASTContext *ast = valobj_sp->GetExecutionContextRef()
+ .GetTargetSP()
+ ->GetScratchClangASTContext();
+ if (ast)
+ m_id_type = CompilerType(ast->getASTContext(),
+ ast->getASTContext()->ObjCBuiltinIdTy);
+ }
+ }
+}
+
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::~NSArrayISyntheticFrontEnd_1400() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+size_t
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::GetIndexOfChildWithName(
+ const ConstString &name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+ return UINT32_MAX;
+ return idx;
+}
+
+size_t
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::CalculateNumChildren() {
+ return m_data_32 ? m_data_32->used : m_data_64->used;
+}
+
+bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::Update() {
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
+ error);
+ } else {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
+ error);
+ }
+ if (error.Fail())
+ return false;
+ return false;
+}
+
+bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::GetChildAtIndex(
+ size_t idx) {
+ if (idx >= CalculateNumChildren())
+ return lldb::ValueObjectSP();
+ lldb::addr_t object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
+ object_at_idx += (idx * m_ptr_size);
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Status error;
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
+ m_exe_ctx_ref, m_id_type);
+}
+
lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(
lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp) {}
@@ -683,17 +936,24 @@ lldb_private::formatters::NSArraySyntheticFrontEndCreator(
static const ConstString g_NSArrayM("__NSArrayM");
static const ConstString g_NSArray0("__NSArray0");
static const ConstString g_NSArray1("__NSSingleObjectArrayI");
+ static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
+ static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
if (class_name.IsEmpty())
return nullptr;
if (class_name == g_NSArrayI) {
- return (new NSArrayISyntheticFrontEnd(valobj_sp));
+ if (runtime->GetFoundationVersion() >= 1400)
+ return (new NSArrayISyntheticFrontEnd_1400(valobj_sp));
+ else
+ return (new NSArrayISyntheticFrontEnd_1300(valobj_sp));
} else if (class_name == g_NSArray0) {
return (new NSArray0SyntheticFrontEnd(valobj_sp));
} else if (class_name == g_NSArray1) {
return (new NSArray1SyntheticFrontEnd(valobj_sp));
} else if (class_name == g_NSArrayM) {
+ if (runtime->GetFoundationVersion() >= 1400)
+ return (new NSArrayMSyntheticFrontEnd_1400(valobj_sp));
if (runtime->GetFoundationVersion() >= 1100)
return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp));
else
diff --git a/source/Plugins/Language/ObjC/NSDictionary.cpp b/source/Plugins/Language/ObjC/NSDictionary.cpp
index 6df83d52acca..50febbe39758 100644
--- a/source/Plugins/Language/ObjC/NSDictionary.cpp
+++ b/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -17,6 +17,8 @@
// Project includes
#include "NSDictionary.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
+
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
@@ -181,6 +183,52 @@ public:
private:
struct DataDescriptor_32 {
+ uint32_t used : 26;
+ uint32_t kvo : 1;
+ uint32_t size;
+ uint32_t buffer;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t used : 58;
+ uint32_t kvo : 1;
+ uint64_t size;
+ uint64_t buffer;
+ };
+
+ struct DictionaryItemDescriptor {
+ lldb::addr_t key_ptr;
+ lldb::addr_t val_ptr;
+ lldb::ValueObjectSP valobj_sp;
+ };
+
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ lldb::ByteOrder m_order;
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ CompilerType m_pair_type;
+ std::vector<DictionaryItemDescriptor> m_children;
+};
+
+class NSDictionaryMLegacySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSDictionaryMLegacySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~NSDictionaryMLegacySyntheticFrontEnd() override;
+
+ size_t CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+ bool Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(const ConstString &name) override;
+
+private:
+ struct DataDescriptor_32 {
uint32_t _used : 26;
uint32_t _kvo : 1;
uint32_t _size;
@@ -250,19 +298,21 @@ bool lldb_private::formatters::NSDictionarySummaryProvider(
static const ConstString g_DictionaryI("__NSDictionaryI");
static const ConstString g_DictionaryM("__NSDictionaryM");
+ static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
+ static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
if (class_name.IsEmpty())
return false;
- if (class_name == g_DictionaryI) {
+ if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
return false;
value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
- } else if (class_name == g_DictionaryM) {
+ } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) {
Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
@@ -311,9 +361,8 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
return nullptr;
- ObjCLanguageRuntime *runtime =
- (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
- lldb::eLanguageTypeObjC);
+ AppleObjCRuntime *runtime =
+ llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime());
if (!runtime)
return nullptr;
@@ -338,6 +387,8 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
static const ConstString g_DictionaryI("__NSDictionaryI");
static const ConstString g_DictionaryM("__NSDictionaryM");
static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
+ static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
+ static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
if (class_name.IsEmpty())
return nullptr;
@@ -345,7 +396,13 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
if (class_name == g_DictionaryI) {
return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
} else if (class_name == g_DictionaryM) {
- return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
+ if (runtime->GetFoundationVersion() > 1400) {
+ return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
+ } else {
+ return (new NSDictionaryMLegacySyntheticFrontEnd(valobj_sp));
+ }
+ } else if (class_name == g_DictionaryMLegacy) {
+ return (new NSDictionaryMLegacySyntheticFrontEnd(valobj_sp));
} else if (class_name == g_Dictionary1) {
return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
} else {
@@ -611,7 +668,7 @@ size_t lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::
CalculateNumChildren() {
if (!m_data_32 && !m_data_64)
return 0;
- return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+ return (m_data_32 ? m_data_32->used : m_data_64->used);
}
bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update() {
@@ -655,6 +712,165 @@ bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::
lldb::ValueObjectSP
lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(
size_t idx) {
+ lldb::addr_t m_keys_ptr;
+ lldb::addr_t m_values_ptr;
+ if (m_data_32) {
+ uint32_t size = m_data_32->size;
+ m_keys_ptr = m_data_32->buffer;
+ m_values_ptr = m_data_32->buffer + (m_ptr_size * size);
+ } else {
+ uint32_t size = m_data_64->size;
+ m_keys_ptr = m_data_64->buffer;
+ m_values_ptr = m_data_64->buffer + (m_ptr_size * size);
+ }
+
+ uint32_t num_children = CalculateNumChildren();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty()) {
+ // do the scan phase
+ lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ while (tries < num_children) {
+ key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
+ val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
+ ;
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Status error;
+ key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ test_idx++;
+
+ if (!key_at_idx || !val_at_idx)
+ continue;
+ tries++;
+
+ DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
+ lldb::ValueObjectSP()};
+
+ m_children.push_back(descriptor);
+ }
+ }
+
+ if (idx >= m_children.size()) // should never happen
+ return lldb::ValueObjectSP();
+
+ DictionaryItemDescriptor &dict_item = m_children[idx];
+ if (!dict_item.valobj_sp) {
+ if (!m_pair_type.IsValid()) {
+ TargetSP target_sp(m_backend.GetTargetSP());
+ if (!target_sp)
+ return ValueObjectSP();
+ m_pair_type = GetLLDBNSPairType(target_sp);
+ }
+ if (!m_pair_type.IsValid())
+ return ValueObjectSP();
+
+ DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
+
+ if (m_ptr_size == 8) {
+ uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ } else {
+ uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ }
+
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ DataExtractor data(buffer_sp, m_order, m_ptr_size);
+ dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
+ m_exe_ctx_ref, m_pair_type);
+ }
+ return dict_item.valobj_sp;
+}
+
+
+lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
+ NSDictionaryMLegacySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
+ m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
+ m_pair_type() {}
+
+lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
+ ~NSDictionaryMLegacySyntheticFrontEnd() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+size_t lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
+ GetIndexOfChildWithName(const ConstString &name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+ return UINT32_MAX;
+ return idx;
+}
+
+size_t lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
+ CalculateNumChildren() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+}
+
+bool lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::Update() {
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
+ error);
+ } else {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
+ error);
+ }
+ if (error.Fail())
+ return false;
+ return false;
+}
+
+bool lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::GetChildAtIndex(
+ size_t idx) {
lldb::addr_t m_keys_ptr =
(m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
lldb::addr_t m_values_ptr =
diff --git a/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/source/Plugins/Language/ObjC/ObjCLanguage.cpp
index 4d9227598cef..ea2eec7b33b7 100644
--- a/source/Plugins/Language/ObjC/ObjCLanguage.cpp
+++ b/source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -1026,6 +1026,7 @@ bool ObjCLanguage::GetFormatterPrefixSuffix(ValueObject &valobj,
static ConstString g_NSNumberShort("NSNumber:short");
static ConstString g_NSNumberInt("NSNumber:int");
static ConstString g_NSNumberLong("NSNumber:long");
+ static ConstString g_NSNumberInt128("NSNumber:int128_t");
static ConstString g_NSNumberFloat("NSNumber:float");
static ConstString g_NSNumberDouble("NSNumber:double");
@@ -1061,6 +1062,10 @@ bool ObjCLanguage::GetFormatterPrefixSuffix(ValueObject &valobj,
prefix = "(long)";
return true;
}
+ if (type_hint == g_NSNumberInt128) {
+ prefix = "(int128_t)";
+ return true;
+ }
if (type_hint == g_NSNumberFloat) {
prefix = "(float)";
return true;
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index b71d6fa4ebea..20e9a930b486 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -707,10 +707,7 @@ size_t ObjectFileELF::GetModuleSpecifications(
SectionHeaderColl section_headers;
lldb_private::UUID &uuid = spec.GetUUID();
- using namespace std::placeholders;
- const SetDataFunction set_data =
- std::bind(&ObjectFileELF::SetData, std::cref(data), _1, _2, _3);
- GetSectionHeaderInfo(section_headers, set_data, header, uuid,
+ GetSectionHeaderInfo(section_headers, data, header, uuid,
gnu_debuglink_file, gnu_debuglink_crc,
spec.GetArchitecture());
@@ -748,7 +745,7 @@ size_t ObjectFileELF::GetModuleSpecifications(
data.SetData(data_sp);
}
ProgramHeaderColl program_headers;
- GetProgramHeaderInfo(program_headers, set_data, header);
+ GetProgramHeaderInfo(program_headers, data, header);
size_t segment_data_end = 0;
for (ProgramHeaderCollConstIter I = program_headers.begin();
@@ -950,29 +947,7 @@ size_t ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const {
bool ObjectFileELF::ParseHeader() {
lldb::offset_t offset = 0;
- if (!m_header.Parse(m_data, &offset))
- return false;
-
- if (!IsInMemory())
- return true;
-
- // For in memory object files m_data might not contain the full object file.
- // Try to load it
- // until the end of the "Section header table" what is at the end of the ELF
- // file.
- addr_t file_size = m_header.e_shoff + m_header.e_shnum * m_header.e_shentsize;
- if (m_data.GetByteSize() < file_size) {
- ProcessSP process_sp(m_process_wp.lock());
- if (!process_sp)
- return false;
-
- DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size);
- if (!data_sp)
- return false;
- m_data.SetData(data_sp, 0, file_size);
- }
-
- return true;
+ return m_header.Parse(m_data, &offset);
}
bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) {
@@ -1188,7 +1163,7 @@ size_t ObjectFileELF::ParseDependentModules() {
// GetProgramHeaderInfo
//----------------------------------------------------------------------
size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
- const SetDataFunction &set_data,
+ DataExtractor &object_data,
const ELFHeader &header) {
// We have already parsed the program headers
if (!program_headers.empty())
@@ -1205,7 +1180,7 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
const size_t ph_size = header.e_phnum * header.e_phentsize;
const elf_off ph_offset = header.e_phoff;
DataExtractor data;
- if (set_data(data, ph_offset, ph_size) != ph_size)
+ if (data.SetData(object_data, ph_offset, ph_size) != ph_size)
return 0;
uint32_t idx;
@@ -1225,12 +1200,7 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
// ParseProgramHeaders
//----------------------------------------------------------------------
size_t ObjectFileELF::ParseProgramHeaders() {
- using namespace std::placeholders;
- return GetProgramHeaderInfo(
- m_program_headers,
- std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2,
- _3),
- m_header);
+ return GetProgramHeaderInfo(m_program_headers, m_data, m_header);
}
lldb_private::Status
@@ -1562,7 +1532,7 @@ void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length,
// GetSectionHeaderInfo
//----------------------------------------------------------------------
size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
- const SetDataFunction &set_data,
+ DataExtractor &object_data,
const elf::ELFHeader &header,
lldb_private::UUID &uuid,
std::string &gnu_debuglink_file,
@@ -1634,7 +1604,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
const size_t sh_size = header.e_shnum * header.e_shentsize;
const elf_off sh_offset = header.e_shoff;
DataExtractor sh_data;
- if (set_data(sh_data, sh_offset, sh_size) != sh_size)
+ if (sh_data.SetData(object_data, sh_offset, sh_size) != sh_size)
return 0;
uint32_t idx;
@@ -1653,7 +1623,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
const Elf64_Off offset = sheader.sh_offset;
lldb_private::DataExtractor shstr_data;
- if (set_data(shstr_data, offset, byte_size) == byte_size) {
+ if (shstr_data.SetData(object_data, offset, byte_size) == byte_size) {
for (SectionHeaderCollIter I = section_headers.begin();
I != section_headers.end(); ++I) {
static ConstString g_sect_name_gnu_debuglink(".gnu_debuglink");
@@ -1669,8 +1639,8 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
DataExtractor data;
if (sheader.sh_type == SHT_MIPS_ABIFLAGS) {
- if (section_size && (set_data(data, sheader.sh_offset,
- section_size) == section_size)) {
+ if (section_size && (data.SetData(object_data, sheader.sh_offset,
+ section_size) == section_size)) {
// MIPS ASE Mask is at offset 12 in MIPS.abiflags section
lldb::offset_t offset = 12; // MIPS ABI Flags Version: 0
arch_flags |= data.GetU32(&offset);
@@ -1723,7 +1693,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
// ABI Mask doesn't cover N32 and N64 ABI.
if (header.e_ident[EI_CLASS] == llvm::ELF::ELFCLASS64)
arch_flags |= lldb_private::ArchSpec::eMIPSABI_N64;
- else if (header.e_flags && llvm::ELF::EF_MIPS_ABI2)
+ else if (header.e_flags & llvm::ELF::EF_MIPS_ABI2)
arch_flags |= lldb_private::ArchSpec::eMIPSABI_N32;
break;
}
@@ -1735,14 +1705,14 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
DataExtractor data;
if (sheader.sh_type == SHT_ARM_ATTRIBUTES && section_size != 0 &&
- set_data(data, sheader.sh_offset, section_size) == section_size)
+ data.SetData(object_data, sheader.sh_offset, section_size) == section_size)
ParseARMAttributes(data, section_size, arch_spec);
}
if (name == g_sect_name_gnu_debuglink) {
DataExtractor data;
- if (section_size && (set_data(data, sheader.sh_offset,
- section_size) == section_size)) {
+ if (section_size && (data.SetData(object_data, sheader.sh_offset,
+ section_size) == section_size)) {
lldb::offset_t gnu_debuglink_offset = 0;
gnu_debuglink_file = data.GetCStr(&gnu_debuglink_offset);
gnu_debuglink_offset = llvm::alignTo(gnu_debuglink_offset, 4);
@@ -1762,8 +1732,8 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
if (is_note_header) {
// Allow notes to refine module info.
DataExtractor data;
- if (section_size && (set_data(data, sheader.sh_offset,
- section_size) == section_size)) {
+ if (section_size && (data.SetData(object_data, sheader.sh_offset,
+ section_size) == section_size)) {
Status error = RefineModuleDetailsFromNote(data, arch_spec, uuid);
if (error.Fail()) {
if (log)
@@ -1819,40 +1789,9 @@ ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const {
// ParseSectionHeaders
//----------------------------------------------------------------------
size_t ObjectFileELF::ParseSectionHeaders() {
- using namespace std::placeholders;
-
- return GetSectionHeaderInfo(
- m_section_headers,
- std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2,
- _3),
- m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc, m_arch_spec);
-}
-
-lldb::offset_t ObjectFileELF::SetData(const lldb_private::DataExtractor &src,
- lldb_private::DataExtractor &dst,
- lldb::offset_t offset,
- lldb::offset_t length) {
- return dst.SetData(src, offset, length);
-}
-
-lldb::offset_t
-ObjectFileELF::SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst,
- lldb::offset_t offset,
- lldb::offset_t length) {
- if (offset + length <= m_data.GetByteSize())
- return dst.SetData(m_data, offset, length);
-
- const auto process_sp = m_process_wp.lock();
- if (process_sp != nullptr) {
- addr_t file_size = offset + length;
-
- DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size);
- if (!data_sp)
- return false;
- m_data.SetData(data_sp, 0, file_size);
- }
-
- return dst.SetData(m_data, offset, length);
+ return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid,
+ m_gnu_debuglink_file, m_gnu_debuglink_crc,
+ m_arch_spec);
}
const ObjectFileELF::ELFSectionHeaderInfo *
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index 06f1a4d22d2d..6d8717b0ef25 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -14,7 +14,6 @@
#include <stdint.h>
// C++ Includes
-#include <functional>
#include <vector>
// Other libraries and framework includes
@@ -182,9 +181,6 @@ private:
typedef std::map<lldb::addr_t, lldb::AddressClass>
FileAddressToAddressClassMap;
- typedef std::function<lldb::offset_t(lldb_private::DataExtractor &,
- lldb::offset_t, lldb::offset_t)>
- SetDataFunction;
/// Version of this reader common to all plugins based on this class.
static const uint32_t m_plugin_version = 1;
@@ -230,7 +226,7 @@ private:
// Parses the ELF program headers.
static size_t GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
- const SetDataFunction &set_data,
+ lldb_private::DataExtractor &object_data,
const elf::ELFHeader &header);
// Finds PT_NOTE segments and calculates their crc sum.
@@ -255,7 +251,7 @@ private:
/// Parses the elf section headers and returns the uuid, debug link name, crc,
/// archspec.
static size_t GetSectionHeaderInfo(SectionHeaderColl &section_headers,
- const SetDataFunction &set_data,
+ lldb_private::DataExtractor &object_data,
const elf::ELFHeader &header,
lldb_private::UUID &uuid,
std::string &gnu_debuglink_file,
@@ -379,14 +375,6 @@ private:
RefineModuleDetailsFromNote(lldb_private::DataExtractor &data,
lldb_private::ArchSpec &arch_spec,
lldb_private::UUID &uuid);
-
- static lldb::offset_t SetData(const lldb_private::DataExtractor &src,
- lldb_private::DataExtractor &dst,
- lldb::offset_t offset, lldb::offset_t length);
-
- lldb::offset_t SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst,
- lldb::offset_t offset,
- lldb::offset_t length);
};
#endif // liblldb_ObjectFileELF_h_
diff --git a/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp b/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
index f6c8c78ccb73..518f0d2da4f2 100644
--- a/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
+++ b/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
@@ -1085,8 +1085,7 @@ Status NativeProcessDarwin::HandleWaitpidResult() {
"waitpid exiting pid from the pipe. Will notify "
"as if parent process died with exit status -1.",
__FUNCTION__);
- SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result",
- notify_status);
+ SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status);
return error;
}
@@ -1099,8 +1098,7 @@ Status NativeProcessDarwin::HandleWaitpidResult() {
"waitpid exit status from the pipe. Will notify "
"as if parent process died with exit status -1.",
__FUNCTION__);
- SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result",
- notify_status);
+ SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status);
return error;
}
@@ -1111,18 +1109,7 @@ Status NativeProcessDarwin::HandleWaitpidResult() {
__FUNCTION__, pid,
(pid == m_pid) ? "the inferior" : "not the inferior", status);
- ExitType exit_type = eExitTypeInvalid;
- int exit_status = -1;
-
- if (WIFEXITED(status)) {
- exit_type = eExitTypeExit;
- exit_status = WEXITSTATUS(status);
- } else if (WIFSIGNALED(status)) {
- exit_type = eExitTypeSignal;
- exit_status = WTERMSIG(status);
- }
-
- SetExitStatus(exit_type, exit_status, nullptr, notify_status);
+ SetExitStatus(WaitStatus::Decode(status), notify_status);
return error;
}
diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index a130472c72d0..e39a1788fc00 100644
--- a/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -503,35 +503,9 @@ Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) {
return PtraceWrapper(PTRACE_SETOPTIONS, pid, nullptr, (void *)ptrace_opts);
}
-static ExitType convert_pid_status_to_exit_type(int status) {
- if (WIFEXITED(status))
- return ExitType::eExitTypeExit;
- else if (WIFSIGNALED(status))
- return ExitType::eExitTypeSignal;
- else if (WIFSTOPPED(status))
- return ExitType::eExitTypeStop;
- else {
- // We don't know what this is.
- return ExitType::eExitTypeInvalid;
- }
-}
-
-static int convert_pid_status_to_return_code(int status) {
- if (WIFEXITED(status))
- return WEXITSTATUS(status);
- else if (WIFSIGNALED(status))
- return WTERMSIG(status);
- else if (WIFSTOPPED(status))
- return WSTOPSIG(status);
- else {
- // We don't know what this is.
- return ExitType::eExitTypeInvalid;
- }
-}
-
// Handles all waitpid events from the inferior process.
void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited,
- int signal, int status) {
+ WaitStatus status) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
// Certain activities differ based on whether the pid is the tid of the main
@@ -564,8 +538,7 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited,
: "thread metadata not found",
GetState());
// The main thread exited. We're done monitoring. Report to delegate.
- SetExitStatus(convert_pid_status_to_exit_type(status),
- convert_pid_status_to_return_code(status), nullptr, true);
+ SetExitStatus(status, true);
// Notify delegate that our process has exited.
SetState(StateType::eStateExited, true);
@@ -658,8 +631,7 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited,
// Notify the delegate - our process is not available but appears to
// have been killed outside
// our control. Is eStateExited the right exit state in this case?
- SetExitStatus(convert_pid_status_to_exit_type(status),
- convert_pid_status_to_return_code(status), nullptr, true);
+ SetExitStatus(status, true);
SetState(StateType::eStateExited, true);
} else {
// This thread was pulled out from underneath us. Anything to do here?
@@ -830,10 +802,8 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info,
data, WIFEXITED(data), WIFSIGNALED(data), thread.GetID(),
is_main_thread);
- if (is_main_thread) {
- SetExitStatus(convert_pid_status_to_exit_type(data),
- convert_pid_status_to_return_code(data), nullptr, true);
- }
+ if (is_main_thread)
+ SetExitStatus(WaitStatus::Decode(data), true);
StateType state = thread.GetState();
if (!StateIsRunningState(state)) {
@@ -2384,33 +2354,17 @@ void NativeProcessLinux::SigchldHandler() {
break;
}
- bool exited = false;
- int signal = 0;
- int exit_status = 0;
- const char *status_cstr = nullptr;
- if (WIFSTOPPED(status)) {
- signal = WSTOPSIG(status);
- status_cstr = "STOPPED";
- } else if (WIFEXITED(status)) {
- exit_status = WEXITSTATUS(status);
- status_cstr = "EXITED";
- exited = true;
- } else if (WIFSIGNALED(status)) {
- signal = WTERMSIG(status);
- status_cstr = "SIGNALED";
- if (wait_pid == static_cast<::pid_t>(GetID())) {
- exited = true;
- exit_status = -1;
- }
- } else
- status_cstr = "(\?\?\?)";
+ WaitStatus wait_status = WaitStatus::Decode(status);
+ bool exited = wait_status.type == WaitStatus::Exit ||
+ (wait_status.type == WaitStatus::Signal &&
+ wait_pid == static_cast<::pid_t>(GetID()));
- LLDB_LOG(log,
- "waitpid (-1, &status, _) => pid = {0}, status = {1:x} "
- "({2}), signal = {3}, exit_state = {4}",
- wait_pid, status, status_cstr, signal, exit_status);
+ LLDB_LOG(
+ log,
+ "waitpid (-1, &status, _) => pid = {0}, status = {1}, exited = {2}",
+ wait_pid, wait_status, exited);
- MonitorCallback(wait_pid, exited, signal, exit_status);
+ MonitorCallback(wait_pid, exited, wait_status);
}
}
diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.h b/source/Plugins/Process/Linux/NativeProcessLinux.h
index 98fc88baab6e..aa6fe4412068 100644
--- a/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ b/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -153,7 +153,7 @@ private:
static void *MonitorThread(void *baton);
- void MonitorCallback(lldb::pid_t pid, bool exited, int signal, int status);
+ void MonitorCallback(lldb::pid_t pid, bool exited, WaitStatus status);
void WaitForNewThread(::pid_t tid);
diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
index efb19fc414f9..a4d775860a65 100644
--- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -40,32 +40,6 @@ using namespace lldb_private;
using namespace lldb_private::process_netbsd;
using namespace llvm;
-static ExitType convert_pid_status_to_exit_type(int status) {
- if (WIFEXITED(status))
- return ExitType::eExitTypeExit;
- else if (WIFSIGNALED(status))
- return ExitType::eExitTypeSignal;
- else if (WIFSTOPPED(status))
- return ExitType::eExitTypeStop;
- else {
- // We don't know what this is.
- return ExitType::eExitTypeInvalid;
- }
-}
-
-static int convert_pid_status_to_return_code(int status) {
- if (WIFEXITED(status))
- return WEXITSTATUS(status);
- else if (WIFSIGNALED(status))
- return WTERMSIG(status);
- else if (WIFSTOPPED(status))
- return WSTOPSIG(status);
- else {
- // We don't know what this is.
- return ExitType::eExitTypeInvalid;
- }
-}
-
// Simple helper function to ensure flags are enabled on the given file
// descriptor.
static Status EnsureFDFlags(int fd, int flags) {
@@ -177,17 +151,15 @@ void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
}
}
-void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, int signal,
- int status) {
+void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
- LLDB_LOG(log, "got exit signal({0}) , pid = {1}", signal, pid);
+ LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
/* Stop Tracking All Threads attached to Process */
m_threads.clear();
- SetExitStatus(convert_pid_status_to_exit_type(status),
- convert_pid_status_to_return_code(status), nullptr, true);
+ SetExitStatus(status, true);
// Notify delegate that our process has exited.
SetState(StateType::eStateExited, true);
@@ -861,36 +833,21 @@ void NativeProcessNetBSD::SigchldHandler() {
LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
}
- bool exited = false;
- int signal = 0;
- int exit_status = 0;
- const char *status_cstr = nullptr;
- if (WIFSTOPPED(status)) {
- signal = WSTOPSIG(status);
- status_cstr = "STOPPED";
- } else if (WIFEXITED(status)) {
- exit_status = WEXITSTATUS(status);
- status_cstr = "EXITED";
- exited = true;
- } else if (WIFSIGNALED(status)) {
- signal = WTERMSIG(status);
- status_cstr = "SIGNALED";
- if (wait_pid == static_cast<::pid_t>(GetID())) {
- exited = true;
- exit_status = -1;
- }
- } else
- status_cstr = "(\?\?\?)";
+ WaitStatus wait_status = WaitStatus::Decode(status);
+ bool exited = wait_status.type == WaitStatus::Exit ||
+ (wait_status.type == WaitStatus::Signal &&
+ wait_pid == static_cast<::pid_t>(GetID()));
LLDB_LOG(log,
- "waitpid ({0}, &status, _) => pid = {1}, status = {2:x} "
- "({3}), signal = {4}, exit_state = {5}",
- GetID(), wait_pid, status, status_cstr, signal, exit_status);
+ "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
+ GetID(), wait_pid, status, exited);
if (exited)
- MonitorExited(wait_pid, signal, exit_status);
- else
- MonitorCallback(wait_pid, signal);
+ MonitorExited(wait_pid, wait_status);
+ else {
+ assert(wait_status.type == WaitStatus::Stop);
+ MonitorCallback(wait_pid, wait_status.status);
+ }
}
bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {
diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
index 758956e3dca1..7a1303faea68 100644
--- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -123,7 +123,7 @@ private:
void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error);
void MonitorCallback(lldb::pid_t pid, int signal);
- void MonitorExited(lldb::pid_t pid, int signal, int status);
+ void MonitorExited(lldb::pid_t pid, WaitStatus status);
void MonitorSIGSTOP(lldb::pid_t pid);
void MonitorSIGTRAP(lldb::pid_t pid);
void MonitorSignal(lldb::pid_t pid, int signal);
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index d318c35366f1..d34a79453fed 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -370,53 +370,23 @@ GDBRemoteCommunicationServerLLGS::SendWResponse(
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
// send W notification
- ExitType exit_type = ExitType::eExitTypeInvalid;
- int return_code = 0;
- std::string exit_description;
-
- const bool got_exit_info =
- process->GetExitStatus(&exit_type, &return_code, exit_description);
- if (!got_exit_info) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- ", failed to retrieve process exit status",
- __FUNCTION__, process->GetID());
+ auto wait_status = process->GetExitStatus();
+ if (!wait_status) {
+ LLDB_LOG(log, "pid = {0}, failed to retrieve process exit status",
+ process->GetID());
StreamGDBRemote response;
response.PutChar('E');
response.PutHex8(GDBRemoteServerError::eErrorExitStatus);
return SendPacketNoLock(response.GetString());
- } else {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- ", returning exit type %d, return code %d [%s]",
- __FUNCTION__, process->GetID(), exit_type, return_code,
- exit_description.c_str());
-
- StreamGDBRemote response;
-
- char return_type_code;
- switch (exit_type) {
- case ExitType::eExitTypeExit:
- return_type_code = 'W';
- break;
- case ExitType::eExitTypeSignal:
- return_type_code = 'X';
- break;
- case ExitType::eExitTypeStop:
- return_type_code = 'S';
- break;
- case ExitType::eExitTypeInvalid:
- return_type_code = 'E';
- break;
- }
- response.PutChar(return_type_code);
+ }
- // POSIX exit status limited to unsigned 8 bits.
- response.PutHex8(return_code);
+ LLDB_LOG(log, "pid = {0}, returning exit type {1}", process->GetID(),
+ *wait_status);
- return SendPacketNoLock(response.GetString());
- }
+ StreamGDBRemote response;
+ response.Format("{0:g}", *wait_status);
+ return SendPacketNoLock(response.GetString());
}
static void AppendHexValue(StreamString &response, const uint8_t *buf,
diff --git a/unittests/Host/CMakeLists.txt b/unittests/Host/CMakeLists.txt
index 7b2ce3bbfde5..0c42eb533fa0 100644
--- a/unittests/Host/CMakeLists.txt
+++ b/unittests/Host/CMakeLists.txt
@@ -1,6 +1,7 @@
set (FILES
FileSpecTest.cpp
FileSystemTest.cpp
+ HostTest.cpp
MainLoopTest.cpp
SocketAddressTest.cpp
SocketTest.cpp
diff --git a/unittests/Host/HostTest.cpp b/unittests/Host/HostTest.cpp
new file mode 100644
index 000000000000..14a459ebf257
--- /dev/null
+++ b/unittests/Host/HostTest.cpp
@@ -0,0 +1,22 @@
+//===-- HostTest.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Host.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace llvm;
+
+TEST(Host, WaitStatusFormat) {
+ EXPECT_EQ("W01", formatv("{0:g}", WaitStatus{WaitStatus::Exit, 1}).str());
+ EXPECT_EQ("X02", formatv("{0:g}", WaitStatus{WaitStatus::Signal, 2}).str());
+ EXPECT_EQ("S03", formatv("{0:g}", WaitStatus{WaitStatus::Stop, 3}).str());
+ EXPECT_EQ("Exited with status 4",
+ formatv("{0}", WaitStatus{WaitStatus::Exit, 4}).str());
+}
diff --git a/unittests/Process/gdb-remote/CMakeLists.txt b/unittests/Process/gdb-remote/CMakeLists.txt
index 694ba182d42f..0ec5554a3d8d 100644
--- a/unittests/Process/gdb-remote/CMakeLists.txt
+++ b/unittests/Process/gdb-remote/CMakeLists.txt
@@ -9,6 +9,9 @@ add_lldb_unittest(ProcessGdbRemoteTests
lldbPluginPlatformMacOSX
lldbPluginProcessUtility
lldbPluginProcessGDBRemote
+
+ LLVMTestingSupport
+
LINK_COMPONENTS
Support
)
diff --git a/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp b/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
index 5e709815b2d5..22b7148af5ba 100644
--- a/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
+++ b/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
@@ -14,8 +14,8 @@
#include "Plugins/Process/gdb-remote/GDBRemoteClientBase.h"
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
#include "lldb/Utility/StreamGDBRemote.h"
-
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Testing/Support/Error.h"
using namespace lldb_private::process_gdb_remote;
using namespace lldb_private;
@@ -45,13 +45,20 @@ struct TestClient : public GDBRemoteClientBase {
}
};
-struct ContinueFixture {
- MockDelegate delegate;
+class GDBRemoteClientBaseTest : public GDBRemoteTest {
+public:
+ void SetUp() override {
+ ASSERT_THAT_ERROR(Connect(client, server), llvm::Succeeded());
+ ASSERT_EQ(TestClient::eBroadcastBitRunPacketSent,
+ listener_sp->StartListeningForEvents(
+ &client, TestClient::eBroadcastBitRunPacketSent));
+ }
+
+protected:
TestClient client;
MockServer server;
- ListenerSP listener_sp;
-
- ContinueFixture();
+ MockDelegate delegate;
+ ListenerSP listener_sp = Listener::MakeListener("listener");
StateType SendCPacket(StringExtractorGDBRemote &response) {
return client.SendContinuePacketAndWaitForResponse(delegate, LinuxSignals(),
@@ -65,76 +72,61 @@ struct ContinueFixture {
}
};
-ContinueFixture::ContinueFixture()
- : listener_sp(Listener::MakeListener("listener")) {
- Connect(client, server);
- listener_sp->StartListeningForEvents(&client,
- TestClient::eBroadcastBitRunPacketSent);
-}
-
} // end anonymous namespace
-class GDBRemoteClientBaseTest : public GDBRemoteTest {};
-
TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) {
StringExtractorGDBRemote response;
- ContinueFixture fix;
- if (HasFailure())
- return;
// Continue. The inferior will stop with a signal.
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
- ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, SendCPacket(response));
ASSERT_EQ("T01", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
// Continue. The inferior will exit.
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("W01"));
- ASSERT_EQ(eStateExited, fix.SendCPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("W01"));
+ ASSERT_EQ(eStateExited, SendCPacket(response));
ASSERT_EQ("W01", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
// Continue. The inferior will get killed.
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("X01"));
- ASSERT_EQ(eStateExited, fix.SendCPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("X01"));
+ ASSERT_EQ(eStateExited, SendCPacket(response));
ASSERT_EQ("X01", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
}
TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) {
StringExtractorGDBRemote continue_response, response;
- ContinueFixture fix;
- if (HasFailure())
- return;
// SendAsyncSignal should do nothing when we are not running.
- ASSERT_FALSE(fix.client.SendAsyncSignal(0x47));
+ ASSERT_FALSE(client.SendAsyncSignal(0x47));
// Continue. After the run packet is sent, send an async signal.
std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return fix.SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
- fix.WaitForRunEvent();
+ WaitForRunEvent();
std::future<bool> async_result = std::async(
- std::launch::async, [&] { return fix.client.SendAsyncSignal(0x47); });
+ std::launch::async, [&] { return client.SendAsyncSignal(0x47); });
// First we'll get interrupted.
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
// Then we get the signal packet.
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("C47", response.GetStringRef());
ASSERT_TRUE(async_result.get());
// And we report back a signal stop.
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T47"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T47"));
ASSERT_EQ(eStateStopped, continue_state.get());
ASSERT_EQ("T47", continue_response.GetStringRef());
}
@@ -142,72 +134,66 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) {
TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncPacket) {
StringExtractorGDBRemote continue_response, async_response, response;
const bool send_async = true;
- ContinueFixture fix;
- if (HasFailure())
- return;
// Continue. After the run packet is sent, send an async packet.
std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return fix.SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
- fix.WaitForRunEvent();
+ WaitForRunEvent();
// Sending without async enabled should fail.
ASSERT_EQ(
PacketResult::ErrorSendFailed,
- fix.client.SendPacketAndWaitForResponse("qTest1", response, !send_async));
+ client.SendPacketAndWaitForResponse("qTest1", response, !send_async));
std::future<PacketResult> async_result = std::async(std::launch::async, [&] {
- return fix.client.SendPacketAndWaitForResponse("qTest2", async_response,
- send_async);
+ return client.SendPacketAndWaitForResponse("qTest2", async_response,
+ send_async);
});
// First we'll get interrupted.
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
// Then we get the async packet.
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("qTest2", response.GetStringRef());
// Send the response and receive it.
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("QTest2"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest2"));
ASSERT_EQ(PacketResult::Success, async_result.get());
ASSERT_EQ("QTest2", async_response.GetStringRef());
// And we get resumed again.
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, continue_state.get());
ASSERT_EQ("T01", continue_response.GetStringRef());
}
TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) {
StringExtractorGDBRemote continue_response, response;
- ContinueFixture fix;
- if (HasFailure())
- return;
// Interrupt should do nothing when we're not running.
- ASSERT_FALSE(fix.client.Interrupt());
+ ASSERT_FALSE(client.Interrupt());
// Continue. After the run packet is sent, send an interrupt.
std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return fix.SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
- fix.WaitForRunEvent();
+ WaitForRunEvent();
std::future<bool> async_result =
- std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
+ std::async(std::launch::async, [&] { return client.Interrupt(); });
// We get interrupted.
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
// And that's it.
ASSERT_EQ(eStateStopped, continue_state.get());
@@ -217,62 +203,56 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) {
TEST_F(GDBRemoteClientBaseTest, SendContinueAndLateInterrupt) {
StringExtractorGDBRemote continue_response, response;
- ContinueFixture fix;
- if (HasFailure())
- return;
// Continue. After the run packet is sent, send an interrupt.
std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return fix.SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
- fix.WaitForRunEvent();
+ WaitForRunEvent();
std::future<bool> async_result =
- std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
+ std::async(std::launch::async, [&] { return client.Interrupt(); });
// However, the target stops due to a different reason than the original
// interrupt.
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, continue_state.get());
ASSERT_EQ("T01", continue_response.GetStringRef());
ASSERT_TRUE(async_result.get());
// The subsequent continue packet should work normally.
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
- ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, SendCPacket(response));
ASSERT_EQ("T01", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
}
TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) {
StringExtractorGDBRemote continue_response, async_response, response;
const bool send_async = true;
- ContinueFixture fix;
- if (HasFailure())
- return;
// Interrupt should do nothing when we're not running.
- ASSERT_FALSE(fix.client.Interrupt());
+ ASSERT_FALSE(client.Interrupt());
// Continue. After the run packet is sent, send an async signal.
std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return fix.SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
- fix.WaitForRunEvent();
+ WaitForRunEvent();
std::future<bool> interrupt_result =
- std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
+ std::async(std::launch::async, [&] { return client.Interrupt(); });
// We get interrupted. We'll send two packets to simulate a buggy stub.
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
// We should stop.
ASSERT_EQ(eStateStopped, continue_state.get());
@@ -281,37 +261,34 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) {
// Packet stream should remain synchronized.
std::future<PacketResult> send_result = std::async(std::launch::async, [&] {
- return fix.client.SendPacketAndWaitForResponse("qTest", async_response,
- !send_async);
+ return client.SendPacketAndWaitForResponse("qTest", async_response,
+ !send_async);
});
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("qTest", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("QTest"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest"));
ASSERT_EQ(PacketResult::Success, send_result.get());
ASSERT_EQ("QTest", async_response.GetStringRef());
}
TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateInterface) {
StringExtractorGDBRemote response;
- ContinueFixture fix;
- if (HasFailure())
- return;
// Continue. We'll have the server send a bunch of async packets before it
// stops.
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("O4142"));
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("Apro"));
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("O4344"));
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("Afile"));
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
- ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("O4142"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("Apro"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("O4344"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("Afile"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, SendCPacket(response));
ASSERT_EQ("T01", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
- EXPECT_EQ("ABCD", fix.delegate.output);
- EXPECT_EQ("profile", fix.delegate.misc_data);
- EXPECT_EQ(1u, fix.delegate.stop_reply_called);
+ EXPECT_EQ("ABCD", delegate.output);
+ EXPECT_EQ("profile", delegate.misc_data);
+ EXPECT_EQ(1u, delegate.stop_reply_called);
}
TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) {
@@ -327,42 +304,35 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) {
stream.PutEscapedBytes(json_packet.c_str(), json_packet.length());
stream.Flush();
- // Set up the
StringExtractorGDBRemote response;
- ContinueFixture fix;
- if (HasFailure())
- return;
// Send async structured data packet, then stop.
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket(stream.GetData()));
- ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
- ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket(stream.GetData()));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, SendCPacket(response));
ASSERT_EQ("T01", response.GetStringRef());
- ASSERT_EQ(1ul, fix.delegate.structured_data_packets.size());
+ ASSERT_EQ(1ul, delegate.structured_data_packets.size());
// Verify the packet contents. It should have been unescaped upon packet
// reception.
- ASSERT_EQ(json_packet, fix.delegate.structured_data_packets[0]);
+ ASSERT_EQ(json_packet, delegate.structured_data_packets[0]);
}
TEST_F(GDBRemoteClientBaseTest, InterruptNoResponse) {
StringExtractorGDBRemote continue_response, response;
- ContinueFixture fix;
- if (HasFailure())
- return;
// Continue. After the run packet is sent, send an interrupt.
std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return fix.SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
- fix.WaitForRunEvent();
+ WaitForRunEvent();
std::future<bool> async_result =
- std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
+ std::async(std::launch::async, [&] { return client.Interrupt(); });
// We get interrupted, but we don't send a stop packet.
- ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
// The functions should still terminate (after a timeout).
diff --git a/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
index 8f6f9f0684a3..cd2583bb8f54 100644
--- a/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ b/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -11,14 +11,14 @@
#include "GDBRemoteTestUtils.h"
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
-#include "lldb/lldb-enumerations.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Core/TraceOptions.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Utility/DataBuffer.h"
-
+#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Testing/Support/Error.h"
using namespace lldb_private::process_gdb_remote;
using namespace lldb_private;
@@ -58,15 +58,18 @@ std::string one_register_hex = "41424344";
} // end anonymous namespace
-class GDBRemoteCommunicationClientTest : public GDBRemoteTest {};
+class GDBRemoteCommunicationClientTest : public GDBRemoteTest {
+public:
+ void SetUp() override {
+ ASSERT_THAT_ERROR(Connect(client, server), llvm::Succeeded());
+ }
-TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
+protected:
TestClient client;
MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
+};
+TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
const lldb::tid_t tid = 0x47;
const uint32_t reg_num = 4;
std::future<bool> write_result = std::async(std::launch::async, [&] {
@@ -87,12 +90,6 @@ TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
}
TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
const lldb::tid_t tid = 0x47;
const uint32_t reg_num = 4;
std::future<bool> write_result = std::async(std::launch::async, [&] {
@@ -113,12 +110,6 @@ TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {
}
TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
const lldb::tid_t tid = 0x47;
const uint32_t reg_num = 4;
std::future<bool> async_result = std::async(
@@ -145,12 +136,6 @@ TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) {
}
TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
const lldb::tid_t tid = 0x47;
uint32_t save_id;
std::future<bool> async_result = std::async(std::launch::async, [&] {
@@ -170,12 +155,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
}
TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
const lldb::tid_t tid = 0x47;
std::future<bool> async_result = std::async(
std::launch::async, [&] { return client.SyncThreadState(tid); });
@@ -185,12 +164,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
}
TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
llvm::Triple triple("i386-pc-linux");
FileSpec file_specs[] = {
@@ -225,12 +198,6 @@ TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
}
TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
llvm::Triple triple("i386-pc-linux");
FileSpec file_spec("/foo/bar.so", false, FileSpec::ePathSyntaxPosix);
@@ -267,13 +234,7 @@ TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {
}
TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
- std::thread server_thread([&server] {
+ std::thread server_thread([this] {
for (;;) {
StringExtractorGDBRemote request;
PacketResult result = server.GetPacket(request);
@@ -312,12 +273,6 @@ TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
std::future<Status> result = std::async(std::launch::async, [&] {
return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11});
});
@@ -334,12 +289,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {
}
TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
const lldb::addr_t addr = 0xa000;
MemoryRegionInfo region_info;
std::future<Status> result = std::async(std::launch::async, [&] {
@@ -355,12 +304,6 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {
}
TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
const lldb::addr_t addr = 0x4000;
MemoryRegionInfo region_info;
std::future<Status> result = std::async(std::launch::async, [&] {
@@ -372,12 +315,6 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
TraceOptions options;
Status error;
@@ -417,12 +354,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendStopTracePacket) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
lldb::tid_t thread_id = 0x23;
lldb::user_id_t trace_id = 3;
@@ -444,12 +375,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendStopTracePacket) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
lldb::tid_t thread_id = 0x23;
lldb::user_id_t trace_id = 3;
@@ -482,12 +407,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
lldb::tid_t thread_id = 0x23;
lldb::user_id_t trace_id = 3;
@@ -520,12 +439,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) {
- TestClient client;
- MockServer server;
- Connect(client, server);
- if (HasFailure())
- return;
-
lldb::tid_t thread_id = 0x23;
lldb::user_id_t trace_id = 3;
TraceOptions options;
diff --git a/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp b/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp
index 4a86b91c0489..2acf72744d20 100644
--- a/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp
+++ b/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp
@@ -30,30 +30,33 @@ void GDBRemoteTest::TearDownTestCase() {
#endif
}
-void Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server) {
+llvm::Error GDBRemoteTest::Connect(GDBRemoteCommunication &client,
+ GDBRemoteCommunication &server) {
bool child_processes_inherit = false;
- Status error;
TCPSocket listen_socket(true, child_processes_inherit);
- ASSERT_FALSE(error.Fail());
- error = listen_socket.Listen("127.0.0.1:0", 5);
- ASSERT_FALSE(error.Fail());
+ if (llvm::Error error = listen_socket.Listen("127.0.0.1:0", 5).ToError())
+ return error;
Socket *accept_socket;
- std::future<Status> accept_error = std::async(
+ std::future<Status> accept_status = std::async(
std::launch::async, [&] { return listen_socket.Accept(accept_socket); });
- char connect_remote_address[64];
- snprintf(connect_remote_address, sizeof(connect_remote_address),
- "connect://localhost:%u", listen_socket.GetLocalPortNumber());
+ llvm::SmallString<32> remote_addr;
+ llvm::raw_svector_ostream(remote_addr)
+ << "connect://localhost:" << listen_socket.GetLocalPortNumber();
- std::unique_ptr<ConnectionFileDescriptor> conn_ap(
+ std::unique_ptr<ConnectionFileDescriptor> conn_up(
new ConnectionFileDescriptor());
- ASSERT_EQ(conn_ap->Connect(connect_remote_address, nullptr),
- lldb::eConnectionStatusSuccess);
+ if (conn_up->Connect(remote_addr, nullptr) != lldb::eConnectionStatusSuccess)
+ return llvm::make_error<llvm::StringError>("Unable to connect",
+ llvm::inconvertibleErrorCode());
+
+ client.SetConnection(conn_up.release());
+ if (llvm::Error error = accept_status.get().ToError())
+ return error;
- client.SetConnection(conn_ap.release());
- ASSERT_TRUE(accept_error.get().Success());
server.SetConnection(new ConnectionFileDescriptor(accept_socket));
+ return llvm::Error::success();
}
} // namespace process_gdb_remote
diff --git a/unittests/Process/gdb-remote/GDBRemoteTestUtils.h b/unittests/Process/gdb-remote/GDBRemoteTestUtils.h
index d7700f23e5ab..cc17422049bc 100644
--- a/unittests/Process/gdb-remote/GDBRemoteTestUtils.h
+++ b/unittests/Process/gdb-remote/GDBRemoteTestUtils.h
@@ -19,11 +19,12 @@ namespace process_gdb_remote {
class GDBRemoteTest : public testing::Test {
public:
static void SetUpTestCase();
-
static void TearDownTestCase();
-};
-void Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server);
+protected:
+ llvm::Error Connect(GDBRemoteCommunication &client,
+ GDBRemoteCommunication &server);
+};
struct MockServer : public GDBRemoteCommunicationServer {
MockServer()
diff --git a/unittests/tools/lldb-server/tests/TestClient.cpp b/unittests/tools/lldb-server/tests/TestClient.cpp
index 540d7979055c..9553ddd65fac 100644
--- a/unittests/tools/lldb-server/tests/TestClient.cpp
+++ b/unittests/tools/lldb-server/tests/TestClient.cpp
@@ -12,7 +12,6 @@
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/common/TCPSocket.h"
#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
-#include "lldb/Host/posix/ProcessLauncherPosix.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include "llvm/ADT/StringExtras.h"