aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/API/CMakeLists.txt119
-rw-r--r--source/API/Makefile18
-rw-r--r--source/API/SBProcess.cpp9
-rw-r--r--source/API/SystemInitializerFull.cpp6
-rw-r--r--source/Breakpoint/CMakeLists.txt23
-rw-r--r--source/Breakpoint/Makefile14
-rw-r--r--source/CMakeLists.txt92
-rw-r--r--source/Commands/CMakeLists.txt32
-rw-r--r--source/Commands/CommandObjectSource.cpp673
-rw-r--r--source/Commands/CommandObjectTarget.cpp3
-rw-r--r--source/Commands/CommandObjectType.cpp5
-rw-r--r--source/Commands/Makefile16
-rw-r--r--source/Core/CMakeLists.txt76
-rw-r--r--source/Core/Makefile14
-rw-r--r--source/Core/StringList.cpp37
-rw-r--r--source/DataFormatters/CMakeLists.txt19
-rw-r--r--source/DataFormatters/Makefile14
-rw-r--r--source/Expression/CMakeLists.txt16
-rw-r--r--source/Expression/Makefile14
-rw-r--r--source/Host/CMakeLists.txt190
-rw-r--r--source/Host/Makefile65
-rw-r--r--source/Host/android/HostInfoAndroid.cpp104
-rw-r--r--source/Host/android/LibcGlue.cpp40
-rw-r--r--source/Host/android/ProcessLauncherAndroid.cpp108
-rw-r--r--source/Host/linux/AbstractSocket.cpp31
-rw-r--r--source/Host/linux/Host.cpp393
-rw-r--r--source/Host/linux/HostInfoLinux.cpp282
-rw-r--r--source/Host/linux/HostThreadLinux.cpp52
-rw-r--r--source/Host/linux/LibcGlue.cpp30
-rw-r--r--source/Host/linux/ThisThread.cpp29
-rw-r--r--source/Host/macosx/Host.mm1587
-rw-r--r--source/Host/macosx/HostInfoMacOSX.mm372
-rw-r--r--source/Host/macosx/HostThreadMacOSX.mm102
-rw-r--r--source/Host/macosx/Symbols.cpp559
-rw-r--r--source/Host/macosx/ThisThread.cpp39
-rw-r--r--source/Host/macosx/cfcpp/CFCBundle.cpp99
-rw-r--r--source/Host/macosx/cfcpp/CFCBundle.h50
-rw-r--r--source/Host/macosx/cfcpp/CFCData.cpp82
-rw-r--r--source/Host/macosx/cfcpp/CFCData.h35
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableArray.cpp166
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableArray.h39
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableDictionary.cpp529
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableDictionary.h79
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableSet.cpp114
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableSet.h53
-rw-r--r--source/Host/macosx/cfcpp/CFCReleaser.h158
-rw-r--r--source/Host/macosx/cfcpp/CFCString.cpp195
-rw-r--r--source/Host/macosx/cfcpp/CFCString.h41
-rw-r--r--source/Host/macosx/cfcpp/CoreFoundationCPP.h30
-rw-r--r--source/Host/netbsd/Makefile14
-rw-r--r--source/Host/windows/Condition.cpp98
-rw-r--r--source/Host/windows/ConnectionGenericFileWindows.cpp354
-rw-r--r--source/Host/windows/EditLineWin.cpp435
-rw-r--r--source/Host/windows/FileSystem.cpp221
-rw-r--r--source/Host/windows/Host.cpp326
-rw-r--r--source/Host/windows/HostInfoWindows.cpp118
-rw-r--r--source/Host/windows/HostProcessWindows.cpp137
-rw-r--r--source/Host/windows/HostThreadWindows.cpp98
-rw-r--r--source/Host/windows/LockFileWindows.cpp93
-rw-r--r--source/Host/windows/Mutex.cpp109
-rw-r--r--source/Host/windows/PipeWindows.cpp336
-rw-r--r--source/Host/windows/ProcessLauncherWindows.cpp105
-rw-r--r--source/Host/windows/ProcessRunLock.cpp106
-rw-r--r--source/Host/windows/ThisThread.cpp66
-rw-r--r--source/Host/windows/Windows.cpp231
-rw-r--r--source/Initialization/CMakeLists.txt5
-rw-r--r--source/Initialization/Makefile14
-rw-r--r--source/Interpreter/CMakeLists.txt45
-rw-r--r--source/Interpreter/CommandHistory.cpp4
-rw-r--r--source/Interpreter/Makefile51
-rw-r--r--source/Makefile37
-rw-r--r--source/Plugins/ABI/CMakeLists.txt12
-rw-r--r--source/Plugins/ABI/MacOSX-arm/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/MacOSX-arm/Makefile14
-rw-r--r--source/Plugins/ABI/MacOSX-arm64/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/MacOSX-arm64/Makefile14
-rw-r--r--source/Plugins/ABI/MacOSX-i386/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/MacOSX-i386/Makefile14
-rw-r--r--source/Plugins/ABI/SysV-arm/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/SysV-arm/Makefile14
-rw-r--r--source/Plugins/ABI/SysV-arm64/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/SysV-arm64/Makefile14
-rw-r--r--source/Plugins/ABI/SysV-hexagon/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/SysV-hexagon/Makefile14
-rw-r--r--source/Plugins/ABI/SysV-i386/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/SysV-i386/Makefile14
-rw-r--r--source/Plugins/ABI/SysV-mips/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/SysV-mips/Makefile14
-rw-r--r--source/Plugins/ABI/SysV-mips64/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/SysV-mips64/Makefile14
-rw-r--r--source/Plugins/ABI/SysV-ppc/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/SysV-ppc/Makefile14
-rw-r--r--source/Plugins/ABI/SysV-ppc64/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/SysV-ppc64/Makefile14
-rw-r--r--source/Plugins/ABI/SysV-x86_64/CMakeLists.txt3
-rw-r--r--source/Plugins/ABI/SysV-x86_64/Makefile14
-rw-r--r--source/Plugins/CMakeLists.txt20
-rw-r--r--source/Plugins/Disassembler/CMakeLists.txt1
-rw-r--r--source/Plugins/Disassembler/llvm/CMakeLists.txt3
-rw-r--r--source/Plugins/Disassembler/llvm/Makefile14
-rw-r--r--source/Plugins/DynamicLoader/CMakeLists.txt9
-rw-r--r--source/Plugins/DynamicLoader/Darwin-Kernel/CMakeLists.txt3
-rw-r--r--source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp1698
-rw-r--r--source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h371
-rw-r--r--source/Plugins/DynamicLoader/Darwin-Kernel/Makefile14
-rw-r--r--source/Plugins/DynamicLoader/Hexagon-DYLD/CMakeLists.txt4
-rw-r--r--source/Plugins/DynamicLoader/Hexagon-DYLD/Makefile14
-rw-r--r--source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt3
-rw-r--r--source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp2075
-rw-r--r--source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h385
-rw-r--r--source/Plugins/DynamicLoader/MacOSX-DYLD/Makefile14
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/CMakeLists.txt5
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/Makefile14
-rw-r--r--source/Plugins/DynamicLoader/Static/CMakeLists.txt3
-rw-r--r--source/Plugins/DynamicLoader/Static/Makefile14
-rw-r--r--source/Plugins/DynamicLoader/Windows-DYLD/CMakeLists.txt3
-rw-r--r--source/Plugins/DynamicLoader/Windows-DYLD/Makefile14
-rw-r--r--source/Plugins/ExpressionParser/CMakeLists.txt2
-rw-r--r--source/Plugins/ExpressionParser/Clang/CMakeLists.txt15
-rw-r--r--source/Plugins/ExpressionParser/Clang/Makefile14
-rw-r--r--source/Plugins/ExpressionParser/Go/CMakeLists.txt5
-rw-r--r--source/Plugins/ExpressionParser/Go/Makefile14
-rw-r--r--source/Plugins/Instruction/ARM/CMakeLists.txt4
-rw-r--r--source/Plugins/Instruction/ARM/Makefile14
-rw-r--r--source/Plugins/Instruction/ARM64/CMakeLists.txt3
-rw-r--r--source/Plugins/Instruction/ARM64/Makefile14
-rw-r--r--source/Plugins/Instruction/CMakeLists.txt4
-rw-r--r--source/Plugins/Instruction/MIPS/CMakeLists.txt3
-rw-r--r--source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp2314
-rw-r--r--source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h130
-rw-r--r--source/Plugins/Instruction/MIPS/Makefile14
-rw-r--r--source/Plugins/Instruction/MIPS64/CMakeLists.txt3
-rw-r--r--source/Plugins/Instruction/MIPS64/Makefile14
-rw-r--r--source/Plugins/InstrumentationRuntime/AddressSanitizer/CMakeLists.txt3
-rw-r--r--source/Plugins/InstrumentationRuntime/AddressSanitizer/Makefile14
-rw-r--r--source/Plugins/InstrumentationRuntime/CMakeLists.txt1
-rw-r--r--source/Plugins/JITLoader/CMakeLists.txt1
-rw-r--r--source/Plugins/JITLoader/GDB/CMakeLists.txt6
-rw-r--r--source/Plugins/JITLoader/GDB/Makefile14
-rw-r--r--source/Plugins/Language/CMakeLists.txt4
-rw-r--r--source/Plugins/Language/CPlusPlus/CMakeLists.txt11
-rw-r--r--source/Plugins/Language/CPlusPlus/Makefile14
-rw-r--r--source/Plugins/Language/Go/CMakeLists.txt4
-rw-r--r--source/Plugins/Language/Go/Makefile14
-rw-r--r--source/Plugins/Language/ObjC/CMakeLists.txt13
-rw-r--r--source/Plugins/Language/ObjC/Makefile14
-rw-r--r--source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt3
-rw-r--r--source/Plugins/Language/ObjCPlusPlus/Makefile14
-rw-r--r--source/Plugins/LanguageRuntime/CMakeLists.txt4
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt2
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt3
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/Makefile14
-rw-r--r--source/Plugins/LanguageRuntime/Go/CMakeLists.txt5
-rw-r--r--source/Plugins/LanguageRuntime/Go/Makefile14
-rw-r--r--source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt10
-rw-r--r--source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/Makefile14
-rw-r--r--source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt1
-rw-r--r--source/Plugins/LanguageRuntime/RenderScript/CMakeLists.txt1
-rw-r--r--source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt3
-rw-r--r--source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/Makefile14
-rw-r--r--source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp87
-rw-r--r--source/Plugins/Makefile67
-rw-r--r--source/Plugins/MemoryHistory/CMakeLists.txt1
-rw-r--r--source/Plugins/MemoryHistory/asan/CMakeLists.txt3
-rw-r--r--source/Plugins/MemoryHistory/asan/Makefile14
-rw-r--r--source/Plugins/ObjectContainer/BSD-Archive/CMakeLists.txt3
-rw-r--r--source/Plugins/ObjectContainer/BSD-Archive/Makefile14
-rw-r--r--source/Plugins/ObjectContainer/CMakeLists.txt2
-rw-r--r--source/Plugins/ObjectContainer/Universal-Mach-O/CMakeLists.txt3
-rw-r--r--source/Plugins/ObjectContainer/Universal-Mach-O/Makefile14
-rw-r--r--source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp310
-rw-r--r--source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h105
-rw-r--r--source/Plugins/ObjectFile/CMakeLists.txt4
-rw-r--r--source/Plugins/ObjectFile/ELF/CMakeLists.txt4
-rw-r--r--source/Plugins/ObjectFile/ELF/Makefile14
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp96
-rw-r--r--source/Plugins/ObjectFile/JIT/CMakeLists.txt3
-rw-r--r--source/Plugins/ObjectFile/JIT/Makefile14
-rw-r--r--source/Plugins/ObjectFile/Mach-O/CMakeLists.txt3
-rw-r--r--source/Plugins/ObjectFile/Mach-O/Makefile14
-rw-r--r--source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp6096
-rw-r--r--source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h252
-rw-r--r--source/Plugins/ObjectFile/PECOFF/CMakeLists.txt4
-rw-r--r--source/Plugins/ObjectFile/PECOFF/Makefile14
-rw-r--r--source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp1056
-rw-r--r--source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h303
-rw-r--r--source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp56
-rw-r--r--source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h24
-rw-r--r--source/Plugins/OperatingSystem/CMakeLists.txt2
-rw-r--r--source/Plugins/OperatingSystem/Go/CMakeLists.txt3
-rw-r--r--source/Plugins/OperatingSystem/Go/Makefile14
-rw-r--r--source/Plugins/OperatingSystem/Python/CMakeLists.txt3
-rw-r--r--source/Plugins/OperatingSystem/Python/Makefile14
-rw-r--r--source/Plugins/Platform/Android/AdbClient.cpp569
-rw-r--r--source/Plugins/Platform/Android/AdbClient.h132
-rw-r--r--source/Plugins/Platform/Android/CMakeLists.txt5
-rw-r--r--source/Plugins/Platform/Android/Makefile14
-rw-r--r--source/Plugins/Platform/Android/PlatformAndroid.cpp389
-rw-r--r--source/Plugins/Platform/Android/PlatformAndroid.h114
-rw-r--r--source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp275
-rw-r--r--source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h79
-rw-r--r--source/Plugins/Platform/CMakeLists.txt16
-rw-r--r--source/Plugins/Platform/FreeBSD/CMakeLists.txt3
-rw-r--r--source/Plugins/Platform/FreeBSD/Makefile14
-rw-r--r--source/Plugins/Platform/Kalimba/CMakeLists.txt3
-rw-r--r--source/Plugins/Platform/Kalimba/Makefile14
-rw-r--r--source/Plugins/Platform/Kalimba/PlatformKalimba.cpp324
-rw-r--r--source/Plugins/Platform/Kalimba/PlatformKalimba.h99
-rw-r--r--source/Plugins/Platform/Linux/CMakeLists.txt3
-rw-r--r--source/Plugins/Platform/Linux/Makefile14
-rw-r--r--source/Plugins/Platform/Linux/PlatformLinux.cpp868
-rw-r--r--source/Plugins/Platform/Linux/PlatformLinux.h122
-rw-r--r--source/Plugins/Platform/MacOSX/CMakeLists.txt27
-rw-r--r--source/Plugins/Platform/MacOSX/Makefile15
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp303
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h81
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp466
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h121
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp466
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h120
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformDarwin.cpp1705
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformDarwin.h156
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp979
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h228
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp386
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformMacOSX.h104
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp912
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h171
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp944
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h173
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp974
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h173
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp502
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h116
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.h315
-rw-r--r--source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm773
-rw-r--r--source/Plugins/Platform/Makefile36
-rw-r--r--source/Plugins/Platform/NetBSD/CMakeLists.txt3
-rw-r--r--source/Plugins/Platform/NetBSD/Makefile14
-rw-r--r--source/Plugins/Platform/POSIX/CMakeLists.txt3
-rw-r--r--source/Plugins/Platform/POSIX/Makefile14
-rw-r--r--source/Plugins/Platform/Windows/CMakeLists.txt3
-rw-r--r--source/Plugins/Platform/Windows/Makefile14
-rw-r--r--source/Plugins/Platform/Windows/PlatformWindows.cpp753
-rw-r--r--source/Plugins/Platform/Windows/PlatformWindows.h169
-rw-r--r--source/Plugins/Platform/gdb-server/CMakeLists.txt3
-rw-r--r--source/Plugins/Platform/gdb-server/Makefile14
-rw-r--r--source/Plugins/Process/CMakeLists.txt19
-rw-r--r--source/Plugins/Process/FreeBSD/CMakeLists.txt16
-rw-r--r--source/Plugins/Process/FreeBSD/Makefile17
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessFreeBSD.h4
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.cpp4
-rw-r--r--source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp4
-rw-r--r--source/Plugins/Process/Linux/CMakeLists.txt14
-rw-r--r--source/Plugins/Process/Linux/Makefile17
-rw-r--r--source/Plugins/Process/Linux/NativeProcessLinux.cpp3189
-rw-r--r--source/Plugins/Process/Linux/NativeProcessLinux.h329
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp230
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux.h107
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp1017
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h185
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp1042
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h196
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp1431
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h167
-rwxr-xr-xsource/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp1239
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h171
-rw-r--r--source/Plugins/Process/Linux/NativeThreadLinux.cpp440
-rw-r--r--source/Plugins/Process/Linux/NativeThreadLinux.h120
-rw-r--r--source/Plugins/Process/Linux/ProcFileReader.cpp108
-rw-r--r--source/Plugins/Process/Linux/ProcFileReader.h37
-rw-r--r--source/Plugins/Process/Linux/Procfs.h31
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt10
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp1445
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h347
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/Makefile14
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp1211
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h274
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp186
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h54
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp161
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h61
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp161
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h61
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp129
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h53
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp127
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h54
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp211
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h98
-rw-r--r--source/Plugins/Process/POSIX/CMakeLists.txt8
-rw-r--r--source/Plugins/Process/POSIX/Makefile32
-rw-r--r--source/Plugins/Process/Utility/CMakeLists.txt47
-rw-r--r--source/Plugins/Process/Utility/Makefile14
-rw-r--r--source/Plugins/Process/Windows/Common/CMakeLists.txt23
-rw-r--r--source/Plugins/Process/Windows/Common/ExceptionRecord.h99
-rw-r--r--source/Plugins/Process/Windows/Common/ProcessWindows.cpp100
-rw-r--r--source/Plugins/Process/Windows/Common/ProcessWindows.h52
-rw-r--r--source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp194
-rw-r--r--source/Plugins/Process/Windows/Common/ProcessWindowsLog.h96
-rw-r--r--source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp155
-rw-r--r--source/Plugins/Process/Windows/Common/RegisterContextWindows.h67
-rw-r--r--source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp98
-rw-r--r--source/Plugins/Process/Windows/Common/TargetThreadWindows.h50
-rw-r--r--source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp323
-rw-r--r--source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h48
-rw-r--r--source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp178
-rw-r--r--source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h48
-rw-r--r--source/Plugins/Process/Windows/Live/CMakeLists.txt24
-rw-r--r--source/Plugins/Process/Windows/Live/DebuggerThread.cpp546
-rw-r--r--source/Plugins/Process/Windows/Live/DebuggerThread.h100
-rw-r--r--source/Plugins/Process/Windows/Live/ForwardDecl.h41
-rw-r--r--source/Plugins/Process/Windows/Live/IDebugDelegate.h46
-rw-r--r--source/Plugins/Process/Windows/Live/LocalDebugDelegate.cpp91
-rw-r--r--source/Plugins/Process/Windows/Live/LocalDebugDelegate.h68
-rw-r--r--source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp989
-rw-r--r--source/Plugins/Process/Windows/Live/ProcessWindowsLive.h125
-rw-r--r--source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.cpp147
-rw-r--r--source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.h55
-rw-r--r--source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.cpp171
-rw-r--r--source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.h40
-rw-r--r--source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.cpp100
-rw-r--r--source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.h36
-rw-r--r--source/Plugins/Process/Windows/MiniDump/CMakeLists.txt21
-rw-r--r--source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp550
-rw-r--r--source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h140
-rw-r--r--source/Plugins/Process/Windows/MiniDump/ThreadWinMiniDump.cpp104
-rw-r--r--source/Plugins/Process/Windows/MiniDump/ThreadWinMiniDump.h49
-rw-r--r--source/Plugins/Process/Windows/MiniDump/x64/RegisterContextWindowsMiniDump_x64.cpp47
-rw-r--r--source/Plugins/Process/Windows/MiniDump/x64/RegisterContextWindowsMiniDump_x64.h36
-rw-r--r--source/Plugins/Process/Windows/MiniDump/x86/RegisterContextWindowsMiniDump_x86.cpp47
-rw-r--r--source/Plugins/Process/Windows/MiniDump/x86/RegisterContextWindowsMiniDump_x86.h36
-rw-r--r--source/Plugins/Process/elf-core/CMakeLists.txt11
-rw-r--r--source/Plugins/Process/elf-core/Makefile14
-rw-r--r--source/Plugins/Process/gdb-remote/CMakeLists.txt16
-rw-r--r--source/Plugins/Process/gdb-remote/Makefile14
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp288
-rw-r--r--source/Plugins/Process/mach-core/CMakeLists.txt6
-rw-r--r--source/Plugins/Process/mach-core/Makefile14
-rw-r--r--source/Plugins/Process/mach-core/ProcessMachCore.cpp520
-rw-r--r--source/Plugins/Process/mach-core/ProcessMachCore.h164
-rw-r--r--source/Plugins/Process/mach-core/ThreadMachCore.cpp132
-rw-r--r--source/Plugins/Process/mach-core/ThreadMachCore.h91
-rw-r--r--source/Plugins/ScriptInterpreter/CMakeLists.txt2
-rw-r--r--source/Plugins/ScriptInterpreter/None/CMakeLists.txt3
-rw-r--r--source/Plugins/ScriptInterpreter/None/Makefile14
-rw-r--r--source/Plugins/ScriptInterpreter/Python/CMakeLists.txt5
-rw-r--r--source/Plugins/ScriptInterpreter/Python/Makefile14
-rw-r--r--source/Plugins/SymbolFile/CMakeLists.txt2
-rw-r--r--source/Plugins/SymbolFile/DWARF/CMakeLists.txt33
-rw-r--r--source/Plugins/SymbolFile/DWARF/Makefile14
-rw-r--r--source/Plugins/SymbolFile/DWARF/NameToDIE.cpp2
-rw-r--r--source/Plugins/SymbolFile/Symtab/CMakeLists.txt3
-rw-r--r--source/Plugins/SymbolFile/Symtab/Makefile14
-rw-r--r--source/Plugins/SymbolVendor/CMakeLists.txt5
-rw-r--r--source/Plugins/SymbolVendor/ELF/CMakeLists.txt3
-rw-r--r--source/Plugins/SymbolVendor/ELF/Makefile14
-rw-r--r--source/Plugins/SymbolVendor/MacOSX/CMakeLists.txt5
-rw-r--r--source/Plugins/SymbolVendor/MacOSX/Makefile14
-rw-r--r--source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp251
-rw-r--r--source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h58
-rw-r--r--source/Plugins/SystemRuntime/CMakeLists.txt1
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp383
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h117
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp383
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h119
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp382
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h116
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp385
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h113
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt7
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/Makefile14
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp1010
-rw-r--r--source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h336
-rw-r--r--source/Plugins/UnwindAssembly/CMakeLists.txt2
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/CMakeLists.txt3
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/Makefile14
-rw-r--r--source/Plugins/UnwindAssembly/x86/CMakeLists.txt3
-rw-r--r--source/Plugins/UnwindAssembly/x86/Makefile14
-rw-r--r--source/Symbol/CMakeLists.txt36
-rw-r--r--source/Symbol/Makefile14
-rw-r--r--source/Target/CMakeLists.txt59
-rw-r--r--source/Target/Makefile14
-rw-r--r--source/Target/Process.cpp2
-rw-r--r--source/Utility/CMakeLists.txt20
-rw-r--r--source/Utility/Makefile15
386 files changed, 63539 insertions, 2225 deletions
diff --git a/source/API/CMakeLists.txt b/source/API/CMakeLists.txt
new file mode 100644
index 000000000000..06a26e17c929
--- /dev/null
+++ b/source/API/CMakeLists.txt
@@ -0,0 +1,119 @@
+if ( CMAKE_SYSTEM_NAME MATCHES "Windows" )
+ add_definitions( -DEXPORT_LIBLLDB )
+endif()
+
+# Include this so that add_lldb_library() has the list of dependencies
+# for liblldb to link against
+include(${LLDB_PROJECT_ROOT}/cmake/LLDBDependencies.cmake)
+
+add_lldb_library(liblldb SHARED
+ SBAddress.cpp
+ SBAttachInfo.cpp
+ SBBlock.cpp
+ SBBreakpoint.cpp
+ SBBreakpointLocation.cpp
+ SBBroadcaster.cpp
+ SBCommandInterpreter.cpp
+ SBCommandReturnObject.cpp
+ SBCommunication.cpp
+ SBCompileUnit.cpp
+ SBData.cpp
+ SBDebugger.cpp
+ SBDeclaration.cpp
+ SBError.cpp
+ SBEvent.cpp
+ SBExecutionContext.cpp
+ SBExpressionOptions.cpp
+ SBFileSpec.cpp
+ SBFileSpecList.cpp
+ SBFrame.cpp
+ SBFunction.cpp
+ SBHostOS.cpp
+ SBInstruction.cpp
+ SBInstructionList.cpp
+ SBLanguageRuntime.cpp
+ SBLaunchInfo.cpp
+ SBLineEntry.cpp
+ SBListener.cpp
+ SBModule.cpp
+ SBModuleSpec.cpp
+ SBPlatform.cpp
+ SBProcess.cpp
+ SBQueue.cpp
+ SBQueueItem.cpp
+ SBSection.cpp
+ SBSourceManager.cpp
+ SBStream.cpp
+ SBStringList.cpp
+ SBSymbol.cpp
+ SBSymbolContext.cpp
+ SBSymbolContextList.cpp
+ SBTarget.cpp
+ SBThread.cpp
+ SBThreadCollection.cpp
+ SBThreadPlan.cpp
+ SBType.cpp
+ SBTypeCategory.cpp
+ SBTypeEnumMember.cpp
+ SBTypeFilter.cpp
+ SBTypeFormat.cpp
+ SBTypeNameSpecifier.cpp
+ SBTypeSummary.cpp
+ SBTypeSynthetic.cpp
+ SBValue.cpp
+ SBValueList.cpp
+ SBVariablesOptions.cpp
+ SBWatchpoint.cpp
+ SBUnixSignals.cpp
+ SystemInitializerFull.cpp
+ ${LLDB_WRAP_PYTHON}
+ )
+
+# This should not be part of LLDBDependencies.cmake, because we don't
+# want every single library taking a dependency on the script interpreters.
+target_link_libraries(liblldb PRIVATE
+ lldbPluginScriptInterpreterNone
+ lldbPluginScriptInterpreterPython
+ )
+
+set_target_properties(liblldb
+ PROPERTIES
+ VERSION ${LLDB_VERSION}
+ )
+
+if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
+ if (NOT LLDB_EXPORT_ALL_SYMBOLS)
+ # If we're not exporting all symbols, we'll want to explicitly set
+ # the exported symbols here. This prevents 'log enable --stack ...'
+ # from working on some systems but limits the liblldb size.
+ MESSAGE("-- Symbols (liblldb): only exporting liblldb.exports symbols")
+ add_llvm_symbol_exports(liblldb ${CMAKE_CURRENT_SOURCE_DIR}/liblldb.exports)
+ else()
+ # Don't use an explicit export. Instead, tell the linker to
+ # export all symbols.
+ MESSAGE("-- Symbols (liblldb): exporting all symbols")
+ # Darwin linker doesn't need this extra step.
+ if (NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ lldb_append_link_flags(liblldb "-Wl,--export-dynamic")
+ endif()
+ endif()
+endif()
+
+if ( CMAKE_SYSTEM_NAME MATCHES "Windows" )
+ # Only MSVC has the ABI compatibility problem and avoids using FindPythonLibs,
+ # so only it needs to explicitly link against ${PYTHON_LIBRARY}
+ if (MSVC AND NOT LLDB_DISABLE_PYTHON)
+ target_link_libraries(liblldb PRIVATE ${PYTHON_LIBRARY})
+ endif()
+else()
+ set_target_properties(liblldb
+ PROPERTIES
+ OUTPUT_NAME lldb
+ )
+endif()
+
+if (LLDB_WRAP_PYTHON)
+ add_dependencies(liblldb swig_wrapper)
+endif()
+target_link_libraries(liblldb ${cmake_2_8_12_PRIVATE} ${LLDB_SYSTEM_LIBS})
+
diff --git a/source/API/Makefile b/source/API/Makefile
new file mode 100644
index 000000000000..e35b2c37735e
--- /dev/null
+++ b/source/API/Makefile
@@ -0,0 +1,18 @@
+##===- source/API/Makefile ---------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbAPI
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
+
+ifeq ($(HOST_OS),MingW)
+CXXFLAGS += -DEXPORT_LIBLLDB
+endif
diff --git a/source/API/SBProcess.cpp b/source/API/SBProcess.cpp
index dceadeca69e5..42554726c018 100644
--- a/source/API/SBProcess.cpp
+++ b/source/API/SBProcess.cpp
@@ -995,7 +995,14 @@ SBProcess::GetStateFromEvent (const SBEvent &event)
bool
SBProcess::GetRestartedFromEvent (const SBEvent &event)
{
- return Process::ProcessEventData::GetRestartedFromEvent (event.get());
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ bool ret_val = Process::ProcessEventData::GetRestartedFromEvent (event.get());
+
+ if (log)
+ log->Printf ("SBProcess::%s (event.sp=%p) => %d", __FUNCTION__, event.get(), ret_val);
+
+ return ret_val;
}
size_t
diff --git a/source/API/SystemInitializerFull.cpp b/source/API/SystemInitializerFull.cpp
index f223357824e8..cbc01a6cff9a 100644
--- a/source/API/SystemInitializerFull.cpp
+++ b/source/API/SystemInitializerFull.cpp
@@ -102,7 +102,7 @@ PyInit__lldb(void);
#define LLDBSwigPyInit PyInit__lldb
#else
-extern "C" void
+extern "C" void
init_lldb(void);
#define LLDBSwigPyInit init_lldb
@@ -308,7 +308,7 @@ SystemInitializerFull::Initialize()
SystemRuntimeMacOSX::Initialize();
RenderScriptRuntime::Initialize();
GoLanguageRuntime::Initialize();
-
+
CPlusPlusLanguage::Initialize();
GoLanguage::Initialize();
ObjCLanguage::Initialize();
@@ -430,7 +430,7 @@ SystemInitializerFull::Terminate()
GoLanguage::Terminate();
ObjCLanguage::Terminate();
ObjCPlusPlusLanguage::Terminate();
-
+
#if defined(__APPLE__)
ProcessMachCore::Terminate();
ProcessKDP::Terminate();
diff --git a/source/Breakpoint/CMakeLists.txt b/source/Breakpoint/CMakeLists.txt
new file mode 100644
index 000000000000..85494b15aa08
--- /dev/null
+++ b/source/Breakpoint/CMakeLists.txt
@@ -0,0 +1,23 @@
+add_lldb_library(lldbBreakpoint
+ Breakpoint.cpp
+ BreakpointID.cpp
+ BreakpointIDList.cpp
+ BreakpointList.cpp
+ BreakpointLocation.cpp
+ BreakpointLocationCollection.cpp
+ BreakpointLocationList.cpp
+ BreakpointOptions.cpp
+ BreakpointResolver.cpp
+ BreakpointResolverAddress.cpp
+ BreakpointResolverFileLine.cpp
+ BreakpointResolverFileRegex.cpp
+ BreakpointResolverName.cpp
+ BreakpointSite.cpp
+ BreakpointSiteList.cpp
+ Stoppoint.cpp
+ StoppointCallbackContext.cpp
+ StoppointLocation.cpp
+ Watchpoint.cpp
+ WatchpointList.cpp
+ WatchpointOptions.cpp
+ )
diff --git a/source/Breakpoint/Makefile b/source/Breakpoint/Makefile
new file mode 100644
index 000000000000..223e4c24465f
--- /dev/null
+++ b/source/Breakpoint/Makefile
@@ -0,0 +1,14 @@
+##===- source/Breakpoint/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbBreakpoint
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
new file mode 100644
index 000000000000..f23af477bf89
--- /dev/null
+++ b/source/CMakeLists.txt
@@ -0,0 +1,92 @@
+include_directories(.)
+
+if ( CMAKE_SYSTEM_NAME MATCHES "Linux" )
+include_directories(
+ Plugins/Process/Linux
+ Plugins/Process/POSIX
+ )
+endif ()
+
+if ( CMAKE_SYSTEM_NAME MATCHES "FreeBSD" )
+include_directories(
+ Plugins/Process/FreeBSD
+ Plugins/Process/POSIX
+ )
+endif ()
+
+if ( CMAKE_SYSTEM_NAME MATCHES "NetBSD" )
+include_directories(
+ Plugins/Process/POSIX
+ )
+endif ()
+
+
+set(lldbBase_SOURCES
+ lldb.cpp
+ )
+
+if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ set(LLDB_VERS_GENERATED_FILE ${LLDB_BINARY_DIR}/source/LLDB_vers.c)
+ add_custom_command(OUTPUT ${LLDB_VERS_GENERATED_FILE}
+ COMMAND ${LLDB_SOURCE_DIR}/scripts/generate-vers.pl
+ ${LLDB_SOURCE_DIR}/lldb.xcodeproj/project.pbxproj liblldb_core
+ > ${LLDB_VERS_GENERATED_FILE}
+ DEPENDS ${LLDB_SOURCE_DIR}/scripts/generate-vers.pl
+ ${LLDB_SOURCE_DIR}/lldb.xcodeproj/project.pbxproj)
+ set_source_files_properties(${LLDB_VERS_GENERATED_FILE} PROPERTIES GENERATED 1)
+ # Add this to lldbBase since lldb.cpp uses the symbol defined here.
+ list(APPEND lldbBase_SOURCES ${LLDB_VERS_GENERATED_FILE})
+ add_custom_target(lldbGeneratedVersion
+ DEPENDS ${LLDB_VERS_GENERATED_FILE})
+endif()
+
+add_lldb_library(lldbBase
+ ${lldbBase_SOURCES}
+ )
+
+if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ add_dependencies(lldbBase lldbGeneratedVersion)
+endif()
+
+add_subdirectory(Breakpoint)
+add_subdirectory(Commands)
+add_subdirectory(Core)
+add_subdirectory(DataFormatters)
+add_subdirectory(Expression)
+add_subdirectory(Host)
+add_subdirectory(Initialization)
+add_subdirectory(Interpreter)
+add_subdirectory(Plugins)
+add_subdirectory(Symbol)
+add_subdirectory(Target)
+add_subdirectory(Utility)
+
+# Build API last. Since liblldb needs to link against every other target, it needs
+# those targets to have already been created.
+add_subdirectory(API)
+
+# Determine LLDB revision and repository. GetSourceVersion and GetRepositoryPath are shell-scripts, and as
+# such will not work on Windows.
+if ( NOT CMAKE_SYSTEM_NAME MATCHES "Windows" )
+ execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetSourceVersion ${LLDB_SOURCE_DIR}
+ OUTPUT_VARIABLE LLDB_REVISION)
+ if ( LLDB_REVISION )
+ string(REGEX REPLACE "(\r?\n)+$" "" LLDB_REVISION ${LLDB_REVISION})
+ endif()
+
+ execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetRepositoryPath ${LLDB_SOURCE_DIR}
+ OUTPUT_VARIABLE LLDB_REPOSITORY)
+ if ( LLDB_REPOSITORY )
+ # Replace newline characters with spaces
+ string(REGEX REPLACE "(\r?\n)+" " " LLDB_REPOSITORY ${LLDB_REPOSITORY})
+
+ # Remove trailing spaces
+ string(REGEX REPLACE "(\ )+$" "" LLDB_REPOSITORY ${LLDB_REPOSITORY})
+ endif()
+
+ set_property(
+ SOURCE lldb.cpp
+ PROPERTY COMPILE_DEFINITIONS "LLDB_REVISION=\"${LLDB_REVISION}\"" "LLDB_REPOSITORY=\"${LLDB_REPOSITORY}\"")
+endif ()
+# FIXME: implement svn/git revision and repository parsing solution on Windows. There is an SVN-only
+# revision parsing solution in tools/clang/lib/Basic/CMakelists.txt.
diff --git a/source/Commands/CMakeLists.txt b/source/Commands/CMakeLists.txt
new file mode 100644
index 000000000000..8805bbf6dc94
--- /dev/null
+++ b/source/Commands/CMakeLists.txt
@@ -0,0 +1,32 @@
+add_lldb_library(lldbCommands
+ CommandCompletions.cpp
+ CommandObjectApropos.cpp
+ CommandObjectArgs.cpp
+ CommandObjectBreakpoint.cpp
+ CommandObjectBreakpointCommand.cpp
+ CommandObjectBugreport.cpp
+ CommandObjectCommands.cpp
+ CommandObjectDisassemble.cpp
+ CommandObjectExpression.cpp
+ CommandObjectFrame.cpp
+ CommandObjectGUI.cpp
+ CommandObjectHelp.cpp
+ CommandObjectLog.cpp
+ CommandObjectMemory.cpp
+ CommandObjectMultiword.cpp
+ CommandObjectPlatform.cpp
+ CommandObjectPlugin.cpp
+ CommandObjectProcess.cpp
+ CommandObjectQuit.cpp
+ CommandObjectRegister.cpp
+ CommandObjectSettings.cpp
+ CommandObjectSource.cpp
+ CommandObjectSyntax.cpp
+ CommandObjectTarget.cpp
+ CommandObjectThread.cpp
+ CommandObjectType.cpp
+ CommandObjectVersion.cpp
+ CommandObjectWatchpoint.cpp
+ CommandObjectWatchpointCommand.cpp
+ CommandObjectLanguage.cpp
+ )
diff --git a/source/Commands/CommandObjectSource.cpp b/source/Commands/CommandObjectSource.cpp
index 08c8d46d1ee0..a9e52d1a76f3 100644
--- a/source/Commands/CommandObjectSource.cpp
+++ b/source/Commands/CommandObjectSource.cpp
@@ -27,6 +27,7 @@
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/StackFrame.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/Options.h"
@@ -34,9 +35,11 @@
using namespace lldb;
using namespace lldb_private;
-//-------------------------------------------------------------------------
-// CommandObjectSourceInfo
-//-------------------------------------------------------------------------
+
+#pragma mark CommandObjectSourceInfo
+//----------------------------------------------------------------------
+// CommandObjectSourceInfo - debug line entries dumping command
+//----------------------------------------------------------------------
class CommandObjectSourceInfo : public CommandObjectParsed
{
@@ -44,14 +47,9 @@ class CommandObjectSourceInfo : public CommandObjectParsed
class CommandOptions : public Options
{
public:
- CommandOptions (CommandInterpreter &interpreter) :
- Options(interpreter)
- {
- }
+ CommandOptions (CommandInterpreter &interpreter) : Options(interpreter) {}
- ~CommandOptions () override
- {
- }
+ ~CommandOptions () override {}
Error
SetOptionValue (uint32_t option_idx, const char *option_arg) override
@@ -60,19 +58,44 @@ class CommandObjectSourceInfo : public CommandObjectParsed
const int short_option = g_option_table[option_idx].short_option;
switch (short_option)
{
- case 'l':
- start_line = StringConvert::ToUInt32 (option_arg, 0);
- if (start_line == 0)
- error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg);
- break;
-
- case 'f':
- file_name = option_arg;
- break;
-
- default:
- error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ case 'l':
+ start_line = StringConvert::ToUInt32(option_arg, 0);
+ if (start_line == 0)
+ error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg);
+ break;
+
+ case 'e':
+ end_line = StringConvert::ToUInt32(option_arg, 0);
+ if (end_line == 0)
+ error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg);
+ break;
+
+ case 'c':
+ num_lines = StringConvert::ToUInt32(option_arg, 0);
+ if (num_lines == 0)
+ error.SetErrorStringWithFormat("invalid line count: '%s'", option_arg);
+ break;
+
+ case 'f':
+ file_name = option_arg;
+ break;
+
+ case 'n':
+ symbol_name = option_arg;
+ break;
+
+ case 'a':
+ {
+ ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
+ address = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ }
break;
+ case 's':
+ modules.push_back(std::string(option_arg));
+ break;
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
}
return error;
@@ -83,10 +106,15 @@ class CommandObjectSourceInfo : public CommandObjectParsed
{
file_spec.Clear();
file_name.clear();
+ symbol_name.clear();
+ address = LLDB_INVALID_ADDRESS;
start_line = 0;
+ end_line = 0;
+ num_lines = 0;
+ modules.clear();
}
- const OptionDefinition*
+ const OptionDefinition *
GetDefinitions () override
{
return g_option_table;
@@ -96,24 +124,24 @@ class CommandObjectSourceInfo : public CommandObjectParsed
// Instance variables to hold the values for command options.
FileSpec file_spec;
std::string file_name;
+ std::string symbol_name;
+ lldb::addr_t address;
uint32_t start_line;
-
+ uint32_t end_line;
+ uint32_t num_lines;
+ STLStringArray modules;
};
-
-public:
- CommandObjectSourceInfo(CommandInterpreter &interpreter) :
- CommandObjectParsed (interpreter,
- "source info",
- "Display information about the source lines from the current executable's debug info.",
- "source info [<cmd-options>]"),
- m_options (interpreter)
- {
- }
- ~CommandObjectSourceInfo () override
+public:
+ CommandObjectSourceInfo (CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "source info", "Display source line information (as specified) based "
+ "on the current executable's debug info.",
+ NULL, eCommandRequiresTarget),
+ m_options(interpreter)
{
}
+ ~CommandObjectSourceInfo () override {}
Options *
GetOptions () override
@@ -122,25 +150,576 @@ public:
}
protected:
+
+ // Dump the line entries in each symbol context.
+ // Return the number of entries found.
+ // If module_list is set, only dump lines contained in one of the modules.
+ // If file_spec is set, only dump lines in the file.
+ // If the start_line option was specified, don't print lines less than start_line.
+ // If the end_line option was specified, don't print lines greater than end_line.
+ // If the num_lines option was specified, dont print more than num_lines entries.
+ uint32_t
+ DumpLinesInSymbolContexts (Stream &strm, const SymbolContextList &sc_list,
+ const ModuleList &module_list, const FileSpec &file_spec)
+ {
+ uint32_t start_line = m_options.start_line;
+ uint32_t end_line = m_options.end_line;
+ uint32_t num_lines = m_options.num_lines;
+ Target *target = m_exe_ctx.GetTargetPtr();
+
+ uint32_t num_matches = 0;
+ bool has_path = false;
+ if (file_spec)
+ {
+ assert(file_spec.GetFilename().AsCString());
+ has_path = (file_spec.GetDirectory().AsCString() != 0);
+ }
+
+ // Dump all the line entries for the file in the list.
+ ConstString last_module_file_name;
+ uint32_t num_scs = sc_list.GetSize();
+ for (uint32_t i = 0; i < num_scs; ++i)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(i, sc);
+ if (sc.comp_unit)
+ {
+ Module *module = sc.module_sp.get();
+ CompileUnit *cu = sc.comp_unit;
+ const LineEntry &line_entry = sc.line_entry;
+ assert(module && cu);
+
+ // Are we looking for specific modules, files or lines?
+ if (module_list.GetSize() && module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32)
+ continue;
+ if (file_spec && !lldb_private::FileSpec::Equal(file_spec, line_entry.file, has_path))
+ continue;
+ if (start_line > 0 && line_entry.line < start_line)
+ continue;
+ if (end_line > 0 && line_entry.line > end_line)
+ continue;
+ if (num_lines > 0 && num_matches > num_lines)
+ continue;
+
+ // Print a new header if the module changed.
+ const ConstString &module_file_name = module->GetFileSpec().GetFilename();
+ assert(module_file_name);
+ if (module_file_name != last_module_file_name)
+ {
+ if (num_matches > 0)
+ strm << "\n\n";
+ strm << "Lines found in module `" << module_file_name << "\n";
+ }
+ // Dump the line entry.
+ line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
+ target, /*show_address_only=*/false);
+ strm << "\n";
+ last_module_file_name = module_file_name;
+ num_matches++;
+ }
+ }
+ return num_matches;
+ }
+
+ // Dump the requested line entries for the file in the compilation unit.
+ // Return the number of entries found.
+ // If module_list is set, only dump lines contained in one of the modules.
+ // If the start_line option was specified, don't print lines less than start_line.
+ // If the end_line option was specified, don't print lines greater than end_line.
+ // If the num_lines option was specified, dont print more than num_lines entries.
+ uint32_t
+ DumpFileLinesInCompUnit (Stream &strm, Module *module, CompileUnit *cu, const FileSpec &file_spec)
+ {
+ uint32_t start_line = m_options.start_line;
+ uint32_t end_line = m_options.end_line;
+ uint32_t num_lines = m_options.num_lines;
+ Target *target = m_exe_ctx.GetTargetPtr();
+
+ uint32_t num_matches = 0;
+ assert(module);
+ if (cu)
+ {
+ assert(file_spec.GetFilename().AsCString());
+ bool has_path = (file_spec.GetDirectory().AsCString() != 0);
+ const FileSpecList &cu_file_list = cu->GetSupportFiles();
+ size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path);
+ if (file_idx != UINT32_MAX)
+ {
+ // Update the file to how it appears in the CU.
+ const FileSpec &cu_file_spec = cu_file_list.GetFileSpecAtIndex(file_idx);
+
+ // Dump all matching lines at or above start_line for the file in the CU.
+ const ConstString &file_spec_name = file_spec.GetFilename();
+ const ConstString &module_file_name = module->GetFileSpec().GetFilename();
+ bool cu_header_printed = false;
+ uint32_t line = start_line;
+ while (true)
+ {
+ LineEntry line_entry;
+
+ // Find the lowest index of a line entry with a line equal to
+ // or higher than 'line'.
+ uint32_t start_idx = 0;
+ start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
+ /*exact=*/false, &line_entry);
+ if (start_idx == UINT32_MAX)
+ // No more line entries for our file in this CU.
+ break;
+
+ if (end_line > 0 && line_entry.line > end_line)
+ break;
+
+ // Loop through to find any other entries for this line, dumping each.
+ line = line_entry.line;
+ do
+ {
+ num_matches++;
+ if (num_lines > 0 && num_matches > num_lines)
+ break;
+ assert(lldb_private::FileSpec::Equal(cu_file_spec, line_entry.file, has_path));
+ if (!cu_header_printed)
+ {
+ if (num_matches > 0)
+ strm << "\n\n";
+ strm << "Lines found for file " << file_spec_name
+ << " in compilation unit " << cu->GetFilename()
+ << " in `" << module_file_name << "\n";
+ cu_header_printed = true;
+ }
+ line_entry.GetDescription(&strm, lldb::eDescriptionLevelBrief, cu,
+ target, /*show_address_only=*/false);
+ strm << "\n";
+
+ // Anymore after this one?
+ start_idx++;
+ start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
+ /*exact=*/true, &line_entry);
+ } while (start_idx != UINT32_MAX);
+
+ // Try the next higher line, starting over at start_idx 0.
+ line++;
+ }
+ }
+ }
+ return num_matches;
+ }
+
+ // Dump the requested line entries for the file in the module.
+ // Return the number of entries found.
+ // If module_list is set, only dump lines contained in one of the modules.
+ // If the start_line option was specified, don't print lines less than start_line.
+ // If the end_line option was specified, don't print lines greater than end_line.
+ // If the num_lines option was specified, dont print more than num_lines entries.
+ uint32_t
+ DumpFileLinesInModule (Stream &strm, Module *module, const FileSpec &file_spec)
+ {
+ uint32_t num_matches = 0;
+ if (module)
+ {
+ // Look through all the compilation units (CUs) in this module for ones that
+ // contain lines of code from this source file.
+ for (size_t i = 0; i < module->GetNumCompileUnits(); i++)
+ {
+ // Look for a matching source file in this CU.
+ CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i));
+ if (cu_sp)
+ {
+ num_matches += DumpFileLinesInCompUnit(strm, module, cu_sp.get(), file_spec);
+ }
+ }
+ }
+ return num_matches;
+ }
+
+ // Given an address and a list of modules, append the symbol contexts of all line entries
+ // containing the address found in the modules and return the count of matches. If none
+ // is found, return an error in 'error_strm'.
+ size_t
+ GetSymbolContextsForAddress (const ModuleList &module_list, lldb::addr_t addr,
+ SymbolContextList &sc_list, StreamString &error_strm)
+ {
+ Address so_addr;
+ size_t num_matches = 0;
+ assert(module_list.GetSize() > 0);
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (target->GetSectionLoadList().IsEmpty())
+ {
+ // The target isn't loaded yet, we need to lookup the file address in
+ // all modules. Note: the module list option does not apply to addresses.
+ const size_t num_modules = module_list.GetSize();
+ for (size_t i = 0; i < num_modules; ++i)
+ {
+ ModuleSP module_sp(module_list.GetModuleAtIndex(i));
+ if (!module_sp)
+ continue;
+ if (module_sp->ResolveFileAddress(addr, so_addr))
+ {
+ SymbolContext sc;
+ sc.Clear(true);
+ if (module_sp->ResolveSymbolContextForAddress(so_addr, eSymbolContextEverything, sc) &
+ eSymbolContextLineEntry)
+ {
+ sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
+ ++num_matches;
+ }
+ }
+ }
+ if (num_matches == 0)
+ error_strm.Printf("Source information for file address 0x%" PRIx64
+ " not found in any modules.\n", addr);
+ }
+ else
+ {
+ // The target has some things loaded, resolve this address to a
+ // compile unit + file + line and display
+ if (target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr))
+ {
+ ModuleSP module_sp(so_addr.GetModule());
+ // Check to make sure this module is in our list.
+ if (module_sp &&
+ module_list.GetIndexForModule(module_sp.get()) != LLDB_INVALID_INDEX32)
+ {
+ SymbolContext sc;
+ sc.Clear(true);
+ if (module_sp->ResolveSymbolContextForAddress(so_addr, eSymbolContextEverything, sc) &
+ eSymbolContextLineEntry)
+ {
+ sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/false);
+ ++num_matches;
+ }
+ else
+ {
+ StreamString addr_strm;
+ so_addr.Dump(&addr_strm, NULL, Address::DumpStyleModuleWithFileAddress);
+ error_strm.Printf("Address 0x%" PRIx64 " resolves to %s, but there is"
+ " no source information available for this address.\n",
+ addr, addr_strm.GetData());
+ }
+ }
+ else
+ {
+ StreamString addr_strm;
+ so_addr.Dump(&addr_strm, NULL, Address::DumpStyleModuleWithFileAddress);
+ error_strm.Printf("Address 0x%" PRIx64 " resolves to %s, but it cannot"
+ " be found in any modules.\n",
+ addr, addr_strm.GetData());
+ }
+ }
+ else
+ error_strm.Printf("Unable to resolve address 0x%" PRIx64 ".\n", addr);
+ }
+ return num_matches;
+ }
+
+ // Dump the line entries found in functions matching the name specified in the option.
bool
- DoExecute (Args& command, CommandReturnObject &result) override
+ DumpLinesInFunctions (CommandReturnObject &result)
{
- result.AppendError ("Not yet implemented");
- result.SetStatus (eReturnStatusFailed);
- return false;
+ SymbolContextList sc_list_funcs;
+ ConstString name(m_options.symbol_name.c_str());
+ SymbolContextList sc_list_lines;
+ Target *target = m_exe_ctx.GetTargetPtr();
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+
+ // Note: module_list can't be const& because FindFunctionSymbols isn't const.
+ ModuleList module_list = (m_module_list.GetSize() > 0) ?
+ m_module_list : target->GetImages();
+ size_t num_matches = module_list.FindFunctions(name,
+ eFunctionNameTypeAuto,
+ /*include_symbols=*/false,
+ /*include_inlines=*/true,
+ /*append=*/true,
+ sc_list_funcs);
+ if (!num_matches)
+ {
+ // If we didn't find any functions with that name, try searching for
+ // symbols that line up exactly with function addresses.
+ SymbolContextList sc_list_symbols;
+ size_t num_symbol_matches = module_list.FindFunctionSymbols(name,
+ eFunctionNameTypeAuto,
+ sc_list_symbols);
+ for (size_t i = 0; i < num_symbol_matches; i++)
+ {
+ SymbolContext sc;
+ sc_list_symbols.GetContextAtIndex(i, sc);
+ if (sc.symbol && sc.symbol->ValueIsAddress())
+ {
+ const Address &base_address = sc.symbol->GetAddressRef();
+ Function *function = base_address.CalculateSymbolContextFunction();
+ if (function)
+ {
+ sc_list_funcs.Append(SymbolContext(function));
+ num_matches++;
+ }
+ }
+ }
+ }
+ if (num_matches == 0)
+ {
+ result.AppendErrorWithFormat("Could not find function named \'%s\'.\n",
+ m_options.symbol_name.c_str());
+ return false;
+ }
+ for (size_t i = 0; i < num_matches; i++)
+ {
+ SymbolContext sc;
+ sc_list_funcs.GetContextAtIndex(i, sc);
+ bool context_found_for_symbol = false;
+ // Loop through all the ranges in the function.
+ AddressRange range;
+ for (uint32_t r = 0;
+ sc.GetAddressRange(eSymbolContextEverything,
+ r,
+ /*use_inline_block_range=*/true,
+ range);
+ ++r)
+ {
+ // Append the symbol contexts for each address in the range to sc_list_lines.
+ const Address &base_address = range.GetBaseAddress();
+ const addr_t size = range.GetByteSize();
+ lldb::addr_t start_addr = base_address.GetLoadAddress(target);
+ if (start_addr == LLDB_INVALID_ADDRESS)
+ start_addr = base_address.GetFileAddress();
+ lldb::addr_t end_addr = start_addr + size;
+ for (lldb::addr_t addr = start_addr; addr < end_addr; addr += addr_byte_size)
+ {
+ StreamString error_strm;
+ if (!GetSymbolContextsForAddress(module_list, addr, sc_list_lines, error_strm))
+ result.AppendWarningWithFormat("in symbol '%s': %s",
+ sc.GetFunctionName().AsCString(),
+ error_strm.GetData());
+ else
+ context_found_for_symbol = true;
+ }
+ }
+ if (!context_found_for_symbol)
+ result.AppendWarningWithFormat("Unable to find line information"
+ " for matching symbol '%s'.\n",
+ sc.GetFunctionName().AsCString());
+ }
+ if (sc_list_lines.GetSize() == 0)
+ {
+ result.AppendErrorWithFormat("No line information could be found"
+ " for any symbols matching '%s'.\n",
+ name.AsCString());
+ return false;
+ }
+ FileSpec file_spec;
+ if (!DumpLinesInSymbolContexts(result.GetOutputStream(),
+ sc_list_lines, module_list, file_spec))
+ {
+ result.AppendErrorWithFormat("Unable to dump line information for symbol '%s'.\n",
+ name.AsCString());
+ return false;
+ }
+ return true;
+ }
+
+ // Dump the line entries found for the address specified in the option.
+ bool
+ DumpLinesForAddress (CommandReturnObject &result)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ SymbolContextList sc_list;
+
+ StreamString error_strm;
+ if (!GetSymbolContextsForAddress(target->GetImages(), m_options.address, sc_list, error_strm))
+ {
+ result.AppendErrorWithFormat("%s.\n", error_strm.GetData());
+ return false;
+ }
+ ModuleList module_list;
+ FileSpec file_spec;
+ if (!DumpLinesInSymbolContexts(result.GetOutputStream(),
+ sc_list, module_list, file_spec))
+ {
+ result.AppendErrorWithFormat("No modules contain load address 0x%" PRIx64 ".\n",
+ m_options.address);
+ return false;
+ }
+ return true;
+ }
+
+ // Dump the line entries found in the file specified in the option.
+ bool
+ DumpLinesForFile (CommandReturnObject &result)
+ {
+ FileSpec file_spec(m_options.file_name, false);
+ const char *filename = m_options.file_name.c_str();
+ Target *target = m_exe_ctx.GetTargetPtr();
+ const ModuleList &module_list = (m_module_list.GetSize() > 0) ?
+ m_module_list : target->GetImages();
+
+ bool displayed_something = false;
+ const size_t num_modules = module_list.GetSize();
+ for (uint32_t i = 0; i < num_modules; ++i)
+ {
+ // Dump lines for this module.
+ Module *module = module_list.GetModulePointerAtIndex(i);
+ assert(module);
+ if (DumpFileLinesInModule(result.GetOutputStream(), module, file_spec))
+ displayed_something = true;
+ }
+ if (!displayed_something)
+ {
+ result.AppendErrorWithFormat("No source filenames matched '%s'.\n", filename);
+ return false;
+ }
+ return true;
+ }
+
+ // Dump the line entries for the current frame.
+ bool
+ DumpLinesForFrame (CommandReturnObject &result)
+ {
+ StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
+ if (cur_frame == NULL)
+ {
+ result.AppendError("No selected frame to use to find the default source.");
+ return false;
+ }
+ else if (!cur_frame->HasDebugInformation())
+ {
+ result.AppendError("No debug info for the selected frame.");
+ return false;
+ }
+ else
+ {
+ const SymbolContext &sc = cur_frame->GetSymbolContext(eSymbolContextLineEntry);
+ SymbolContextList sc_list;
+ sc_list.Append(sc);
+ ModuleList module_list;
+ FileSpec file_spec;
+ if (!DumpLinesInSymbolContexts(result.GetOutputStream(), sc_list, module_list, file_spec))
+ {
+ result.AppendError("No source line info available for the selected frame.");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool
+ DoExecute (Args &command, CommandReturnObject &result) override
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 0)
+ {
+ result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
+ GetCommandName());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (target == NULL)
+ {
+ target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError("invalid target, create a debug target using the "
+ "'target create' command.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+ // Collect the list of modules to search.
+ m_module_list.Clear();
+ if (m_options.modules.size() > 0)
+ {
+ for (size_t i = 0, e = m_options.modules.size(); i < e; ++i)
+ {
+ FileSpec module_file_spec(m_options.modules[i].c_str(), false);
+ if (module_file_spec)
+ {
+ ModuleSpec module_spec(module_file_spec);
+ if (target->GetImages().FindModules(module_spec, m_module_list) == 0)
+ result.AppendWarningWithFormat("No module found for '%s'.\n",
+ m_options.modules[i].c_str());
+ }
+ }
+ if (!m_module_list.GetSize())
+ {
+ result.AppendError("No modules match the input.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else if (target->GetImages().GetSize() == 0)
+ {
+ result.AppendError("The target has no associated executable images.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // Check the arguments to see what lines we should dump.
+ if (!m_options.symbol_name.empty())
+ {
+ // Print lines for symbol.
+ if (DumpLinesInFunctions(result))
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ else
+ result.SetStatus(eReturnStatusFailed);
+ }
+ else if (m_options.address != LLDB_INVALID_ADDRESS)
+ {
+ // Print lines for an address.
+ if (DumpLinesForAddress(result))
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ else
+ result.SetStatus(eReturnStatusFailed);
+ }
+ else if (!m_options.file_name.empty())
+ {
+ // Dump lines for a file.
+ if (DumpLinesForFile(result))
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ else
+ result.SetStatus(eReturnStatusFailed);
+ }
+ else
+ {
+ // Dump the line for the current frame.
+ if (DumpLinesForFrame(result))
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ else
+ result.SetStatus(eReturnStatusFailed);
+ }
+ return result.Succeeded();
}
CommandOptions m_options;
+ ModuleList m_module_list;
};
-OptionDefinition
-CommandObjectSourceInfo::CommandOptions::g_option_table[] =
-{
-{ LLDB_OPT_SET_1, false, "line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."},
-{ LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."},
-{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
+OptionDefinition CommandObjectSourceInfo::CommandOptions::g_option_table[] = {
+ {LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount,
+ "The number of line entries to display."},
+ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "shlib", 's', OptionParser::eRequiredArgument, NULL, NULL,
+ CommandCompletions::eModuleCompletion, eArgTypeShlibName,
+ "Look up the source in the given module or shared library (can be "
+ "specified more than once)."},
+ {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL,
+ CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."},
+ {LLDB_OPT_SET_1, false, "line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum,
+ "The line number at which to start the displaying lines."},
+ {LLDB_OPT_SET_1, false, "end-line", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum,
+ "The line number at which to stop displaying lines."},
+ {LLDB_OPT_SET_2, false, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL,
+ CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display."},
+ {LLDB_OPT_SET_3, false, "address", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeAddressOrExpression,
+ "Lookup the address and display the source information for the "
+ "corresponding file and line."},
+ {0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL}
};
+
#pragma mark CommandObjectSourceList
//-------------------------------------------------------------------------
// CommandObjectSourceList
@@ -906,7 +1485,6 @@ CommandObjectSourceList::CommandOptions::g_option_table[] =
};
#pragma mark CommandObjectMultiwordSource
-
//-------------------------------------------------------------------------
// CommandObjectMultiwordSource
//-------------------------------------------------------------------------
@@ -917,8 +1495,7 @@ CommandObjectMultiwordSource::CommandObjectMultiwordSource (CommandInterpreter &
"A set of commands for accessing source file information",
"source <subcommand> [<subcommand-options>]")
{
- // "source info" isn't implemented yet...
- //LoadSubCommand ("info", CommandObjectSP (new CommandObjectSourceInfo (interpreter)));
+ LoadSubCommand ("info", CommandObjectSP (new CommandObjectSourceInfo (interpreter)));
LoadSubCommand ("list", CommandObjectSP (new CommandObjectSourceList (interpreter)));
}
diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp
index 026ae3570854..57ec1c953fcf 100644
--- a/source/Commands/CommandObjectTarget.cpp
+++ b/source/Commands/CommandObjectTarget.cpp
@@ -2577,8 +2577,9 @@ protected:
if (command.GetArgumentCount() == 0)
{
- result.AppendErrorWithFormat ("\nSyntax: %s\n", m_cmd_syntax.c_str());
+ result.AppendError ("file option must be specified.");
result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
}
else
{
diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp
index b57ac70f8f1a..2b803e7eb0d3 100644
--- a/source/Commands/CommandObjectType.cpp
+++ b/source/Commands/CommandObjectType.cpp
@@ -1396,11 +1396,6 @@ protected:
auto category_closure = [&result, &formatter_regex] (const lldb::TypeCategoryImplSP& category) -> void {
result.GetOutputStream().Printf("-----------------------\nCategory: %s\n-----------------------\n", category->GetName());
-
- typedef const std::shared_ptr<FormatterType> Bar;
- typedef std::function<bool(ConstString,Bar)> Func1Type;
- typedef std::function<bool(RegularExpressionSP,Bar)> Func2Type;
-
TypeCategoryImpl::ForEachCallbacks<FormatterType> foreach;
foreach.SetExact([&result, &formatter_regex] (ConstString name, const FormatterSharedPointer& format_sp) -> bool {
if (formatter_regex)
diff --git a/source/Commands/Makefile b/source/Commands/Makefile
new file mode 100644
index 000000000000..1a66485a0c21
--- /dev/null
+++ b/source/Commands/Makefile
@@ -0,0 +1,16 @@
+##===- source/Commands/Makefile ----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbCommands
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
+
+EXTRA_OPTIONS += -Wno-four-char-constants \ No newline at end of file
diff --git a/source/Core/CMakeLists.txt b/source/Core/CMakeLists.txt
new file mode 100644
index 000000000000..b975fb88e784
--- /dev/null
+++ b/source/Core/CMakeLists.txt
@@ -0,0 +1,76 @@
+add_lldb_library(lldbCore
+ Address.cpp
+ AddressRange.cpp
+ AddressResolver.cpp
+ AddressResolverFileLine.cpp
+ AddressResolverName.cpp
+ ArchSpec.cpp
+ Baton.cpp
+ Broadcaster.cpp
+ Communication.cpp
+ Connection.cpp
+ ConnectionMachPort.cpp
+ ConnectionSharedMemory.cpp
+ ConstString.cpp
+ CxaDemangle.cpp
+ DataBufferHeap.cpp
+ DataBufferMemoryMap.cpp
+ DataEncoder.cpp
+ DataExtractor.cpp
+ Debugger.cpp
+ Disassembler.cpp
+ DynamicLoader.cpp
+ EmulateInstruction.cpp
+ Error.cpp
+ Event.cpp
+ FastDemangle.cpp
+ FileLineResolver.cpp
+ FileSpecList.cpp
+ FormatEntity.cpp
+ History.cpp
+ IOHandler.cpp
+ Listener.cpp
+ Log.cpp
+ Logging.cpp
+ Mangled.cpp
+ Module.cpp
+ ModuleChild.cpp
+ ModuleList.cpp
+ Opcode.cpp
+ PluginManager.cpp
+ RegisterValue.cpp
+ RegularExpression.cpp
+ Scalar.cpp
+ SearchFilter.cpp
+ Section.cpp
+ SourceManager.cpp
+ State.cpp
+ Stream.cpp
+ StreamAsynchronousIO.cpp
+ StreamCallback.cpp
+ StreamFile.cpp
+ StreamGDBRemote.cpp
+ StreamString.cpp
+ StringList.cpp
+ StructuredData.cpp
+ Timer.cpp
+ UserID.cpp
+ UserSettingsController.cpp
+ UUID.cpp
+ Value.cpp
+ ValueObject.cpp
+ ValueObjectCast.cpp
+ ValueObjectChild.cpp
+ ValueObjectConstResult.cpp
+ ValueObjectConstResultCast.cpp
+ ValueObjectConstResultChild.cpp
+ ValueObjectConstResultImpl.cpp
+ ValueObjectDynamicValue.cpp
+ ValueObjectList.cpp
+ ValueObjectMemory.cpp
+ ValueObjectRegister.cpp
+ ValueObjectSyntheticFilter.cpp
+ ValueObjectVariable.cpp
+ VMRange.cpp
+ )
+
diff --git a/source/Core/Makefile b/source/Core/Makefile
new file mode 100644
index 000000000000..b7773e3f571d
--- /dev/null
+++ b/source/Core/Makefile
@@ -0,0 +1,14 @@
+##===- source/Core/Makefile --------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbCore
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Core/StringList.cpp b/source/Core/StringList.cpp
index 4e07ba4a4579..ce197ac7bd48 100644
--- a/source/Core/StringList.cpp
+++ b/source/Core/StringList.cpp
@@ -11,6 +11,8 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
#include <string>
@@ -305,12 +307,29 @@ StringList::operator << (const char* str)
}
StringList&
+StringList::operator << (const std::string& str)
+{
+ AppendString(str);
+ return *this;
+}
+
+StringList&
StringList::operator << (StringList strings)
{
AppendList(strings);
return *this;
}
+StringList&
+StringList::operator = (const std::vector<std::string> &rhs)
+{
+ Clear();
+ for (const auto &s : rhs)
+ m_strings.push_back(s);
+
+ return *this;
+}
+
size_t
StringList::AutoComplete (const char *s, StringList &matches, size_t &exact_idx) const
{
@@ -339,3 +358,21 @@ StringList::AutoComplete (const char *s, StringList &matches, size_t &exact_idx)
return matches.GetSize();
}
+void
+StringList::LogDump(Log *log, const char *name)
+{
+ if (!log)
+ return;
+
+ StreamString strm;
+ if (name)
+ strm.Printf("Begin %s:\n", name);
+ for (const auto &s : m_strings) {
+ strm.Indent();
+ strm.Printf("%s\n", s.c_str());
+ }
+ if (name)
+ strm.Printf("End %s.\n", name);
+
+ log->Debug("%s", strm.GetData());
+}
diff --git a/source/DataFormatters/CMakeLists.txt b/source/DataFormatters/CMakeLists.txt
new file mode 100644
index 000000000000..bfb5c8b9f68b
--- /dev/null
+++ b/source/DataFormatters/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_lldb_library(lldbDataFormatters
+ CXXFunctionPointer.cpp
+ DataVisualization.cpp
+ DumpValueObjectOptions.cpp
+ FormatCache.cpp
+ FormatClasses.cpp
+ FormatManager.cpp
+ FormattersHelpers.cpp
+ LanguageCategory.cpp
+ StringPrinter.cpp
+ TypeCategory.cpp
+ TypeCategoryMap.cpp
+ TypeFormat.cpp
+ TypeSummary.cpp
+ TypeSynthetic.cpp
+ TypeValidator.cpp
+ ValueObjectPrinter.cpp
+ VectorType.cpp
+ )
diff --git a/source/DataFormatters/Makefile b/source/DataFormatters/Makefile
new file mode 100644
index 000000000000..4eb3249e5a58
--- /dev/null
+++ b/source/DataFormatters/Makefile
@@ -0,0 +1,14 @@
+##===- source/DataFormatters/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbDataFormatters
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Expression/CMakeLists.txt b/source/Expression/CMakeLists.txt
new file mode 100644
index 000000000000..52392f13319a
--- /dev/null
+++ b/source/Expression/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_lldb_library(lldbExpression
+ DWARFExpression.cpp
+ Expression.cpp
+ ExpressionSourceCode.cpp
+ ExpressionVariable.cpp
+ FunctionCaller.cpp
+ IRDynamicChecks.cpp
+ IRExecutionUnit.cpp
+ IRInterpreter.cpp
+ IRMemoryMap.cpp
+ LLVMUserExpression.cpp
+ Materializer.cpp
+ REPL.cpp
+ UserExpression.cpp
+ UtilityFunction.cpp
+ )
diff --git a/source/Expression/Makefile b/source/Expression/Makefile
new file mode 100644
index 000000000000..495f094d3900
--- /dev/null
+++ b/source/Expression/Makefile
@@ -0,0 +1,14 @@
+##===- source/Expression/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbExpression
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Host/CMakeLists.txt b/source/Host/CMakeLists.txt
new file mode 100644
index 000000000000..776fcfb44ffa
--- /dev/null
+++ b/source/Host/CMakeLists.txt
@@ -0,0 +1,190 @@
+macro(add_host_subdirectory group)
+ list(APPEND HOST_SOURCES ${ARGN})
+ source_group(${group} FILES ${ARGN})
+endmacro()
+
+add_host_subdirectory(common
+ common/Condition.cpp
+ common/File.cpp
+ common/FileCache.cpp
+ common/FileSpec.cpp
+ common/FileSystem.cpp
+ common/GetOptInc.cpp
+ common/Host.cpp
+ common/HostInfoBase.cpp
+ common/HostNativeThreadBase.cpp
+ common/HostProcess.cpp
+ common/HostThread.cpp
+ common/IOObject.cpp
+ common/LockFileBase.cpp
+ common/Mutex.cpp
+ common/MonitoringProcessLauncher.cpp
+ common/NativeBreakpoint.cpp
+ common/NativeBreakpointList.cpp
+ common/NativeWatchpointList.cpp
+ common/NativeProcessProtocol.cpp
+ common/NativeRegisterContext.cpp
+ common/NativeRegisterContextRegisterInfo.cpp
+ common/NativeThreadProtocol.cpp
+ common/OptionParser.cpp
+ common/PipeBase.cpp
+ common/ProcessRunLock.cpp
+ common/Socket.cpp
+ common/SocketAddress.cpp
+ common/SoftwareBreakpoint.cpp
+ common/StringConvert.cpp
+ common/Symbols.cpp
+ common/TCPSocket.cpp
+ common/Terminal.cpp
+ common/ThisThread.cpp
+ common/ThreadLauncher.cpp
+ common/TimeValue.cpp
+ common/XML.cpp
+ common/UDPSocket.cpp
+ )
+
+# Keep track of whether we want to provide a define for the
+# Python's architecture-specific lib path (i.e. where a
+# Python lldb module would go).
+set (get_python_libdir 0)
+
+if (NOT LLDB_DISABLE_LIBEDIT)
+ add_host_subdirectory(common
+ common/Editline.cpp
+ )
+endif()
+
+add_host_subdirectory(posix
+ posix/ConnectionFileDescriptorPosix.cpp
+ )
+
+if (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ add_host_subdirectory(windows
+ windows/Condition.cpp
+ windows/ConnectionGenericFileWindows.cpp
+ windows/EditLineWin.cpp
+ windows/FileSystem.cpp
+ windows/Host.cpp
+ windows/HostInfoWindows.cpp
+ windows/HostProcessWindows.cpp
+ windows/HostThreadWindows.cpp
+ windows/LockFileWindows.cpp
+ windows/Mutex.cpp
+ windows/PipeWindows.cpp
+ windows/ProcessLauncherWindows.cpp
+ windows/ProcessRunLock.cpp
+ windows/ThisThread.cpp
+ windows/Windows.cpp
+ )
+else()
+ if (NOT LLDB_DISABLE_PYTHON)
+ # We'll grab the arch-specific python libdir on POSIX systems.
+ set (get_python_libdir 1)
+ endif()
+
+ add_host_subdirectory(posix
+ posix/DomainSocket.cpp
+ posix/FileSystem.cpp
+ posix/HostInfoPosix.cpp
+ posix/HostProcessPosix.cpp
+ posix/HostThreadPosix.cpp
+ posix/LockFilePosix.cpp
+ posix/MainLoopPosix.cpp
+ posix/PipePosix.cpp
+ )
+
+ if (NOT __ANDROID_NDK__)
+ add_host_subdirectory(posix
+ posix/ProcessLauncherPosix.cpp
+ )
+ endif()
+
+ if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR})
+ add_host_subdirectory(macosx
+ macosx/Host.mm
+ macosx/HostInfoMacOSX.mm
+ macosx/HostThreadMacOSX.mm
+ macosx/Symbols.cpp
+ macosx/ThisThread.cpp
+ macosx/cfcpp/CFCBundle.cpp
+ macosx/cfcpp/CFCData.cpp
+ macosx/cfcpp/CFCMutableArray.cpp
+ macosx/cfcpp/CFCMutableDictionary.cpp
+ macosx/cfcpp/CFCMutableSet.cpp
+ macosx/cfcpp/CFCString.cpp
+ )
+
+ elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
+ if (__ANDROID_NDK__)
+ add_host_subdirectory(android
+ android/HostInfoAndroid.cpp
+ android/LibcGlue.cpp
+ android/ProcessLauncherAndroid.cpp
+ linux/AbstractSocket.cpp
+ linux/Host.cpp
+ linux/HostInfoLinux.cpp
+ linux/HostThreadLinux.cpp
+ linux/LibcGlue.cpp
+ linux/ThisThread.cpp
+ )
+ else()
+ add_host_subdirectory(linux
+ linux/AbstractSocket.cpp
+ linux/Host.cpp
+ linux/HostInfoLinux.cpp
+ linux/HostThreadLinux.cpp
+ linux/LibcGlue.cpp
+ linux/ThisThread.cpp
+ )
+ endif()
+
+ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ add_host_subdirectory(freebsd
+ freebsd/Host.cpp
+ freebsd/HostInfoFreeBSD.cpp
+ freebsd/HostThreadFreeBSD.cpp
+ freebsd/ThisThread.cpp
+ )
+
+ elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
+ add_host_subdirectory(netbsd
+ netbsd/Host.cpp
+ netbsd/HostInfoNetBSD.cpp
+ netbsd/HostThreadNetBSD.cpp
+ netbsd/ThisThread.cpp
+ )
+ endif()
+endif()
+
+if (${get_python_libdir})
+ # Call a python script to gather the arch-specific libdir for
+ # modules like the lldb module.
+ execute_process(
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/get_relative_lib_dir.py
+ RESULT_VARIABLE get_libdir_status
+ OUTPUT_VARIABLE relative_libdir
+ )
+ if (get_libdir_status EQUAL 0)
+ add_definitions(-DLLDB_PYTHON_RELATIVE_LIBDIR="${relative_libdir}")
+ endif()
+endif()
+
+if (${get_python_libdir})
+ # Call a python script to gather the arch-specific libdir for
+ # modules like the lldb module.
+ execute_process(
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/get_relative_lib_dir.py
+ RESULT_VARIABLE get_libdir_status
+ OUTPUT_VARIABLE relative_libdir
+ )
+ if (get_libdir_status EQUAL 0)
+ add_definitions(-DLLDB_PYTHON_RELATIVE_LIBDIR="${relative_libdir}")
+ endif()
+endif()
+
+add_lldb_library(lldbHost ${HOST_SOURCES})
+
+if (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
+target_link_libraries(lldbHost kvm)
+endif ()
diff --git a/source/Host/Makefile b/source/Host/Makefile
new file mode 100644
index 000000000000..da90c8c364a3
--- /dev/null
+++ b/source/Host/Makefile
@@ -0,0 +1,65 @@
+##===- source/Host/Makefile --------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LEVEL := $(LLDB_LEVEL)/../..
+
+include $(LEVEL)/Makefile.config
+
+define DIR_SOURCES
+SOURCES += $$(addprefix $(1)/,$$(notdir $$(wildcard $$(PROJ_SRC_DIR)/$(1)/*.cpp \
+ $$(PROJ_SRC_DIR)/*.cc $$(PROJ_SRC_DIR)/$(1)/*.c $$(PROJ_SRC_DIR)/$(1)/*.mm)))
+endef
+
+$(eval $(call DIR_SOURCES,common))
+
+ifeq ($(HOST_OS),Darwin)
+$(eval $(call DIR_SOURCES,posix))
+$(eval $(call DIR_SOURCES,macosx))
+CFCPP_SOURCES = \
+ $(addprefix macosx/cfcpp/,$(notdir $(wildcard $(PROJ_SRC_DIR)/macosx/cfcpp/*.cpp)))
+SOURCES += $(CFCPP_SOURCES)
+
+CFCPP_BaseNameSources := $(sort $(basename $(CFCPP_SOURCES)))
+CFCPP_OBJECTS := $(CFCPP_BaseNameSources:%=$(ObjDir)/%.o)
+
+# Make sure the cfcpp output directory exists
+$(CFCPP_OBJECTS): $(ObjDir)/cfcpp/.dir
+endif
+
+ifeq ($(HOST_OS),Linux)
+$(eval $(call DIR_SOURCES,posix))
+$(eval $(call DIR_SOURCES,linux))
+endif
+
+ifneq (,$(filter $(HOST_OS), FreeBSD GNU/kFreeBSD))
+$(eval $(call DIR_SOURCES,posix))
+$(eval $(call DIR_SOURCES,freebsd))
+endif
+
+ifeq ($(HOST_OS),NetBSD)
+$(eval $(call DIR_SOURCES,posix))
+$(eval $(call DIR_SOURCES,netbsd))
+endif
+
+ifeq ($(HOST_OS),MingW)
+$(eval $(call DIR_SOURCES,windows))
+SOURCES += posix/ConnectionFileDescriptorPosix.cpp
+endif
+
+ifeq ($(HOST_OS),Android)
+$(eval $(call DIR_SOURCES,posix))
+$(eval $(call DIR_SOURCES,linux))
+$(eval $(call DIR_SOURCES,android))
+endif
+
+LIBRARYNAME := lldbHost
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Host/android/HostInfoAndroid.cpp b/source/Host/android/HostInfoAndroid.cpp
new file mode 100644
index 000000000000..3fa50ec8ddfd
--- /dev/null
+++ b/source/Host/android/HostInfoAndroid.cpp
@@ -0,0 +1,104 @@
+//===-- HostInfoAndroid.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/android/HostInfoAndroid.h"
+#include "lldb/Host/linux/HostInfoLinux.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb_private;
+using namespace llvm;
+
+void
+HostInfoAndroid::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
+{
+ HostInfoLinux::ComputeHostArchitectureSupport(arch_32, arch_64);
+
+ if (arch_32.IsValid())
+ {
+ arch_32.GetTriple().setEnvironment(llvm::Triple::Android);
+ }
+ if (arch_64.IsValid())
+ {
+ arch_64.GetTriple().setEnvironment(llvm::Triple::Android);
+ }
+}
+
+FileSpec
+HostInfoAndroid::GetDefaultShell()
+{
+ return FileSpec("/system/bin/sh", false);
+}
+
+FileSpec
+HostInfoAndroid::ResolveLibraryPath(const std::string& module_path, const ArchSpec& arch)
+{
+ static const char* const ld_library_path_separator = ":";
+ static const char* const default_lib32_path[] = {
+ "/vendor/lib",
+ "/system/lib",
+ nullptr
+ };
+ static const char* const default_lib64_path[] = {
+ "/vendor/lib64",
+ "/system/lib64",
+ nullptr
+ };
+
+ if (module_path.empty() || module_path[0] == '/')
+ return FileSpec(module_path.c_str(), true);
+
+ SmallVector<StringRef, 4> ld_paths;
+
+ if (const char* ld_library_path = ::getenv("LD_LIBRARY_PATH"))
+ StringRef(ld_library_path).split(ld_paths, StringRef(ld_library_path_separator), -1, false);
+
+ const char* const* default_lib_path = nullptr;
+ switch (arch.GetAddressByteSize())
+ {
+ case 4:
+ default_lib_path = default_lib32_path;
+ break;
+ case 8:
+ default_lib_path = default_lib64_path;
+ break;
+ default:
+ assert(false && "Unknown address byte size");
+ return FileSpec();
+ }
+
+ for(const char* const* it = default_lib_path; *it; ++it)
+ ld_paths.push_back(StringRef(*it));
+
+ for (const StringRef& path : ld_paths)
+ {
+ FileSpec file_candidate(path.str().c_str(), true);
+ file_candidate.AppendPathComponent(module_path.c_str());
+
+ if (file_candidate.Exists())
+ return file_candidate;
+ }
+
+ return FileSpec();
+}
+
+bool
+HostInfoAndroid::ComputeTempFileBaseDirectory(FileSpec &file_spec)
+{
+ bool success = HostInfoLinux::ComputeTempFileBaseDirectory(file_spec);
+
+ // On Android, there is no path which is guaranteed to be writable. If the user has not
+ // provided a path via an environment variable, the generic algorithm will deduce /tmp, which
+ // is plain wrong. In that case we have an invalid directory, we substitute the path with
+ // /data/local/tmp, which is correct at least in some cases (i.e., when running as shell user).
+ if (!success || !file_spec.Exists())
+ file_spec = FileSpec("/data/local/tmp", false);
+
+ return file_spec.Exists();
+}
diff --git a/source/Host/android/LibcGlue.cpp b/source/Host/android/LibcGlue.cpp
new file mode 100644
index 000000000000..3842fb6c2a8e
--- /dev/null
+++ b/source/Host/android/LibcGlue.cpp
@@ -0,0 +1,40 @@
+//===-- LibcGlue.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This files adds functions missing from libc on earlier versions of Android
+
+#include <android/api-level.h>
+
+#include <sys/syscall.h>
+
+#if __ANDROID_API__ < 21
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "lldb/Host/Time.h"
+
+time_t timegm(struct tm* t)
+{
+ return (time_t) timegm64(t);
+}
+
+int signalfd (int fd, const sigset_t *mask, int flags)
+{
+ return syscall(__NR_signalfd4, fd, mask, _NSIG / 8, flags);
+}
+
+int posix_openpt(int flags)
+{
+ return open("/dev/ptmx", flags);
+}
+
+#endif
diff --git a/source/Host/android/ProcessLauncherAndroid.cpp b/source/Host/android/ProcessLauncherAndroid.cpp
new file mode 100644
index 000000000000..24eebc8c030f
--- /dev/null
+++ b/source/Host/android/ProcessLauncherAndroid.cpp
@@ -0,0 +1,108 @@
+//===-- ProcessLauncherAndroid.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/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/android/ProcessLauncherAndroid.h"
+
+#include "lldb/Target/ProcessLaunchInfo.h"
+
+#include <limits.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool
+DupDescriptor(const FileSpec &file_spec, int fd, int flags)
+{
+ int target_fd = ::open(file_spec.GetCString(), flags, 0666);
+
+ if (target_fd == -1)
+ return false;
+
+ if (::dup2(target_fd, fd) == -1)
+ return false;
+
+ return (::close(target_fd) == -1) ? false : true;
+}
+
+// If there is no PATH variable specified inside the environment then set the path to /system/bin.
+// It is required because the default path used by execve() is wrong on android.
+static void
+FixupEnvironment(Args& env)
+{
+ static const char* path = "PATH=";
+ static const int path_len = ::strlen(path);
+ for (const char** args = env.GetConstArgumentVector(); *args; ++args)
+ if (::strncmp(path, *args, path_len) == 0)
+ return;
+ env.AppendArgument("PATH=/system/bin");
+}
+
+HostProcess
+ProcessLauncherAndroid::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error)
+{
+ // TODO: Handle other launch parameters specified in launc_info
+
+ char exe_path[PATH_MAX];
+ launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
+
+ lldb::pid_t pid = ::fork();
+ if (pid == static_cast<lldb::pid_t>(-1))
+ {
+ // Fork failed
+ error.SetErrorStringWithFormat("Fork failed with error message: %s", strerror(errno));
+ return HostProcess(LLDB_INVALID_PROCESS_ID);
+ }
+ else if (pid == 0)
+ {
+ if (const lldb_private::FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO)) {
+ FileSpec file_spec = file_action->GetFileSpec();
+ if (file_spec)
+ if (!DupDescriptor(file_spec, STDIN_FILENO, O_RDONLY))
+ exit(-1);
+ }
+
+ if (const lldb_private::FileAction *file_action = launch_info.GetFileActionForFD(STDOUT_FILENO)) {
+ FileSpec file_spec = file_action->GetFileSpec();
+ if (file_spec)
+ if (!DupDescriptor(file_spec, STDOUT_FILENO, O_WRONLY | O_CREAT | O_TRUNC))
+ exit(-1);
+ }
+
+ if (const lldb_private::FileAction *file_action = launch_info.GetFileActionForFD(STDERR_FILENO)) {
+ FileSpec file_spec = file_action->GetFileSpec();
+ if (file_spec)
+ if (!DupDescriptor(file_spec, STDERR_FILENO, O_WRONLY | O_CREAT | O_TRUNC))
+ exit(-1);
+ }
+
+ // Child process
+ const char **argv = launch_info.GetArguments().GetConstArgumentVector();
+
+ Args env = launch_info.GetEnvironmentEntries();
+ FixupEnvironment(env);
+ const char **envp = env.GetConstArgumentVector();
+
+ FileSpec working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir)
+ {
+ if (::chdir(working_dir.GetCString()) != 0)
+ exit(-1);
+ }
+
+ execve(argv[0],
+ const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp));
+ exit(-1);
+ }
+
+ return HostProcess(pid);
+}
diff --git a/source/Host/linux/AbstractSocket.cpp b/source/Host/linux/AbstractSocket.cpp
new file mode 100644
index 000000000000..8ac0107123bb
--- /dev/null
+++ b/source/Host/linux/AbstractSocket.cpp
@@ -0,0 +1,31 @@
+//===-- AbstractSocket.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/linux/AbstractSocket.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+AbstractSocket::AbstractSocket(bool child_processes_inherit, Error &error)
+ : DomainSocket(ProtocolUnixAbstract, child_processes_inherit, error)
+{
+}
+
+size_t
+AbstractSocket::GetNameOffset() const
+{
+ return 1;
+}
+
+void
+AbstractSocket::DeleteSocketFile(llvm::StringRef name)
+{
+}
diff --git a/source/Host/linux/Host.cpp b/source/Host/linux/Host.cpp
new file mode 100644
index 000000000000..cb7369fe7aec
--- /dev/null
+++ b/source/Host/linux/Host.cpp
@@ -0,0 +1,393 @@
+//===-- source/Host/linux/Host.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdio.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#ifdef __ANDROID_NDK__
+#include "lldb/Host/android/Android.h"
+#endif
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "Plugins/Process/Linux/ProcFileReader.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+typedef enum ProcessStateFlags
+{
+ eProcessStateRunning = (1u << 0), // Running
+ eProcessStateSleeping = (1u << 1), // Sleeping in an interruptible wait
+ eProcessStateWaiting = (1u << 2), // Waiting in an uninterruptible disk sleep
+ eProcessStateZombie = (1u << 3), // Zombie
+ eProcessStateTracedOrStopped = (1u << 4), // Traced or stopped (on a signal)
+ eProcessStatePaging = (1u << 5) // Paging
+} ProcessStateFlags;
+
+typedef struct ProcessStatInfo
+{
+ lldb::pid_t ppid; // Parent Process ID
+ uint32_t fProcessState; // ProcessStateFlags
+} ProcessStatInfo;
+
+// Get the process info with additional information from /proc/$PID/stat (like process state, and tracer pid).
+static bool GetProcessAndStatInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info, ProcessStatInfo &stat_info, lldb::pid_t &tracerpid);
+
+static bool
+ReadProcPseudoFileStat (lldb::pid_t pid, ProcessStatInfo& stat_info)
+{
+ // Read the /proc/$PID/stat file.
+ lldb::DataBufferSP buf_sp = process_linux::ProcFileReader::ReadIntoDataBuffer (pid, "stat");
+
+ // The filename of the executable is stored in parenthesis right after the pid. We look for the closing
+ // parenthesis for the filename and work from there in case the name has something funky like ')' in it.
+ const char *filename_end = strrchr ((const char *)buf_sp->GetBytes(), ')');
+ if (filename_end)
+ {
+ char state = '\0';
+ int ppid = LLDB_INVALID_PROCESS_ID;
+
+ // Read state and ppid.
+ sscanf (filename_end + 1, " %c %d", &state, &ppid);
+
+ stat_info.ppid = ppid;
+
+ switch (state)
+ {
+ case 'R':
+ stat_info.fProcessState |= eProcessStateRunning;
+ break;
+ case 'S':
+ stat_info.fProcessState |= eProcessStateSleeping;
+ break;
+ case 'D':
+ stat_info.fProcessState |= eProcessStateWaiting;
+ break;
+ case 'Z':
+ stat_info.fProcessState |= eProcessStateZombie;
+ break;
+ case 'T':
+ stat_info.fProcessState |= eProcessStateTracedOrStopped;
+ break;
+ case 'W':
+ stat_info.fProcessState |= eProcessStatePaging;
+ break;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static void
+GetLinuxProcessUserAndGroup (lldb::pid_t pid, ProcessInstanceInfo &process_info, lldb::pid_t &tracerpid)
+{
+ tracerpid = 0;
+ uint32_t rUid = UINT32_MAX; // Real User ID
+ uint32_t eUid = UINT32_MAX; // Effective User ID
+ uint32_t rGid = UINT32_MAX; // Real Group ID
+ uint32_t eGid = UINT32_MAX; // Effective Group ID
+
+ // Read the /proc/$PID/status file and parse the Uid:, Gid:, and TracerPid: fields.
+ lldb::DataBufferSP buf_sp = process_linux::ProcFileReader::ReadIntoDataBuffer (pid, "status");
+
+ static const char uid_token[] = "Uid:";
+ char *buf_uid = strstr ((char *)buf_sp->GetBytes(), uid_token);
+ if (buf_uid)
+ {
+ // Real, effective, saved set, and file system UIDs. Read the first two.
+ buf_uid += sizeof(uid_token);
+ rUid = strtol (buf_uid, &buf_uid, 10);
+ eUid = strtol (buf_uid, &buf_uid, 10);
+ }
+
+ static const char gid_token[] = "Gid:";
+ char *buf_gid = strstr ((char *)buf_sp->GetBytes(), gid_token);
+ if (buf_gid)
+ {
+ // Real, effective, saved set, and file system GIDs. Read the first two.
+ buf_gid += sizeof(gid_token);
+ rGid = strtol (buf_gid, &buf_gid, 10);
+ eGid = strtol (buf_gid, &buf_gid, 10);
+ }
+
+ static const char tracerpid_token[] = "TracerPid:";
+ char *buf_tracerpid = strstr((char *)buf_sp->GetBytes(), tracerpid_token);
+ if (buf_tracerpid)
+ {
+ // Tracer PID. 0 if we're not being debugged.
+ buf_tracerpid += sizeof(tracerpid_token);
+ tracerpid = strtol (buf_tracerpid, &buf_tracerpid, 10);
+ }
+
+ process_info.SetUserID (rUid);
+ process_info.SetEffectiveUserID (eUid);
+ process_info.SetGroupID (rGid);
+ process_info.SetEffectiveGroupID (eGid);
+}
+
+lldb::DataBufferSP
+Host::GetAuxvData(lldb_private::Process *process)
+{
+ return process_linux::ProcFileReader::ReadIntoDataBuffer (process->GetID(), "auxv");
+}
+
+lldb::DataBufferSP
+Host::GetAuxvData (lldb::pid_t pid)
+{
+ return process_linux::ProcFileReader::ReadIntoDataBuffer (pid, "auxv");
+}
+
+static bool
+IsDirNumeric(const char *dname)
+{
+ for (; *dname; dname++)
+ {
+ if (!isdigit (*dname))
+ return false;
+ }
+ return true;
+}
+
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+ static const char procdir[] = "/proc/";
+
+ DIR *dirproc = opendir (procdir);
+ if (dirproc)
+ {
+ struct dirent *direntry = NULL;
+ const uid_t our_uid = getuid();
+ const lldb::pid_t our_pid = getpid();
+ bool all_users = match_info.GetMatchAllUsers();
+
+ while ((direntry = readdir (dirproc)) != NULL)
+ {
+ if (direntry->d_type != DT_DIR || !IsDirNumeric (direntry->d_name))
+ continue;
+
+ lldb::pid_t pid = atoi (direntry->d_name);
+
+ // Skip this process.
+ if (pid == our_pid)
+ continue;
+
+ lldb::pid_t tracerpid;
+ ProcessStatInfo stat_info;
+ ProcessInstanceInfo process_info;
+
+ if (!GetProcessAndStatInfo (pid, process_info, stat_info, tracerpid))
+ continue;
+
+ // Skip if process is being debugged.
+ if (tracerpid != 0)
+ continue;
+
+ // Skip zombies.
+ if (stat_info.fProcessState & eProcessStateZombie)
+ continue;
+
+ // Check for user match if we're not matching all users and not running as root.
+ if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
+ continue;
+
+ if (match_info.Matches (process_info))
+ {
+ process_infos.Append (process_info);
+ }
+ }
+
+ closedir (dirproc);
+ }
+
+ return process_infos.GetSize();
+}
+
+bool
+Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
+{
+ bool tids_changed = false;
+ static const char procdir[] = "/proc/";
+ static const char taskdir[] = "/task/";
+ std::string process_task_dir = procdir + std::to_string(pid) + taskdir;
+ DIR *dirproc = opendir (process_task_dir.c_str());
+
+ if (dirproc)
+ {
+ struct dirent *direntry = NULL;
+ while ((direntry = readdir (dirproc)) != NULL)
+ {
+ if (direntry->d_type != DT_DIR || !IsDirNumeric (direntry->d_name))
+ continue;
+
+ lldb::tid_t tid = atoi(direntry->d_name);
+ TidMap::iterator it = tids_to_attach.find(tid);
+ if (it == tids_to_attach.end())
+ {
+ tids_to_attach.insert(TidPair(tid, false));
+ tids_changed = true;
+ }
+ }
+ closedir (dirproc);
+ }
+
+ return tids_changed;
+}
+
+static bool
+GetELFProcessCPUType (const char *exe_path, ProcessInstanceInfo &process_info)
+{
+ // Clear the architecture.
+ process_info.GetArchitecture().Clear();
+
+ ModuleSpecList specs;
+ FileSpec filespec (exe_path, false);
+ const size_t num_specs = ObjectFile::GetModuleSpecifications (filespec, 0, 0, specs);
+ // GetModuleSpecifications() could fail if the executable has been deleted or is locked.
+ // But it shouldn't return more than 1 architecture.
+ assert(num_specs <= 1 && "Linux plugin supports only a single architecture");
+ if (num_specs == 1)
+ {
+ ModuleSpec module_spec;
+ if (specs.GetModuleSpecAtIndex (0, module_spec) && module_spec.GetArchitecture().IsValid())
+ {
+ process_info.GetArchitecture () = module_spec.GetArchitecture();
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool
+GetProcessAndStatInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info, ProcessStatInfo &stat_info, lldb::pid_t &tracerpid)
+{
+ tracerpid = 0;
+ process_info.Clear();
+ ::memset (&stat_info, 0, sizeof(stat_info));
+ stat_info.ppid = LLDB_INVALID_PROCESS_ID;
+
+ // Use special code here because proc/[pid]/exe is a symbolic link.
+ char link_path[PATH_MAX];
+ char exe_path[PATH_MAX] = "";
+ if (snprintf (link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", pid) <= 0)
+ return false;
+
+ ssize_t len = readlink (link_path, exe_path, sizeof(exe_path) - 1);
+ if (len <= 0)
+ return false;
+
+ // readlink does not append a null byte.
+ exe_path[len] = 0;
+
+ // If the binary has been deleted, the link name has " (deleted)" appended.
+ // Remove if there.
+ static const ssize_t deleted_len = strlen(" (deleted)");
+ if (len > deleted_len &&
+ !strcmp(exe_path + len - deleted_len, " (deleted)"))
+ {
+ exe_path[len - deleted_len] = 0;
+ }
+ else
+ {
+ GetELFProcessCPUType (exe_path, process_info);
+ }
+
+ process_info.SetProcessID(pid);
+ process_info.GetExecutableFile().SetFile(exe_path, false);
+ process_info.GetArchitecture().MergeFrom(HostInfo::GetArchitecture());
+
+ lldb::DataBufferSP buf_sp;
+
+ // Get the process environment.
+ buf_sp = process_linux::ProcFileReader::ReadIntoDataBuffer(pid, "environ");
+ Args &info_env = process_info.GetEnvironmentEntries();
+ char *next_var = (char *)buf_sp->GetBytes();
+ char *end_buf = next_var + buf_sp->GetByteSize();
+ while (next_var < end_buf && 0 != *next_var)
+ {
+ info_env.AppendArgument(next_var);
+ next_var += strlen(next_var) + 1;
+ }
+
+ // Get the command line used to start the process.
+ buf_sp = process_linux::ProcFileReader::ReadIntoDataBuffer(pid, "cmdline");
+
+ // Grab Arg0 first, if there is one.
+ char *cmd = (char *)buf_sp->GetBytes();
+ if (cmd)
+ {
+ process_info.SetArg0(cmd);
+
+ // Now process any remaining arguments.
+ Args &info_args = process_info.GetArguments();
+ char *next_arg = cmd + strlen(cmd) + 1;
+ end_buf = cmd + buf_sp->GetByteSize();
+ while (next_arg < end_buf && 0 != *next_arg)
+ {
+ info_args.AppendArgument(next_arg);
+ next_arg += strlen(next_arg) + 1;
+ }
+ }
+
+ // Read /proc/$PID/stat to get our parent pid.
+ if (ReadProcPseudoFileStat (pid, stat_info))
+ {
+ process_info.SetParentProcessID (stat_info.ppid);
+ }
+
+ // Get User and Group IDs and get tracer pid.
+ GetLinuxProcessUserAndGroup (pid, process_info, tracerpid);
+
+ return true;
+}
+
+bool
+Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ lldb::pid_t tracerpid;
+ ProcessStatInfo stat_info;
+
+ return GetProcessAndStatInfo (pid, process_info, stat_info, tracerpid);
+}
+
+size_t
+Host::GetEnvironment (StringList &env)
+{
+ char **host_env = environ;
+ char *env_entry;
+ size_t i;
+ for (i=0; (env_entry = host_env[i]) != NULL; ++i)
+ env.AppendString(env_entry);
+ return i;
+}
+
+Error
+Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
+{
+ return Error("unimplemented");
+}
diff --git a/source/Host/linux/HostInfoLinux.cpp b/source/Host/linux/HostInfoLinux.cpp
new file mode 100644
index 000000000000..4732a2a571b6
--- /dev/null
+++ b/source/Host/linux/HostInfoLinux.cpp
@@ -0,0 +1,282 @@
+//===-- HostInfoLinux.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/Core/Log.h"
+#include "lldb/Host/linux/HostInfoLinux.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+#include <algorithm>
+#include <mutex> // std::once
+
+using namespace lldb_private;
+
+namespace
+{
+struct HostInfoLinuxFields
+{
+ HostInfoLinuxFields()
+ : m_os_major(0)
+ , m_os_minor(0)
+ , m_os_update(0)
+ {
+ }
+
+ std::string m_distribution_id;
+ uint32_t m_os_major;
+ uint32_t m_os_minor;
+ uint32_t m_os_update;
+};
+
+HostInfoLinuxFields *g_fields = nullptr;
+}
+
+void
+HostInfoLinux::Initialize()
+{
+ HostInfoPosix::Initialize();
+
+ g_fields = new HostInfoLinuxFields();
+}
+
+uint32_t
+HostInfoLinux::GetMaxThreadNameLength()
+{
+ return 16;
+}
+
+bool
+HostInfoLinux::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update)
+{
+ static bool success = false;
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+
+ struct utsname un;
+ if (uname(&un) == 0)
+ {
+ int status = sscanf(un.release, "%u.%u.%u", &g_fields->m_os_major, &g_fields->m_os_minor, &g_fields->m_os_update);
+ if (status == 3)
+ success = true;
+ else
+ {
+ // Some kernels omit the update version, so try looking for just "X.Y" and
+ // set update to 0.
+ g_fields->m_os_update = 0;
+ status = sscanf(un.release, "%u.%u", &g_fields->m_os_major, &g_fields->m_os_minor);
+ if (status == 2)
+ success = true;
+ }
+ }
+ });
+
+
+ major = g_fields->m_os_major;
+ minor = g_fields->m_os_minor;
+ update = g_fields->m_os_update;
+ return success;
+}
+
+bool
+HostInfoLinux::GetOSBuildString(std::string &s)
+{
+ struct utsname un;
+ ::memset(&un, 0, sizeof(utsname));
+ s.clear();
+
+ if (uname(&un) < 0)
+ return false;
+
+ s.assign(un.release);
+ return true;
+}
+
+bool
+HostInfoLinux::GetOSKernelDescription(std::string &s)
+{
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(utsname));
+ s.clear();
+
+ if (uname(&un) < 0)
+ return false;
+
+ s.assign(un.version);
+ return true;
+}
+
+llvm::StringRef
+HostInfoLinux::GetDistributionId()
+{
+ // Try to run 'lbs_release -i', and use that response
+ // for the distribution id.
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST));
+ if (log)
+ log->Printf("attempting to determine Linux distribution...");
+
+ // check if the lsb_release command exists at one of the
+ // following paths
+ const char *const exe_paths[] = {"/bin/lsb_release", "/usr/bin/lsb_release"};
+
+ for (size_t exe_index = 0; exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index)
+ {
+ const char *const get_distribution_info_exe = exe_paths[exe_index];
+ if (access(get_distribution_info_exe, F_OK))
+ {
+ // this exe doesn't exist, move on to next exe
+ if (log)
+ log->Printf("executable doesn't exist: %s", get_distribution_info_exe);
+ continue;
+ }
+
+ // execute the distribution-retrieval command, read output
+ std::string get_distribution_id_command(get_distribution_info_exe);
+ get_distribution_id_command += " -i";
+
+ FILE *file = popen(get_distribution_id_command.c_str(), "r");
+ if (!file)
+ {
+ if (log)
+ log->Printf("failed to run command: \"%s\", cannot retrieve "
+ "platform information",
+ get_distribution_id_command.c_str());
+ break;
+ }
+
+ // retrieve the distribution id string.
+ char distribution_id[256] = {'\0'};
+ if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != NULL)
+ {
+ if (log)
+ log->Printf("distribution id command returned \"%s\"", distribution_id);
+
+ const char *const distributor_id_key = "Distributor ID:\t";
+ if (strstr(distribution_id, distributor_id_key))
+ {
+ // strip newlines
+ std::string id_string(distribution_id + strlen(distributor_id_key));
+ id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), id_string.end());
+
+ // lower case it and convert whitespace to underscores
+ std::transform(id_string.begin(), id_string.end(), id_string.begin(), [](char ch)
+ {
+ return tolower(isspace(ch) ? '_' : ch);
+ });
+
+ g_fields->m_distribution_id = id_string;
+ if (log)
+ log->Printf("distribution id set to \"%s\"", g_fields->m_distribution_id.c_str());
+ }
+ else
+ {
+ if (log)
+ log->Printf("failed to find \"%s\" field in \"%s\"", distributor_id_key, distribution_id);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("failed to retrieve distribution id, \"%s\" returned no"
+ " lines",
+ get_distribution_id_command.c_str());
+ }
+
+ // clean up the file
+ pclose(file);
+ }
+ });
+
+ return g_fields->m_distribution_id.c_str();
+}
+
+FileSpec
+HostInfoLinux::GetProgramFileSpec()
+{
+ static FileSpec g_program_filespec;
+
+ if (!g_program_filespec)
+ {
+ char exe_path[PATH_MAX];
+ ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
+ if (len > 0)
+ {
+ exe_path[len] = 0;
+ g_program_filespec.SetFile(exe_path, false);
+ }
+ }
+
+ return g_program_filespec;
+}
+
+bool
+HostInfoLinux::ComputeSupportExeDirectory(FileSpec &file_spec)
+{
+ if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) &&
+ file_spec.IsAbsolute() &&
+ file_spec.Exists())
+ return true;
+ file_spec.GetDirectory() = GetProgramFileSpec().GetDirectory();
+ return !file_spec.GetDirectory().IsEmpty();
+}
+
+bool
+HostInfoLinux::ComputeSystemPluginsDirectory(FileSpec &file_spec)
+{
+ FileSpec temp_file("/usr/lib/lldb", true);
+ file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str());
+ return true;
+}
+
+bool
+HostInfoLinux::ComputeUserPluginsDirectory(FileSpec &file_spec)
+{
+ // XDG Base Directory Specification
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ // If XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb.
+ const char *xdg_data_home = getenv("XDG_DATA_HOME");
+ if (xdg_data_home && xdg_data_home[0])
+ {
+ std::string user_plugin_dir(xdg_data_home);
+ user_plugin_dir += "/lldb";
+ file_spec.GetDirectory().SetCString(user_plugin_dir.c_str());
+ }
+ else
+ file_spec.GetDirectory().SetCString("~/.local/share/lldb");
+ return true;
+}
+
+void
+HostInfoLinux::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
+{
+ HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64);
+
+ const char *distribution_id = GetDistributionId().data();
+
+ // On Linux, "unknown" in the vendor slot isn't what we want for the default
+ // triple. It's probably an artifact of config.guess.
+ if (arch_32.IsValid())
+ {
+ arch_32.SetDistributionId(distribution_id);
+ if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor)
+ arch_32.GetTriple().setVendorName(llvm::StringRef());
+ }
+ if (arch_64.IsValid())
+ {
+ arch_64.SetDistributionId(distribution_id);
+ if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor)
+ arch_64.GetTriple().setVendorName(llvm::StringRef());
+ }
+}
diff --git a/source/Host/linux/HostThreadLinux.cpp b/source/Host/linux/HostThreadLinux.cpp
new file mode 100644
index 000000000000..2312ced0107b
--- /dev/null
+++ b/source/Host/linux/HostThreadLinux.cpp
@@ -0,0 +1,52 @@
+//===-- HostThreadLinux.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/Core/DataBuffer.h"
+#include "lldb/Host/linux/HostThreadLinux.h"
+#include "Plugins/Process/Linux/ProcFileReader.h"
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <pthread.h>
+
+using namespace lldb_private;
+
+HostThreadLinux::HostThreadLinux()
+ : HostThreadPosix()
+{
+}
+
+HostThreadLinux::HostThreadLinux(lldb::thread_t thread)
+ : HostThreadPosix(thread)
+{
+}
+
+void
+HostThreadLinux::SetName(lldb::thread_t thread, llvm::StringRef name)
+{
+#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
+ ::pthread_setname_np(thread, name.data());
+#else
+ (void) thread;
+ (void) name;
+#endif
+}
+
+void
+HostThreadLinux::GetName(lldb::thread_t thread, llvm::SmallVectorImpl<char> &name)
+{
+ // Read /proc/$TID/comm file.
+ lldb::DataBufferSP buf_sp = process_linux::ProcFileReader::ReadIntoDataBuffer(thread, "comm");
+ const char *comm_str = (const char *)buf_sp->GetBytes();
+ const char *cr_str = ::strchr(comm_str, '\n');
+ size_t length = cr_str ? (cr_str - comm_str) : strlen(comm_str);
+
+ name.clear();
+ name.append(comm_str, comm_str + length);
+}
diff --git a/source/Host/linux/LibcGlue.cpp b/source/Host/linux/LibcGlue.cpp
new file mode 100644
index 000000000000..63d026f76c62
--- /dev/null
+++ b/source/Host/linux/LibcGlue.cpp
@@ -0,0 +1,30 @@
+//===-- LibcGlue.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This file adds functions missing from libc on older versions of linux
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <lldb/Host/linux/Uio.h>
+#include <cerrno>
+
+#ifndef HAVE_PROCESS_VM_READV // If the syscall wrapper is not available, provide one.
+ssize_t process_vm_readv(::pid_t pid,
+ const struct iovec *local_iov, unsigned long liovcnt,
+ const struct iovec *remote_iov, unsigned long riovcnt,
+ unsigned long flags)
+{
+#ifdef HAVE_NR_PROCESS_VM_READV // If we have the syscall number, we can issue the syscall ourselves.
+ return syscall(__NR_process_vm_readv, pid, local_iov, liovcnt, remote_iov, riovcnt, flags);
+#else // If not, let's pretend the syscall is not present.
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif
diff --git a/source/Host/linux/ThisThread.cpp b/source/Host/linux/ThisThread.cpp
new file mode 100644
index 000000000000..1c68c8ba16d7
--- /dev/null
+++ b/source/Host/linux/ThisThread.cpp
@@ -0,0 +1,29 @@
+//===-- ThisThread.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/HostNativeThread.h"
+#include "lldb/Host/ThisThread.h"
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <pthread.h>
+
+using namespace lldb_private;
+
+void
+ThisThread::SetName(llvm::StringRef name)
+{
+ HostNativeThread::SetName(::pthread_self(), name);
+}
+
+void
+ThisThread::GetName(llvm::SmallVectorImpl<char> &name)
+{
+ HostNativeThread::GetName(::pthread_self(), name);
+}
diff --git a/source/Host/macosx/Host.mm b/source/Host/macosx/Host.mm
new file mode 100644
index 000000000000..2db27a276e4a
--- /dev/null
+++ b/source/Host/macosx/Host.mm
@@ -0,0 +1,1587 @@
+//===-- Host.mm -------------------------------------------------*- 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 <AvailabilityMacros.h>
+
+#if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+#define NO_XPC_SERVICES 1
+#endif
+
+#if !defined(NO_XPC_SERVICES)
+#define __XPC_PRIVATE_H__
+#include <xpc/xpc.h>
+
+#define LaunchUsingXPCRightName "com.apple.dt.Xcode.RootDebuggingXPCService"
+
+// These XPC messaging keys are used for communication between Host.mm and the XPC service.
+#define LauncherXPCServiceAuthKey "auth-key"
+#define LauncherXPCServiceArgPrefxKey "arg"
+#define LauncherXPCServiceEnvPrefxKey "env"
+#define LauncherXPCServiceCPUTypeKey "cpuType"
+#define LauncherXPCServicePosixspawnFlagsKey "posixspawnFlags"
+#define LauncherXPCServiceStdInPathKeyKey "stdInPath"
+#define LauncherXPCServiceStdOutPathKeyKey "stdOutPath"
+#define LauncherXPCServiceStdErrPathKeyKey "stdErrPath"
+#define LauncherXPCServiceChildPIDKey "childPID"
+#define LauncherXPCServiceErrorTypeKey "errorType"
+#define LauncherXPCServiceCodeTypeKey "errorCode"
+
+#endif
+
+#include "llvm/Support/Host.h"
+
+#include <asl.h>
+#include <crt_externs.h>
+#include <grp.h>
+#include <libproc.h>
+#include <pwd.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/CleanUp.h"
+#include "lldb/Utility/NameMatches.h"
+
+#include "cfcpp/CFCBundle.h"
+#include "cfcpp/CFCMutableArray.h"
+#include "cfcpp/CFCMutableDictionary.h"
+#include "cfcpp/CFCReleaser.h"
+#include "cfcpp/CFCString.h"
+
+
+#include <objc/objc-auto.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
+
+#ifndef _POSIX_SPAWN_DISABLE_ASLR
+#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
+#endif
+
+extern "C"
+{
+ int __pthread_chdir(const char *path);
+ int __pthread_fchdir (int fildes);
+}
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle_directory)
+{
+#if defined (__APPLE__)
+ if (file.GetFileType () == FileSpec::eFileTypeDirectory)
+ {
+ char path[PATH_MAX];
+ if (file.GetPath(path, sizeof(path)))
+ {
+ CFCBundle bundle (path);
+ if (bundle.GetPath (path, sizeof(path)))
+ {
+ bundle_directory.SetFile (path, false);
+ return true;
+ }
+ }
+ }
+#endif
+ bundle_directory.Clear();
+ return false;
+}
+
+
+bool
+Host::ResolveExecutableInBundle (FileSpec &file)
+{
+#if defined (__APPLE__)
+ if (file.GetFileType () == FileSpec::eFileTypeDirectory)
+ {
+ char path[PATH_MAX];
+ if (file.GetPath(path, sizeof(path)))
+ {
+ CFCBundle bundle (path);
+ CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
+ if (url.get())
+ {
+ if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
+ {
+ file.SetFile(path, false);
+ return true;
+ }
+ }
+ }
+ }
+#endif
+ return false;
+}
+
+static void *
+AcceptPIDFromInferior (void *arg)
+{
+ const char *connect_url = (const char *)arg;
+ ConnectionFileDescriptor file_conn;
+ Error error;
+ if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
+ {
+ char pid_str[256];
+ ::memset (pid_str, 0, sizeof(pid_str));
+ ConnectionStatus status;
+ const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL);
+ if (pid_str_len > 0)
+ {
+ int pid = atoi (pid_str);
+ return (void *)(intptr_t)pid;
+ }
+ }
+ return NULL;
+}
+
+static bool
+WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
+{
+ const int time_delta_usecs = 100000;
+ const int num_retries = timeout_in_seconds/time_delta_usecs;
+ for (int i=0; i<num_retries; i++)
+ {
+ struct proc_bsdinfo bsd_info;
+ int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
+ (uint64_t) 0,
+ &bsd_info,
+ PROC_PIDTBSDINFO_SIZE);
+
+ switch (error)
+ {
+ case EINVAL:
+ case ENOTSUP:
+ case ESRCH:
+ case EPERM:
+ return false;
+
+ default:
+ break;
+
+ case 0:
+ if (bsd_info.pbi_status == SSTOP)
+ return true;
+ }
+ ::usleep (time_delta_usecs);
+ }
+ return false;
+}
+#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
+
+//static lldb::pid_t
+//LaunchInNewTerminalWithCommandFile
+//(
+// const char **argv,
+// const char **envp,
+// const char *working_dir,
+// const ArchSpec *arch_spec,
+// bool stop_at_entry,
+// bool disable_aslr
+//)
+//{
+// if (!argv || !argv[0])
+// return LLDB_INVALID_PROCESS_ID;
+//
+// OSStatus error = 0;
+//
+// FileSpec program (argv[0], false);
+//
+//
+// std::string unix_socket_name;
+//
+// char temp_file_path[PATH_MAX];
+// const char *tmpdir = ::getenv ("TMPDIR");
+// if (tmpdir == NULL)
+// tmpdir = "/tmp/";
+// ::snprintf (temp_file_path, sizeof(temp_file_path), "%s%s-XXXXXX", tmpdir, program.GetFilename().AsCString());
+//
+// if (::mktemp (temp_file_path) == NULL)
+// return LLDB_INVALID_PROCESS_ID;
+//
+// unix_socket_name.assign (temp_file_path);
+//
+// ::strlcat (temp_file_path, ".command", sizeof (temp_file_path));
+//
+// StreamFile command_file;
+// command_file.GetFile().Open (temp_file_path,
+// File::eOpenOptionWrite | File::eOpenOptionCanCreate,
+// lldb::eFilePermissionsDefault);
+//
+// if (!command_file.GetFile().IsValid())
+// return LLDB_INVALID_PROCESS_ID;
+//
+// FileSpec darwin_debug_file_spec;
+// if (!HostInfo::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec))
+// return LLDB_INVALID_PROCESS_ID;
+// darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
+//
+// if (!darwin_debug_file_spec.Exists())
+// return LLDB_INVALID_PROCESS_ID;
+//
+// char launcher_path[PATH_MAX];
+// darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
+// command_file.Printf("\"%s\" ", launcher_path);
+//
+// command_file.Printf("--unix-socket=%s ", unix_socket_name.c_str());
+//
+// if (arch_spec && arch_spec->IsValid())
+// {
+// command_file.Printf("--arch=%s ", arch_spec->GetArchitectureName());
+// }
+//
+// if (disable_aslr)
+// {
+// command_file.PutCString("--disable-aslr ");
+// }
+//
+// command_file.PutCString("-- ");
+//
+// if (argv)
+// {
+// for (size_t i=0; argv[i] != NULL; ++i)
+// {
+// command_file.Printf("\"%s\" ", argv[i]);
+// }
+// }
+// command_file.PutCString("\necho Process exited with status $?\n");
+// command_file.GetFile().Close();
+// if (::chmod (temp_file_path, S_IRWXU | S_IRWXG) != 0)
+// return LLDB_INVALID_PROCESS_ID;
+//
+// CFCMutableDictionary cf_env_dict;
+//
+// const bool can_create = true;
+// if (envp)
+// {
+// for (size_t i=0; envp[i] != NULL; ++i)
+// {
+// const char *env_entry = envp[i];
+// const char *equal_pos = strchr(env_entry, '=');
+// if (equal_pos)
+// {
+// std::string env_key (env_entry, equal_pos);
+// std::string env_val (equal_pos + 1);
+// CFCString cf_env_key (env_key.c_str(), kCFStringEncodingUTF8);
+// CFCString cf_env_val (env_val.c_str(), kCFStringEncodingUTF8);
+// cf_env_dict.AddValue (cf_env_key.get(), cf_env_val.get(), can_create);
+// }
+// }
+// }
+//
+// LSApplicationParameters app_params;
+// ::memset (&app_params, 0, sizeof (app_params));
+// app_params.flags = kLSLaunchDontAddToRecents | kLSLaunchAsync;
+// app_params.argv = NULL;
+// app_params.environment = (CFDictionaryRef)cf_env_dict.get();
+//
+// CFCReleaser<CFURLRef> command_file_url (::CFURLCreateFromFileSystemRepresentation (NULL,
+// (const UInt8 *)temp_file_path,
+// strlen(temp_file_path),
+// false));
+//
+// CFCMutableArray urls;
+//
+// // Terminal.app will open the ".command" file we have created
+// // and run our process inside it which will wait at the entry point
+// // for us to attach.
+// urls.AppendValue(command_file_url.get());
+//
+//
+// lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+//
+// Error lldb_error;
+// // Sleep and wait a bit for debugserver to start to listen...
+// char connect_url[128];
+// ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name.c_str());
+//
+// // Spawn a new thread to accept incoming connection on the connect_url
+// // so we can grab the pid from the inferior
+// lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name.c_str(),
+// AcceptPIDFromInferior,
+// connect_url,
+// &lldb_error);
+//
+// ProcessSerialNumber psn;
+// error = LSOpenURLsWithRole(urls.get(), kLSRolesShell, NULL, &app_params, &psn, 1);
+// if (error == noErr)
+// {
+// thread_result_t accept_thread_result = NULL;
+// if (Host::ThreadJoin (accept_thread, &accept_thread_result, &lldb_error))
+// {
+// if (accept_thread_result)
+// {
+// pid = (intptr_t)accept_thread_result;
+//
+// // Wait for process to be stopped the entry point by watching
+// // for the process status to be set to SSTOP which indicates it it
+// // SIGSTOP'ed at the entry point
+// WaitForProcessToSIGSTOP (pid, 5);
+// }
+// }
+// }
+// else
+// {
+// Host::ThreadCancel (accept_thread, &lldb_error);
+// }
+//
+// return pid;
+//}
+
+const char *applscript_in_new_tty =
+"tell application \"Terminal\"\n"
+" do script \"%s\"\n"
+"end tell\n";
+
+
+const char *applscript_in_existing_tty = "\
+set the_shell_script to \"%s\"\n\
+tell application \"Terminal\"\n\
+ repeat with the_window in (get windows)\n\
+ repeat with the_tab in tabs of the_window\n\
+ set the_tty to tty in the_tab\n\
+ if the_tty contains \"%s\" then\n\
+ if the_tab is not busy then\n\
+ set selected of the_tab to true\n\
+ set frontmost of the_window to true\n\
+ do script the_shell_script in the_tab\n\
+ return\n\
+ end if\n\
+ end if\n\
+ end repeat\n\
+ end repeat\n\
+ do script the_shell_script\n\
+end tell\n";
+
+
+static Error
+LaunchInNewTerminalWithAppleScript (const char *exe_path, ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
+ if (::mktemp (unix_socket_name) == NULL)
+ {
+ error.SetErrorString ("failed to make temporary path for a unix socket");
+ return error;
+ }
+
+ StreamString command;
+ FileSpec darwin_debug_file_spec;
+ if (!HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, darwin_debug_file_spec))
+ {
+ error.SetErrorString ("can't locate the 'darwin-debug' executable");
+ return error;
+ }
+
+ darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
+
+ if (!darwin_debug_file_spec.Exists())
+ {
+ error.SetErrorStringWithFormat ("the 'darwin-debug' executable doesn't exists at '%s'",
+ darwin_debug_file_spec.GetPath().c_str());
+ return error;
+ }
+
+ char launcher_path[PATH_MAX];
+ darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
+
+ const ArchSpec &arch_spec = launch_info.GetArchitecture();
+ // Only set the architecture if it is valid and if it isn't Haswell (x86_64h).
+ if (arch_spec.IsValid() && arch_spec.GetCore() != ArchSpec::eCore_x86_64_x86_64h)
+ command.Printf("arch -arch %s ", arch_spec.GetArchitectureName());
+
+ command.Printf("'%s' --unix-socket=%s", launcher_path, unix_socket_name);
+
+ if (arch_spec.IsValid())
+ command.Printf(" --arch=%s", arch_spec.GetArchitectureName());
+
+ FileSpec working_dir{launch_info.GetWorkingDirectory()};
+ if (working_dir)
+ command.Printf(" --working-dir '%s'", working_dir.GetCString());
+ else
+ {
+ char cwd[PATH_MAX];
+ if (getcwd(cwd, PATH_MAX))
+ command.Printf(" --working-dir '%s'", cwd);
+ }
+
+ if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR))
+ command.PutCString(" --disable-aslr");
+
+ // We are launching on this host in a terminal. So compare the environment on the host
+ // to what is supplied in the launch_info. Any items that aren't in the host environment
+ // need to be sent to darwin-debug. If we send all environment entries, we might blow the
+ // max command line length, so we only send user modified entries.
+ const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector ();
+
+ StringList host_env;
+ const size_t host_env_count = Host::GetEnvironment (host_env);
+
+ if (envp && envp[0])
+ {
+ const char *env_entry;
+ for (size_t env_idx = 0; (env_entry = envp[env_idx]) != NULL; ++env_idx)
+ {
+ bool add_entry = true;
+ for (size_t i=0; i<host_env_count; ++i)
+ {
+ const char *host_env_entry = host_env.GetStringAtIndex(i);
+ if (strcmp(env_entry, host_env_entry) == 0)
+ {
+ add_entry = false;
+ break;
+ }
+ }
+ if (add_entry)
+ {
+ command.Printf(" --env='%s'", env_entry);
+ }
+ }
+ }
+
+ command.PutCString(" -- ");
+
+ const char **argv = launch_info.GetArguments().GetConstArgumentVector ();
+ if (argv)
+ {
+ for (size_t i=0; argv[i] != NULL; ++i)
+ {
+ if (i==0)
+ command.Printf(" '%s'", exe_path);
+ else
+ command.Printf(" '%s'", argv[i]);
+ }
+ }
+ else
+ {
+ command.Printf(" '%s'", exe_path);
+ }
+ command.PutCString (" ; echo Process exited with status $?");
+ if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit))
+ command.PutCString (" ; exit");
+
+ StreamString applescript_source;
+
+ const char *tty_command = command.GetString().c_str();
+// if (tty_name && tty_name[0])
+// {
+// applescript_source.Printf (applscript_in_existing_tty,
+// tty_command,
+// tty_name);
+// }
+// else
+// {
+ applescript_source.Printf (applscript_in_new_tty,
+ tty_command);
+// }
+
+
+
+ const char *script_source = applescript_source.GetString().c_str();
+ //puts (script_source);
+ NSAppleScript* applescript = [[NSAppleScript alloc] initWithSource:[NSString stringWithCString:script_source encoding:NSUTF8StringEncoding]];
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ Error lldb_error;
+ // Sleep and wait a bit for debugserver to start to listen...
+ ConnectionFileDescriptor file_conn;
+ char connect_url[128];
+ ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
+
+ // Spawn a new thread to accept incoming connection on the connect_url
+ // so we can grab the pid from the inferior. We have to do this because we
+ // are sending an AppleScript that will launch a process in Terminal.app,
+ // in a shell and the shell will fork/exec a couple of times before we get
+ // to the process that we wanted to launch. So when our process actually
+ // gets launched, we will handshake with it and get the process ID for it.
+ HostThread accept_thread = ThreadLauncher::LaunchThread(unix_socket_name, AcceptPIDFromInferior, connect_url, &lldb_error);
+
+ [applescript executeAndReturnError:nil];
+
+ thread_result_t accept_thread_result = NULL;
+ lldb_error = accept_thread.Join(&accept_thread_result);
+ if (lldb_error.Success() && accept_thread_result)
+ {
+ pid = (intptr_t)accept_thread_result;
+
+ // Wait for process to be stopped at the entry point by watching
+ // for the process status to be set to SSTOP which indicates it it
+ // SIGSTOP'ed at the entry point
+ WaitForProcessToSIGSTOP(pid, 5);
+ }
+
+ FileSystem::Unlink(FileSpec{unix_socket_name, false});
+ [applescript release];
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ launch_info.SetProcessID (pid);
+ return error;
+}
+
+#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
+
+
+// On MacOSX CrashReporter will display a string for each shared library if
+// the shared library has an exported symbol named "__crashreporter_info__".
+
+static Mutex&
+GetCrashReporterMutex ()
+{
+ static Mutex g_mutex;
+ return g_mutex;
+}
+
+extern "C" {
+ const char *__crashreporter_info__ = NULL;
+}
+
+asm(".desc ___crashreporter_info__, 0x10");
+
+void
+Host::SetCrashDescriptionWithFormat (const char *format, ...)
+{
+ static StreamString g_crash_description;
+ Mutex::Locker locker (GetCrashReporterMutex ());
+
+ if (format)
+ {
+ va_list args;
+ va_start (args, format);
+ g_crash_description.GetString().clear();
+ g_crash_description.PrintfVarArg(format, args);
+ va_end (args);
+ __crashreporter_info__ = g_crash_description.GetData();
+ }
+ else
+ {
+ __crashreporter_info__ = NULL;
+ }
+}
+
+void
+Host::SetCrashDescription (const char *cstr)
+{
+ Mutex::Locker locker (GetCrashReporterMutex ());
+ static std::string g_crash_description;
+ if (cstr)
+ {
+ g_crash_description.assign (cstr);
+ __crashreporter_info__ = g_crash_description.c_str();
+ }
+ else
+ {
+ __crashreporter_info__ = NULL;
+ }
+}
+
+bool
+Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
+{
+#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ return false;
+#else
+ // We attach this to an 'odoc' event to specify a particular selection
+ typedef struct {
+ int16_t reserved0; // must be zero
+ int16_t fLineNumber;
+ int32_t fSelStart;
+ int32_t fSelEnd;
+ uint32_t reserved1; // must be zero
+ uint32_t reserved2; // must be zero
+ } BabelAESelInfo;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST));
+ char file_path[PATH_MAX];
+ file_spec.GetPath(file_path, PATH_MAX);
+ CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
+ CFCReleaser<CFURLRef> file_URL (::CFURLCreateWithFileSystemPath (NULL,
+ file_cfstr.get(),
+ kCFURLPOSIXPathStyle,
+ false));
+
+ if (log)
+ log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no);
+
+ long error;
+ BabelAESelInfo file_and_line_info =
+ {
+ 0, // reserved0
+ (int16_t)(line_no - 1), // fLineNumber (zero based line number)
+ 1, // fSelStart
+ 1024, // fSelEnd
+ 0, // reserved1
+ 0 // reserved2
+ };
+
+ AEKeyDesc file_and_line_desc;
+
+ error = ::AECreateDesc (typeUTF8Text,
+ &file_and_line_info,
+ sizeof (file_and_line_info),
+ &(file_and_line_desc.descContent));
+
+ if (error != noErr)
+ {
+ if (log)
+ log->Printf("Error creating AEDesc: %ld.\n", error);
+ return false;
+ }
+
+ file_and_line_desc.descKey = keyAEPosition;
+
+ static std::string g_app_name;
+ static FSRef g_app_fsref;
+
+ LSApplicationParameters app_params;
+ ::memset (&app_params, 0, sizeof (app_params));
+ app_params.flags = kLSLaunchDefaults |
+ kLSLaunchDontAddToRecents |
+ kLSLaunchDontSwitch;
+
+ char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR");
+
+ if (external_editor)
+ {
+ if (log)
+ log->Printf("Looking for external editor \"%s\".\n", external_editor);
+
+ if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0)
+ {
+ CFCString editor_name (external_editor, kCFStringEncodingUTF8);
+ error = ::LSFindApplicationForInfo (kLSUnknownCreator,
+ NULL,
+ editor_name.get(),
+ &g_app_fsref,
+ NULL);
+
+ // If we found the app, then store away the name so we don't have to re-look it up.
+ if (error != noErr)
+ {
+ if (log)
+ log->Printf("Could not find External Editor application, error: %ld.\n", error);
+ return false;
+ }
+
+ }
+ app_params.application = &g_app_fsref;
+ }
+
+ ProcessSerialNumber psn;
+ CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
+ error = ::LSOpenURLsWithRole (file_array.get(),
+ kLSRolesAll,
+ &file_and_line_desc,
+ &app_params,
+ &psn,
+ 1);
+
+ AEDisposeDesc (&(file_and_line_desc.descContent));
+
+ if (error != noErr)
+ {
+ if (log)
+ log->Printf("LSOpenURLsWithRole failed, error: %ld.\n", error);
+
+ return false;
+ }
+
+ return true;
+#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
+}
+
+size_t
+Host::GetEnvironment (StringList &env)
+{
+ char **host_env = *_NSGetEnviron();
+ char *env_entry;
+ size_t i;
+ for (i=0; (env_entry = host_env[i]) != NULL; ++i)
+ env.AppendString(env_entry);
+ return i;
+
+}
+
+static bool
+GetMacOSXProcessCPUType (ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid())
+ {
+ // Make a new mib to stay thread safe
+ int mib[CTL_MAXNAME]={0,};
+ size_t mib_len = CTL_MAXNAME;
+ if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len))
+ return false;
+
+ mib[mib_len] = process_info.GetProcessID();
+ mib_len++;
+
+ cpu_type_t cpu, sub = 0;
+ size_t len = sizeof(cpu);
+ if (::sysctl (mib, mib_len, &cpu, &len, 0, 0) == 0)
+ {
+ switch (cpu)
+ {
+ case CPU_TYPE_I386: sub = CPU_SUBTYPE_I386_ALL; break;
+ case CPU_TYPE_X86_64: sub = CPU_SUBTYPE_X86_64_ALL; break;
+
+#if defined (CPU_TYPE_ARM64) && defined (CPU_SUBTYPE_ARM64_ALL)
+ case CPU_TYPE_ARM64: sub = CPU_SUBTYPE_ARM64_ALL; break;
+#endif
+
+ case CPU_TYPE_ARM:
+ {
+ // Note that we fetched the cpu type from the PROCESS but we can't get a cpusubtype of the
+ // process -- we can only get the host's cpu subtype.
+ uint32_t cpusubtype = 0;
+ len = sizeof(cpusubtype);
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
+ sub = cpusubtype;
+
+ bool host_cpu_is_64bit;
+ uint32_t is64bit_capable;
+ size_t is64bit_capable_len = sizeof (is64bit_capable);
+ if (sysctlbyname("hw.cpu64bit_capable", &is64bit_capable, &is64bit_capable_len, NULL, 0) == 0)
+ host_cpu_is_64bit = true;
+ else
+ host_cpu_is_64bit = false;
+
+ // if the host is an armv8 device, its cpusubtype will be in CPU_SUBTYPE_ARM64 numbering
+ // and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value instead.
+
+ if (host_cpu_is_64bit)
+ {
+ sub = CPU_SUBTYPE_ARM_V7;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ process_info.GetArchitecture ().SetArchitecture (eArchTypeMachO, cpu, sub);
+ return true;
+ }
+ }
+ process_info.GetArchitecture().Clear();
+ return false;
+}
+
+static bool
+GetMacOSXProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
+ ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid())
+ {
+ int proc_args_mib[3] = { CTL_KERN, KERN_PROCARGS2, (int)process_info.GetProcessID() };
+
+ size_t arg_data_size = 0;
+ if (::sysctl (proc_args_mib, 3, nullptr, &arg_data_size, NULL, 0) || arg_data_size == 0)
+ arg_data_size = 8192;
+
+ // Add a few bytes to the calculated length, I know we need to add at least one byte
+ // to this number otherwise we get junk back, so add 128 just in case...
+ DataBufferHeap arg_data(arg_data_size+128, 0);
+ arg_data_size = arg_data.GetByteSize();
+ if (::sysctl (proc_args_mib, 3, arg_data.GetBytes(), &arg_data_size , NULL, 0) == 0)
+ {
+ DataExtractor data (arg_data.GetBytes(), arg_data_size, endian::InlHostByteOrder(), sizeof(void *));
+ lldb::offset_t offset = 0;
+ uint32_t argc = data.GetU32 (&offset);
+ llvm::Triple &triple = process_info.GetArchitecture().GetTriple();
+ const llvm::Triple::ArchType triple_arch = triple.getArch();
+ const bool check_for_ios_simulator = (triple_arch == llvm::Triple::x86 || triple_arch == llvm::Triple::x86_64);
+ const char *cstr = data.GetCStr (&offset);
+ if (cstr)
+ {
+ process_info.GetExecutableFile().SetFile(cstr, false);
+
+ if (match_info_ptr == NULL ||
+ NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
+ match_info_ptr->GetNameMatchType(),
+ match_info_ptr->GetProcessInfo().GetName()))
+ {
+ // Skip NULLs
+ while (1)
+ {
+ const uint8_t *p = data.PeekData(offset, 1);
+ if ((p == NULL) || (*p != '\0'))
+ break;
+ ++offset;
+ }
+ // Now extract all arguments
+ Args &proc_args = process_info.GetArguments();
+ for (int i=0; i<static_cast<int>(argc); ++i)
+ {
+ cstr = data.GetCStr(&offset);
+ if (cstr)
+ proc_args.AppendArgument(cstr);
+ }
+
+ Args &proc_env = process_info.GetEnvironmentEntries ();
+ while ((cstr = data.GetCStr(&offset)))
+ {
+ if (cstr[0] == '\0')
+ break;
+
+ if (check_for_ios_simulator)
+ {
+ if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) == 0)
+ process_info.GetArchitecture().GetTriple().setOS(llvm::Triple::IOS);
+ else
+ process_info.GetArchitecture().GetTriple().setOS(llvm::Triple::MacOSX);
+ }
+
+ proc_env.AppendArgument(cstr);
+ }
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool
+GetMacOSXProcessUserAndGroup (ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid())
+ {
+ int mib[4];
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = process_info.GetProcessID();
+ struct kinfo_proc proc_kinfo;
+ size_t proc_kinfo_size = sizeof(struct kinfo_proc);
+
+ if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
+ {
+ if (proc_kinfo_size > 0)
+ {
+ process_info.SetParentProcessID (proc_kinfo.kp_eproc.e_ppid);
+ process_info.SetUserID (proc_kinfo.kp_eproc.e_pcred.p_ruid);
+ process_info.SetGroupID (proc_kinfo.kp_eproc.e_pcred.p_rgid);
+ process_info.SetEffectiveUserID (proc_kinfo.kp_eproc.e_ucred.cr_uid);
+ if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
+ process_info.SetEffectiveGroupID (proc_kinfo.kp_eproc.e_ucred.cr_groups[0]);
+ else
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+ return true;
+ }
+ }
+ }
+ process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
+ process_info.SetUserID (UINT32_MAX);
+ process_info.SetGroupID (UINT32_MAX);
+ process_info.SetEffectiveUserID (UINT32_MAX);
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+ return false;
+}
+
+
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+ std::vector<struct kinfo_proc> kinfos;
+
+ int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
+
+ size_t pid_data_size = 0;
+ if (::sysctl (mib, 4, NULL, &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ // Add a few extra in case a few more show up
+ const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
+
+ kinfos.resize (estimated_pid_count);
+ pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
+
+ if (::sysctl (mib, 4, &kinfos[0], &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
+
+ bool all_users = match_info.GetMatchAllUsers();
+ const lldb::pid_t our_pid = getpid();
+ const uid_t our_uid = getuid();
+ for (size_t i = 0; i < actual_pid_count; i++)
+ {
+ const struct kinfo_proc &kinfo = kinfos[i];
+
+ bool kinfo_user_matches = false;
+ if (all_users)
+ kinfo_user_matches = true;
+ else
+ kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;
+
+ // Special case, if lldb is being run as root we can attach to anything.
+ if (our_uid == 0)
+ kinfo_user_matches = true;
+
+ if (kinfo_user_matches == false || // Make sure the user is acceptable
+ static_cast<lldb::pid_t>(kinfo.kp_proc.p_pid) == our_pid || // Skip this process
+ kinfo.kp_proc.p_pid == 0 || // Skip kernel (kernel pid is zero)
+ kinfo.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains...
+ kinfo.kp_proc.p_flag & P_TRACED || // Being debugged?
+ kinfo.kp_proc.p_flag & P_WEXIT || // Working on exiting?
+ kinfo.kp_proc.p_flag & P_TRANSLATED) // Skip translated ppc (Rosetta)
+ continue;
+
+ ProcessInstanceInfo process_info;
+ process_info.SetProcessID (kinfo.kp_proc.p_pid);
+ process_info.SetParentProcessID (kinfo.kp_eproc.e_ppid);
+ process_info.SetUserID (kinfo.kp_eproc.e_pcred.p_ruid);
+ process_info.SetGroupID (kinfo.kp_eproc.e_pcred.p_rgid);
+ process_info.SetEffectiveUserID (kinfo.kp_eproc.e_ucred.cr_uid);
+ if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
+ process_info.SetEffectiveGroupID (kinfo.kp_eproc.e_ucred.cr_groups[0]);
+ else
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+
+ // Make sure our info matches before we go fetch the name and cpu type
+ if (match_info.Matches (process_info))
+ {
+ // Get CPU type first so we can know to look for iOS simulator is we have x86 or x86_64
+ if (GetMacOSXProcessCPUType (process_info))
+ {
+ if (GetMacOSXProcessArgs (&match_info, process_info))
+ {
+ if (match_info.Matches (process_info))
+ process_infos.Append (process_info);
+ }
+ }
+ }
+ }
+ return process_infos.GetSize();
+}
+
+bool
+Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.SetProcessID(pid);
+ bool success = false;
+
+ // Get CPU type first so we can know to look for iOS simulator is we have x86 or x86_64
+ if (GetMacOSXProcessCPUType (process_info))
+ success = true;
+
+ if (GetMacOSXProcessArgs (NULL, process_info))
+ success = true;
+
+ if (GetMacOSXProcessUserAndGroup (process_info))
+ success = true;
+
+ if (success)
+ return true;
+
+ process_info.Clear();
+ return false;
+}
+
+#if !NO_XPC_SERVICES
+static void
+PackageXPCArguments (xpc_object_t message, const char *prefix, const Args& args)
+{
+ size_t count = args.GetArgumentCount();
+ char buf[50]; // long enough for 'argXXX'
+ memset(buf, 0, 50);
+ sprintf(buf, "%sCount", prefix);
+ xpc_dictionary_set_int64(message, buf, count);
+ for (size_t i=0; i<count; i++) {
+ memset(buf, 0, 50);
+ sprintf(buf, "%s%zi", prefix, i);
+ xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i));
+ }
+}
+
+/*
+ A valid authorizationRef means that
+ - there is the LaunchUsingXPCRightName rights in the /etc/authorization
+ - we have successfully copied the rights to be send over the XPC wire
+ Once obtained, it will be valid for as long as the process lives.
+ */
+static AuthorizationRef authorizationRef = NULL;
+static Error
+getXPCAuthorization (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
+
+ if ((launch_info.GetUserID() == 0) && !authorizationRef)
+ {
+ OSStatus createStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);
+ if (createStatus != errAuthorizationSuccess)
+ {
+ error.SetError(1, eErrorTypeGeneric);
+ error.SetErrorString("Can't create authorizationRef.");
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+ return error;
+ }
+
+ OSStatus rightsStatus = AuthorizationRightGet(LaunchUsingXPCRightName, NULL);
+ if (rightsStatus != errAuthorizationSuccess)
+ {
+ // No rights in the security database, Create it with the right prompt.
+ CFStringRef prompt = CFSTR("Xcode is trying to take control of a root process.");
+ CFStringRef keys[] = { CFSTR("en") };
+ CFTypeRef values[] = { prompt };
+ CFDictionaryRef promptDict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+ CFStringRef keys1[] = { CFSTR("class"), CFSTR("group"), CFSTR("comment"), CFSTR("default-prompt"), CFSTR("shared") };
+ CFTypeRef values1[] = { CFSTR("user"), CFSTR("admin"), CFSTR(LaunchUsingXPCRightName), promptDict, kCFBooleanFalse };
+ CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ rightsStatus = AuthorizationRightSet(authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL);
+ CFRelease(promptDict);
+ CFRelease(dict);
+ }
+
+ OSStatus copyRightStatus = errAuthorizationDenied;
+ if (rightsStatus == errAuthorizationSuccess)
+ {
+ AuthorizationItem item1 = { LaunchUsingXPCRightName, 0, NULL, 0 };
+ AuthorizationItem items[] = {item1};
+ AuthorizationRights requestedRights = {1, items };
+ AuthorizationFlags authorizationFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
+ copyRightStatus = AuthorizationCopyRights(authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment, authorizationFlags, NULL);
+ }
+
+ if (copyRightStatus != errAuthorizationSuccess)
+ {
+ // Eventually when the commandline supports running as root and the user is not
+ // logged in in the current audit session, we will need the trick in gdb where
+ // we ask the user to type in the root passwd in the terminal.
+ error.SetError(2, eErrorTypeGeneric);
+ error.SetErrorStringWithFormat("Launching as root needs root authorization.");
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+
+ if (authorizationRef)
+ {
+ AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
+ authorizationRef = NULL;
+ }
+ }
+ }
+
+ return error;
+}
+#endif
+
+static Error
+LaunchProcessXPC(const char *exe_path, ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
+{
+#if !NO_XPC_SERVICES
+ Error error = getXPCAuthorization(launch_info);
+ if (error.Fail())
+ return error;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
+
+ uid_t requested_uid = launch_info.GetUserID();
+ const char *xpc_service = nil;
+ bool send_auth = false;
+ AuthorizationExternalForm extForm;
+ if (requested_uid == 0)
+ {
+ if (AuthorizationMakeExternalForm(authorizationRef, &extForm) == errAuthorizationSuccess)
+ {
+ send_auth = true;
+ }
+ else
+ {
+ error.SetError(3, eErrorTypeGeneric);
+ error.SetErrorStringWithFormat("Launching root via XPC needs to externalize authorization reference.");
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+ return error;
+ }
+ xpc_service = LaunchUsingXPCRightName;
+ }
+ else
+ {
+ error.SetError(4, eErrorTypeGeneric);
+ error.SetErrorStringWithFormat("Launching via XPC is only currently available for root.");
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+ return error;
+ }
+
+ xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);
+
+ xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
+ xpc_type_t type = xpc_get_type(event);
+
+ if (type == XPC_TYPE_ERROR) {
+ if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
+ // The service has either canceled itself, crashed, or been terminated.
+ // The XPC connection is still valid and sending a message to it will re-launch the service.
+ // If the service is state-full, this is the time to initialize the new service.
+ return;
+ } else if (event == XPC_ERROR_CONNECTION_INVALID) {
+ // The service is invalid. Either the service name supplied to xpc_connection_create() is incorrect
+ // or we (this process) have canceled the service; we can do any cleanup of application state at this point.
+ // printf("Service disconnected");
+ return;
+ } else {
+ // printf("Unexpected error from service: %s", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
+ }
+
+ } else {
+ // printf("Received unexpected event in handler");
+ }
+ });
+
+ xpc_connection_set_finalizer_f (conn, xpc_finalizer_t(xpc_release));
+ xpc_connection_resume (conn);
+ xpc_object_t message = xpc_dictionary_create (nil, nil, 0);
+
+ if (send_auth)
+ {
+ xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes, sizeof(AuthorizationExternalForm));
+ }
+
+ PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey, launch_info.GetArguments());
+ PackageXPCArguments(message, LauncherXPCServiceEnvPrefxKey, launch_info.GetEnvironmentEntries());
+
+ // Posix spawn stuff.
+ xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey, launch_info.GetArchitecture().GetMachOCPUType());
+ xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey, Host::GetPosixspawnFlags(launch_info));
+ const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
+ if (file_action && file_action->GetPath())
+ {
+ xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey, file_action->GetPath());
+ }
+ file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
+ if (file_action && file_action->GetPath())
+ {
+ xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey, file_action->GetPath());
+ }
+ file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
+ if (file_action && file_action->GetPath())
+ {
+ xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey, file_action->GetPath());
+ }
+
+ xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, message);
+ xpc_type_t returnType = xpc_get_type(reply);
+ if (returnType == XPC_TYPE_DICTIONARY)
+ {
+ pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);
+ if (pid == 0)
+ {
+ int errorType = xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);
+ int errorCode = xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);
+
+ error.SetError(errorCode, eErrorTypeGeneric);
+ error.SetErrorStringWithFormat("Problems with launching via XPC. Error type : %i, code : %i", errorType, errorCode);
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+
+ if (authorizationRef)
+ {
+ AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
+ authorizationRef = NULL;
+ }
+ }
+ }
+ else if (returnType == XPC_TYPE_ERROR)
+ {
+ error.SetError(5, eErrorTypeGeneric);
+ error.SetErrorStringWithFormat("Problems with launching via XPC. XPC error : %s", xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+ }
+
+ return error;
+#else
+ Error error;
+ return error;
+#endif
+}
+
+static bool
+ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info)
+{
+ bool result = false;
+
+#if !NO_XPC_SERVICES
+ bool launchingAsRoot = launch_info.GetUserID() == 0;
+ bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0;
+
+ if (launchingAsRoot && !currentUserIsRoot)
+ {
+ // If current user is already root, we don't need XPC's help.
+ result = true;
+ }
+#endif
+
+ return result;
+}
+
+Error
+Host::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ char exe_path[PATH_MAX];
+ PlatformSP host_platform_sp (Platform::GetHostPlatform ());
+
+ ModuleSpec exe_module_spec(launch_info.GetExecutableFile(), launch_info.GetArchitecture());
+
+ FileSpec::FileType file_type = exe_module_spec.GetFileSpec().GetFileType();
+ if (file_type != FileSpec::eFileTypeRegular)
+ {
+ lldb::ModuleSP exe_module_sp;
+ error = host_platform_sp->ResolveExecutable (exe_module_spec,
+ exe_module_sp,
+ NULL);
+
+ if (error.Fail())
+ return error;
+
+ if (exe_module_sp)
+ exe_module_spec.GetFileSpec() = exe_module_sp->GetFileSpec();
+ }
+
+ if (exe_module_spec.GetFileSpec().Exists())
+ {
+ exe_module_spec.GetFileSpec().GetPath (exe_path, sizeof(exe_path));
+ }
+ else
+ {
+ launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path);
+ return error;
+ }
+
+ if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
+ {
+#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
+ return LaunchInNewTerminalWithAppleScript (exe_path, launch_info);
+#else
+ error.SetErrorString ("launching a process in a new terminal is not supported on iOS devices");
+ return error;
+#endif
+ }
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ if (ShouldLaunchUsingXPC(launch_info))
+ {
+ error = LaunchProcessXPC(exe_path, launch_info, pid);
+ }
+ else
+ {
+ error = LaunchProcessPosixSpawn(exe_path, launch_info, pid);
+ }
+
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ // If all went well, then set the process ID into the launch info
+ launch_info.SetProcessID(pid);
+
+ // Make sure we reap any processes we spawn or we will have zombies.
+ if (!launch_info.MonitorProcess())
+ {
+ const bool monitor_signals = false;
+ Host::MonitorChildProcessCallback callback = nullptr;
+
+ if (!launch_info.GetFlags().Test(lldb::eLaunchFlagDontSetExitStatus))
+ callback = Process::SetProcessExitStatus;
+
+ StartMonitoringChildProcess (callback,
+ NULL,
+ pid,
+ monitor_signals);
+ }
+ }
+ else
+ {
+ // Invalid process ID, something didn't go well
+ if (error.Success())
+ error.SetErrorString ("process launch failed for unknown reasons");
+ }
+ return error;
+}
+
+Error
+Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
+ {
+ FileSpec expand_tool_spec;
+ if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
+ {
+ error.SetErrorString("could not get support executable directory for lldb-argdumper tool");
+ return error;
+ }
+ expand_tool_spec.AppendPathComponent("lldb-argdumper");
+ if (!expand_tool_spec.Exists())
+ {
+ error.SetErrorStringWithFormat("could not find the lldb-argdumper tool: %s", expand_tool_spec.GetPath().c_str());
+ return error;
+ }
+
+ StreamString expand_tool_spec_stream;
+ expand_tool_spec_stream.Printf("\"%s\"",expand_tool_spec.GetPath().c_str());
+
+ Args expand_command(expand_tool_spec_stream.GetData());
+ expand_command.AppendArguments (launch_info.GetArguments());
+
+ int status;
+ std::string output;
+ FileSpec cwd(launch_info.GetWorkingDirectory());
+ if (!cwd.Exists())
+ {
+ char *wd = getcwd(nullptr, 0);
+ if (wd == nullptr)
+ {
+ error.SetErrorStringWithFormat("cwd does not exist; cannot launch with shell argument expansion");
+ return error;
+ }
+ else
+ {
+ FileSpec working_dir(wd, false);
+ free(wd);
+ launch_info.SetWorkingDirectory(working_dir);
+
+ }
+ }
+ RunShellCommand(expand_command, cwd, &status, nullptr, &output, 10);
+
+ if (status != 0)
+ {
+ error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", status);
+ return error;
+ }
+
+ auto data_sp = StructuredData::ParseJSON(output);
+ if (!data_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto dict_sp = data_sp->GetAsDictionary();
+ if (!data_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
+ if (!args_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto args_array_sp = args_sp->GetAsArray();
+ if (!args_array_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ launch_info.GetArguments().Clear();
+
+ for (size_t i = 0;
+ i < args_array_sp->GetSize();
+ i++)
+ {
+ auto item_sp = args_array_sp->GetItemAtIndex(i);
+ if (!item_sp)
+ continue;
+ auto str_sp = item_sp->GetAsString();
+ if (!str_sp)
+ continue;
+
+ launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
+ }
+ }
+
+ return error;
+}
+
+HostThread
+Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
+{
+ unsigned long mask = DISPATCH_PROC_EXIT;
+ if (monitor_signals)
+ mask |= DISPATCH_PROC_SIGNAL;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
+
+
+ dispatch_source_t source = ::dispatch_source_create (DISPATCH_SOURCE_TYPE_PROC,
+ pid,
+ mask,
+ ::dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT,0));
+
+ if (log)
+ log->Printf ("Host::StartMonitoringChildProcess (callback=%p, baton=%p, pid=%i, monitor_signals=%i) source = %p\n",
+ callback,
+ callback_baton,
+ (int)pid,
+ monitor_signals,
+ source);
+
+ if (source)
+ {
+ ::dispatch_source_set_cancel_handler (source, ^{
+ ::dispatch_release (source);
+ });
+ ::dispatch_source_set_event_handler (source, ^{
+
+ int status= 0;
+ int wait_pid = 0;
+ bool cancel = false;
+ bool exited = false;
+ do
+ {
+ wait_pid = ::waitpid (pid, &status, 0);
+ } while (wait_pid < 0 && errno == EINTR);
+
+ if (wait_pid >= 0)
+ {
+ int signal = 0;
+ int exit_status = 0;
+ const char *status_cstr = NULL;
+ 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";
+ exited = true;
+ exit_status = -1;
+ }
+ else
+ {
+ status_cstr = "???";
+ }
+
+ if (log)
+ log->Printf ("::waitpid (pid = %llu, &status, 0) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_status = %i",
+ pid,
+ wait_pid,
+ status,
+ status_cstr,
+ signal,
+ exit_status);
+
+ if (callback)
+ cancel = callback (callback_baton, pid, exited, signal, exit_status);
+
+ if (exited || cancel)
+ {
+ ::dispatch_source_cancel(source);
+ }
+ }
+ });
+
+ ::dispatch_resume (source);
+ }
+ return HostThread();
+}
+
+//----------------------------------------------------------------------
+// Log to both stderr and to ASL Logging when running on MacOSX.
+//----------------------------------------------------------------------
+void
+Host::SystemLog (SystemLogType type, const char *format, va_list args)
+{
+ if (format && format[0])
+ {
+ static aslmsg g_aslmsg = NULL;
+ if (g_aslmsg == NULL)
+ {
+ g_aslmsg = ::asl_new (ASL_TYPE_MSG);
+ char asl_key_sender[PATH_MAX];
+ snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.LLDB.framework");
+ ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
+ }
+
+ // Copy the va_list so we can log this message twice
+ va_list copy_args;
+ va_copy (copy_args, args);
+ // Log to stderr
+ ::vfprintf (stderr, format, copy_args);
+ va_end (copy_args);
+
+ int asl_level;
+ switch (type)
+ {
+ case eSystemLogError:
+ asl_level = ASL_LEVEL_ERR;
+ break;
+
+ case eSystemLogWarning:
+ asl_level = ASL_LEVEL_WARNING;
+ break;
+ }
+
+ // Log to ASL
+ ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
+ }
+}
+
+lldb::DataBufferSP
+Host::GetAuxvData(lldb_private::Process *process)
+{
+ return lldb::DataBufferSP();
+}
diff --git a/source/Host/macosx/HostInfoMacOSX.mm b/source/Host/macosx/HostInfoMacOSX.mm
new file mode 100644
index 000000000000..f5a0540e8774
--- /dev/null
+++ b/source/Host/macosx/HostInfoMacOSX.mm
@@ -0,0 +1,372 @@
+//===-- HostInfoMacOSX.mm ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if !defined(LLDB_DISABLE_PYTHON)
+#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
+#endif
+
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/macosx/HostInfoMacOSX.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/SafeMachO.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+// C++ Includes
+#include <string>
+
+// C inclues
+#include <stdlib.h>
+#include <sys/sysctl.h>
+#include <sys/syslimits.h>
+#include <sys/types.h>
+
+// Objective C/C++ includes
+#include <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
+#include <mach-o/dyld.h>
+#include <objc/objc-auto.h>
+
+// These are needed when compiling on systems
+// that do not yet have these definitions
+#include <AvailabilityMacros.h>
+#ifndef CPU_SUBTYPE_X86_64_H
+#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8)
+#endif
+#ifndef CPU_TYPE_ARM64
+#define CPU_TYPE_ARM64 (CPU_TYPE_ARM|CPU_ARCH_ABI64)
+#endif
+
+#include <TargetConditionals.h> // for TARGET_OS_TV, TARGET_OS_WATCH
+
+using namespace lldb_private;
+
+bool
+HostInfoMacOSX::GetOSBuildString(std::string &s)
+{
+ int mib[2] = {CTL_KERN, KERN_OSVERSION};
+ char cstr[PATH_MAX];
+ size_t cstr_len = sizeof(cstr);
+ if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0)
+ {
+ s.assign(cstr, cstr_len);
+ return true;
+ }
+
+ s.clear();
+ return false;
+}
+
+bool
+HostInfoMacOSX::GetOSKernelDescription(std::string &s)
+{
+ int mib[2] = {CTL_KERN, KERN_VERSION};
+ char cstr[PATH_MAX];
+ size_t cstr_len = sizeof(cstr);
+ if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0)
+ {
+ s.assign(cstr, cstr_len);
+ return true;
+ }
+ s.clear();
+ return false;
+}
+
+bool
+HostInfoMacOSX::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update)
+{
+ static uint32_t g_major = 0;
+ static uint32_t g_minor = 0;
+ static uint32_t g_update = 0;
+
+ if (g_major == 0)
+ {
+ @autoreleasepool
+ {
+ NSDictionary *version_info = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
+ NSString *version_value = [version_info objectForKey:@"ProductVersion"];
+ const char *version_str = [version_value UTF8String];
+ if (version_str)
+ Args::StringToVersion(version_str, g_major, g_minor, g_update);
+ }
+ }
+
+ if (g_major != 0)
+ {
+ major = g_major;
+ minor = g_minor;
+ update = g_update;
+ return true;
+ }
+ return false;
+}
+
+FileSpec
+HostInfoMacOSX::GetProgramFileSpec()
+{
+ static FileSpec g_program_filespec;
+ if (!g_program_filespec)
+ {
+ char program_fullpath[PATH_MAX];
+ // If DST is NULL, then return the number of bytes needed.
+ uint32_t len = sizeof(program_fullpath);
+ int err = _NSGetExecutablePath(program_fullpath, &len);
+ if (err == 0)
+ g_program_filespec.SetFile(program_fullpath, false);
+ else if (err == -1)
+ {
+ char *large_program_fullpath = (char *)::malloc(len + 1);
+
+ err = _NSGetExecutablePath(large_program_fullpath, &len);
+ if (err == 0)
+ g_program_filespec.SetFile(large_program_fullpath, false);
+
+ ::free(large_program_fullpath);
+ }
+ }
+ return g_program_filespec;
+}
+
+bool
+HostInfoMacOSX::ComputeSupportExeDirectory(FileSpec &file_spec)
+{
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ std::string raw_path = lldb_file_spec.GetPath();
+
+ size_t framework_pos = raw_path.find("LLDB.framework");
+ if (framework_pos != std::string::npos)
+ {
+ framework_pos += strlen("LLDB.framework");
+#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ // Shallow bundle
+ raw_path.resize(framework_pos);
+#else
+ // Normal bundle
+ raw_path.resize(framework_pos);
+ raw_path.append("/Resources");
+#endif
+ }
+ else
+ {
+ // Find the bin path relative to the lib path where the cmake-based
+ // OS X .dylib lives. This is not going to work if the bin and lib
+ // dir are not both in the same dir.
+ //
+ // It is not going to work to do it by the executable path either,
+ // as in the case of a python script, the executable is python, not
+ // the lldb driver.
+ raw_path.append("/../bin");
+ FileSpec support_dir_spec(raw_path, true);
+ if (!support_dir_spec.Exists() || !support_dir_spec.IsDirectory())
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoMacOSX::%s(): failed to find support directory",
+ __FUNCTION__);
+ return false;
+ }
+
+ // Get normalization from support_dir_spec. Note the FileSpec resolve
+ // does not remove '..' in the path.
+ char *const dir_realpath = realpath(support_dir_spec.GetPath().c_str(), NULL);
+ if (dir_realpath)
+ {
+ raw_path = dir_realpath;
+ free(dir_realpath);
+ }
+ else
+ {
+ raw_path = support_dir_spec.GetPath();
+ }
+ }
+
+ file_spec.GetDirectory().SetString(llvm::StringRef(raw_path.c_str(), raw_path.size()));
+ return (bool)file_spec.GetDirectory();
+}
+
+bool
+HostInfoMacOSX::ComputeHeaderDirectory(FileSpec &file_spec)
+{
+ FileSpec lldb_file_spec;
+ if (!HostInfo::GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ std::string raw_path = lldb_file_spec.GetPath();
+
+ size_t framework_pos = raw_path.find("LLDB.framework");
+ if (framework_pos != std::string::npos)
+ {
+ framework_pos += strlen("LLDB.framework");
+ raw_path.resize(framework_pos);
+ raw_path.append("/Headers");
+ }
+ file_spec.GetDirectory().SetString(llvm::StringRef(raw_path.c_str(), raw_path.size()));
+ return true;
+}
+
+bool
+HostInfoMacOSX::ComputePythonDirectory(FileSpec &file_spec)
+{
+#ifndef LLDB_DISABLE_PYTHON
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ std::string raw_path = lldb_file_spec.GetPath();
+
+ size_t framework_pos = raw_path.find("LLDB.framework");
+ if (framework_pos != std::string::npos)
+ {
+ framework_pos += strlen("LLDB.framework");
+ raw_path.resize(framework_pos);
+ raw_path.append("/Resources/Python");
+ }
+ else
+ {
+ llvm::SmallString<256> python_version_dir;
+ llvm::raw_svector_ostream os(python_version_dir);
+ os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages";
+
+ // We may get our string truncated. Should we protect this with an assert?
+ raw_path.append(python_version_dir.c_str());
+ }
+ file_spec.GetDirectory().SetString(llvm::StringRef(raw_path.c_str(), raw_path.size()));
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool
+HostInfoMacOSX::ComputeClangDirectory(FileSpec &file_spec)
+{
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath (lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ std::string raw_path = lldb_file_spec.GetPath();
+
+ size_t framework_pos = raw_path.find("LLDB.framework");
+ if (framework_pos != std::string::npos)
+ {
+ framework_pos += strlen("LLDB.framework");
+ raw_path.resize(framework_pos);
+ raw_path.append("/Resources/Clang");
+ }
+ file_spec.SetFile (raw_path.c_str(), true);
+ return true;
+}
+
+bool
+HostInfoMacOSX::ComputeSystemPluginsDirectory(FileSpec &file_spec)
+{
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ std::string raw_path = lldb_file_spec.GetPath();
+
+ size_t framework_pos = raw_path.find("LLDB.framework");
+ if (framework_pos == std::string::npos)
+ return false;
+
+ framework_pos += strlen("LLDB.framework");
+ raw_path.resize(framework_pos);
+ raw_path.append("/Resources/PlugIns");
+ file_spec.GetDirectory().SetString(llvm::StringRef(raw_path.c_str(), raw_path.size()));
+ return true;
+}
+
+bool
+HostInfoMacOSX::ComputeUserPluginsDirectory(FileSpec &file_spec)
+{
+ FileSpec temp_file("~/Library/Application Support/LLDB/PlugIns", true);
+ file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str());
+ return true;
+}
+
+void
+HostInfoMacOSX::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
+{
+ // All apple systems support 32 bit execution.
+ uint32_t cputype, cpusubtype;
+ uint32_t is_64_bit_capable = false;
+ size_t len = sizeof(cputype);
+ ArchSpec host_arch;
+ // These will tell us about the kernel architecture, which even on a 64
+ // bit machine can be 32 bit...
+ if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0)
+ {
+ len = sizeof(cpusubtype);
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) != 0)
+ cpusubtype = CPU_TYPE_ANY;
+
+ len = sizeof(is_64_bit_capable);
+ ::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0);
+
+ if (is_64_bit_capable)
+ {
+ if (cputype & CPU_ARCH_ABI64)
+ {
+ // We have a 64 bit kernel on a 64 bit system
+ arch_64.SetArchitecture(eArchTypeMachO, cputype, cpusubtype);
+ }
+ else
+ {
+ // We have a 64 bit kernel that is returning a 32 bit cputype, the
+ // cpusubtype will be correct as if it were for a 64 bit architecture
+ arch_64.SetArchitecture(eArchTypeMachO, cputype | CPU_ARCH_ABI64, cpusubtype);
+ }
+
+ // Now we need modify the cpusubtype for the 32 bit slices.
+ uint32_t cpusubtype32 = cpusubtype;
+#if defined(__i386__) || defined(__x86_64__)
+ if (cpusubtype == CPU_SUBTYPE_486 || cpusubtype == CPU_SUBTYPE_X86_64_H)
+ cpusubtype32 = CPU_SUBTYPE_I386_ALL;
+#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64)
+ cpusubtype32 = CPU_SUBTYPE_ARM_V7S;
+#endif
+ arch_32.SetArchitecture(eArchTypeMachO, cputype & ~(CPU_ARCH_MASK), cpusubtype32);
+
+ if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64)
+ {
+ // When running on a watch or tv, report the host os correctly
+#if defined (TARGET_OS_TV) && TARGET_OS_TV == 1
+ arch_32.GetTriple().setOS(llvm::Triple::TvOS);
+ arch_64.GetTriple().setOS(llvm::Triple::TvOS);
+#else
+ arch_32.GetTriple().setOS(llvm::Triple::IOS);
+ arch_64.GetTriple().setOS(llvm::Triple::IOS);
+#endif
+ }
+ else
+ {
+ arch_32.GetTriple().setOS(llvm::Triple::MacOSX);
+ arch_64.GetTriple().setOS(llvm::Triple::MacOSX);
+ }
+ }
+ else
+ {
+ // We have a 32 bit kernel on a 32 bit system
+ arch_32.SetArchitecture(eArchTypeMachO, cputype, cpusubtype);
+#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
+ arch_32.GetTriple().setOS(llvm::Triple::WatchOS);
+#else
+ arch_32.GetTriple().setOS(llvm::Triple::IOS);
+#endif
+ arch_64.Clear();
+ }
+ }
+}
diff --git a/source/Host/macosx/HostThreadMacOSX.mm b/source/Host/macosx/HostThreadMacOSX.mm
new file mode 100644
index 000000000000..c84a78efd9e6
--- /dev/null
+++ b/source/Host/macosx/HostThreadMacOSX.mm
@@ -0,0 +1,102 @@
+//===-- HostThreadMacOSX.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/macosx/HostThreadMacOSX.h"
+#include "lldb/Host/Host.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
+
+#include <objc/objc-auto.h>
+#include <pthread.h>
+
+using namespace lldb_private;
+
+namespace
+{
+
+pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
+pthread_key_t g_thread_create_key = 0;
+
+class MacOSXDarwinThread
+{
+ public:
+ MacOSXDarwinThread()
+ : m_pool(nil)
+ {
+ // Register our thread with the collector if garbage collection is enabled.
+ if (objc_collectingEnabled())
+ {
+#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
+ // On Leopard and earlier there is no way objc_registerThreadWithCollector
+ // function, so we do it manually.
+ auto_zone_register_thread(auto_zone());
+#else
+ // On SnowLeopard and later we just call the thread registration function.
+ objc_registerThreadWithCollector();
+#endif
+ }
+ else
+ {
+ m_pool = [[NSAutoreleasePool alloc] init];
+ }
+ }
+
+ ~MacOSXDarwinThread()
+ {
+ if (m_pool)
+ {
+ [m_pool drain];
+ m_pool = nil;
+ }
+ }
+
+ static void
+ PThreadDestructor(void *v)
+ {
+ if (v)
+ delete static_cast<MacOSXDarwinThread *>(v);
+ ::pthread_setspecific(g_thread_create_key, NULL);
+ }
+
+ protected:
+ NSAutoreleasePool *m_pool;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MacOSXDarwinThread);
+};
+
+void
+InitThreadCreated()
+{
+ ::pthread_key_create(&g_thread_create_key, MacOSXDarwinThread::PThreadDestructor);
+}
+} // namespace
+
+HostThreadMacOSX::HostThreadMacOSX()
+ : HostThreadPosix()
+{
+}
+
+HostThreadMacOSX::HostThreadMacOSX(lldb::thread_t thread)
+ : HostThreadPosix(thread)
+{
+}
+
+lldb::thread_result_t
+HostThreadMacOSX::ThreadCreateTrampoline(lldb::thread_arg_t arg)
+{
+ ::pthread_once(&g_thread_create_once, InitThreadCreated);
+ if (g_thread_create_key)
+ {
+ ::pthread_setspecific(g_thread_create_key, new MacOSXDarwinThread());
+ }
+
+ return HostThreadPosix::ThreadCreateTrampoline(arg);
+}
diff --git a/source/Host/macosx/Symbols.cpp b/source/Host/macosx/Symbols.cpp
new file mode 100644
index 000000000000..f6a18febe6da
--- /dev/null
+++ b/source/Host/macosx/Symbols.cpp
@@ -0,0 +1,559 @@
+//===-- Symbols.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/Symbols.h"
+
+// C Includes
+#include <dirent.h>
+#include <pwd.h>
+#include "lldb/Utility/SafeMachO.h"
+
+// C++ Includes
+// Other libraries and framework includes
+#include <CoreFoundation/CoreFoundation.h>
+
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/CleanUp.h"
+#include "Host/macosx/cfcpp/CFCBundle.h"
+#include "Host/macosx/cfcpp/CFCData.h"
+#include "Host/macosx/cfcpp/CFCReleaser.h"
+#include "Host/macosx/cfcpp/CFCString.h"
+#include "mach/machine.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm::MachO;
+
+#if !defined (__arm__) && !defined (__arm64__) && !defined (__aarch64__) // No DebugSymbols on the iOS devices
+extern "C" {
+
+CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url);
+CFDictionaryRef DBGCopyDSYMPropertyLists (CFURLRef dsym_url);
+
+}
+#endif
+
+int
+LocateMacOSXFilesUsingDebugSymbols
+(
+ const ModuleSpec &module_spec,
+ ModuleSpec &return_module_spec
+)
+{
+ return_module_spec = module_spec;
+ return_module_spec.GetFileSpec().Clear();
+ return_module_spec.GetSymbolFileSpec().Clear();
+
+ int items_found = 0;
+
+#if !defined (__arm__) && !defined (__arm64__) && !defined (__aarch64__) // No DebugSymbols on the iOS devices
+
+ const UUID *uuid = module_spec.GetUUIDPtr();
+ const ArchSpec *arch = module_spec.GetArchitecturePtr();
+
+ if (uuid && uuid->IsValid())
+ {
+ // Try and locate the dSYM file using DebugSymbols first
+ const UInt8 *module_uuid = (const UInt8 *)uuid->GetBytes();
+ if (module_uuid != NULL)
+ {
+ CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes (NULL,
+ module_uuid[0],
+ module_uuid[1],
+ module_uuid[2],
+ module_uuid[3],
+ module_uuid[4],
+ module_uuid[5],
+ module_uuid[6],
+ module_uuid[7],
+ module_uuid[8],
+ module_uuid[9],
+ module_uuid[10],
+ module_uuid[11],
+ module_uuid[12],
+ module_uuid[13],
+ module_uuid[14],
+ module_uuid[15]));
+
+ if (module_uuid_ref.get())
+ {
+ CFCReleaser<CFURLRef> exec_url;
+ const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (exec_fspec)
+ {
+ char exec_cf_path[PATH_MAX];
+ if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
+ exec_url.reset(::CFURLCreateFromFileSystemRepresentation (NULL,
+ (const UInt8 *)exec_cf_path,
+ strlen(exec_cf_path),
+ FALSE));
+ }
+
+ CFCReleaser<CFURLRef> dsym_url (::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
+ char path[PATH_MAX];
+
+ if (dsym_url.get())
+ {
+ if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
+ {
+ if (log)
+ {
+ log->Printf ("DebugSymbols framework returned dSYM path of %s for UUID %s -- looking for the dSYM", path, uuid->GetAsString().c_str());
+ }
+ FileSpec dsym_filespec(path, path[0] == '~');
+
+ if (dsym_filespec.GetFileType () == FileSpec::eFileTypeDirectory)
+ {
+ dsym_filespec = Symbols::FindSymbolFileInBundle (dsym_filespec, uuid, arch);
+ ++items_found;
+ }
+ else
+ {
+ ++items_found;
+ }
+ return_module_spec.GetSymbolFileSpec() = dsym_filespec;
+ }
+
+ bool success = false;
+ if (log)
+ {
+ if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
+ {
+ log->Printf ("DebugSymbols framework returned dSYM path of %s for UUID %s -- looking for an exec file", path, uuid->GetAsString().c_str());
+ }
+
+ }
+
+ CFCReleaser<CFDictionaryRef> dict(::DBGCopyDSYMPropertyLists (dsym_url.get()));
+ CFDictionaryRef uuid_dict = NULL;
+ if (dict.get())
+ {
+ CFCString uuid_cfstr (uuid->GetAsString().c_str());
+ uuid_dict = static_cast<CFDictionaryRef>(::CFDictionaryGetValue (dict.get(), uuid_cfstr.get()));
+ }
+ if (uuid_dict)
+ {
+ CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSymbolRichExecutable")));
+ if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path)))
+ {
+ if (log)
+ {
+ log->Printf ("plist bundle has exec path of %s for UUID %s", path, uuid->GetAsString().c_str());
+ }
+ ++items_found;
+ FileSpec exec_filespec (path, path[0] == '~');
+ if (exec_filespec.Exists())
+ {
+ success = true;
+ return_module_spec.GetFileSpec() = exec_filespec;
+ }
+ }
+ }
+
+ if (!success)
+ {
+ // No dictionary, check near the dSYM bundle for an executable that matches...
+ if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
+ {
+ char *dsym_extension_pos = ::strstr (path, ".dSYM");
+ if (dsym_extension_pos)
+ {
+ *dsym_extension_pos = '\0';
+ if (log)
+ {
+ log->Printf ("Looking for executable binary next to dSYM bundle with name with name %s", path);
+ }
+ FileSpec file_spec (path, true);
+ ModuleSpecList module_specs;
+ ModuleSpec matched_module_spec;
+ switch (file_spec.GetFileType())
+ {
+ case FileSpec::eFileTypeDirectory: // Bundle directory?
+ {
+ CFCBundle bundle (path);
+ CFCReleaser<CFURLRef> bundle_exe_url (bundle.CopyExecutableURL ());
+ if (bundle_exe_url.get())
+ {
+ if (::CFURLGetFileSystemRepresentation (bundle_exe_url.get(), true, (UInt8*)path, sizeof(path)-1))
+ {
+ FileSpec bundle_exe_file_spec (path, true);
+ if (ObjectFile::GetModuleSpecifications(bundle_exe_file_spec, 0, 0, module_specs) &&
+ module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
+
+ {
+ ++items_found;
+ return_module_spec.GetFileSpec() = bundle_exe_file_spec;
+ if (log)
+ {
+ log->Printf ("Executable binary %s next to dSYM is compatible; using", path);
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case FileSpec::eFileTypePipe: // Forget pipes
+ case FileSpec::eFileTypeSocket: // We can't process socket files
+ case FileSpec::eFileTypeInvalid: // File doesn't exist...
+ break;
+
+ case FileSpec::eFileTypeUnknown:
+ case FileSpec::eFileTypeRegular:
+ case FileSpec::eFileTypeSymbolicLink:
+ case FileSpec::eFileTypeOther:
+ if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0, module_specs) &&
+ module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
+
+ {
+ ++items_found;
+ return_module_spec.GetFileSpec() = file_spec;
+ if (log)
+ {
+ log->Printf ("Executable binary %s next to dSYM is compatible; using", path);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+#endif // #if !defined (__arm__) && !defined (__arm64__) && !defined (__aarch64__)
+
+ return items_found;
+}
+
+FileSpec
+Symbols::FindSymbolFileInBundle (const FileSpec& dsym_bundle_fspec,
+ const lldb_private::UUID *uuid,
+ const ArchSpec *arch)
+{
+ char path[PATH_MAX];
+
+ FileSpec dsym_fspec;
+
+ if (dsym_bundle_fspec.GetPath(path, sizeof(path)))
+ {
+ ::strncat (path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
+
+ lldb_utility::CleanUp <DIR *, int> dirp (opendir(path), NULL, closedir);
+ if (dirp.is_valid())
+ {
+ dsym_fspec.GetDirectory().SetCString(path);
+ struct dirent* dp;
+ while ((dp = readdir(dirp.get())) != NULL)
+ {
+ // Only search directories
+ if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
+ {
+ if (dp->d_namlen == 1 && dp->d_name[0] == '.')
+ continue;
+
+ if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
+ continue;
+ }
+
+ if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN)
+ {
+ dsym_fspec.GetFilename().SetCString(dp->d_name);
+ ModuleSpecList module_specs;
+ if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs))
+ {
+ ModuleSpec spec;
+ for (size_t i = 0; i < module_specs.GetSize(); ++i)
+ {
+ assert(module_specs.GetModuleSpecAtIndex(i, spec));
+ if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
+ (arch == NULL || (spec.GetArchitecturePtr() && spec.GetArchitecture().IsCompatibleMatch(*arch))))
+ {
+ return dsym_fspec;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ dsym_fspec.Clear();
+ return dsym_fspec;
+}
+
+static bool
+GetModuleSpecInfoFromUUIDDictionary (CFDictionaryRef uuid_dict, ModuleSpec &module_spec)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ bool success = false;
+ if (uuid_dict != NULL && CFGetTypeID (uuid_dict) == CFDictionaryGetTypeID ())
+ {
+ std::string str;
+ CFStringRef cf_str;
+
+ cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSymbolRichExecutable"));
+ if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
+ {
+ if (CFCString::FileSystemRepresentation(cf_str, str))
+ {
+ module_spec.GetFileSpec().SetFile (str.c_str(), true);
+ if (log)
+ {
+ log->Printf ("From dsymForUUID plist: Symbol rich executable is at '%s'", str.c_str());
+ }
+ }
+ }
+
+ cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGDSYMPath"));
+ if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
+ {
+ if (CFCString::FileSystemRepresentation(cf_str, str))
+ {
+ module_spec.GetSymbolFileSpec().SetFile (str.c_str(), true);
+ success = true;
+ if (log)
+ {
+ log->Printf ("From dsymForUUID plist: dSYM is at '%s'", str.c_str());
+ }
+ }
+ }
+
+ cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGArchitecture"));
+ if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
+ {
+ if (CFCString::FileSystemRepresentation(cf_str, str))
+ module_spec.GetArchitecture().SetTriple(str.c_str());
+ }
+
+ std::string DBGBuildSourcePath;
+ std::string DBGSourcePath;
+
+ cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGBuildSourcePath"));
+ if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
+ {
+ CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
+ }
+
+ cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSourcePath"));
+ if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
+ {
+ CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
+ }
+
+ if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty())
+ {
+ module_spec.GetSourceMappingList().Append (ConstString(DBGBuildSourcePath.c_str()), ConstString(DBGSourcePath.c_str()), true);
+ }
+ }
+ return success;
+}
+
+
+bool
+Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
+{
+ bool success = false;
+ const UUID *uuid_ptr = module_spec.GetUUIDPtr();
+ const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
+
+ // It's expensive to check for the DBGShellCommands defaults setting, only do it once per
+ // lldb run and cache the result.
+ static bool g_have_checked_for_dbgshell_command = false;
+ static const char *g_dbgshell_command = NULL;
+ if (g_have_checked_for_dbgshell_command == false)
+ {
+ g_have_checked_for_dbgshell_command = true;
+ CFTypeRef defaults_setting = CFPreferencesCopyAppValue (CFSTR ("DBGShellCommands"), CFSTR ("com.apple.DebugSymbols"));
+ if (defaults_setting && CFGetTypeID (defaults_setting) == CFStringGetTypeID())
+ {
+ char cstr_buf[PATH_MAX];
+ if (CFStringGetCString ((CFStringRef) defaults_setting, cstr_buf, sizeof (cstr_buf), kCFStringEncodingUTF8))
+ {
+ g_dbgshell_command = strdup (cstr_buf); // this malloc'ed memory will never be freed
+ }
+ }
+ if (defaults_setting)
+ {
+ CFRelease (defaults_setting);
+ }
+ }
+
+ // When g_dbgshell_command is NULL, the user has not enabled the use of an external program
+ // to find the symbols, don't run it for them.
+ if (force_lookup == false && g_dbgshell_command == NULL)
+ {
+ return false;
+ }
+
+ if (uuid_ptr || (file_spec_ptr && file_spec_ptr->Exists()))
+ {
+ static bool g_located_dsym_for_uuid_exe = false;
+ static bool g_dsym_for_uuid_exe_exists = false;
+ static char g_dsym_for_uuid_exe_path[PATH_MAX];
+ if (!g_located_dsym_for_uuid_exe)
+ {
+ g_located_dsym_for_uuid_exe = true;
+ const char *dsym_for_uuid_exe_path_cstr = getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
+ FileSpec dsym_for_uuid_exe_spec;
+ if (dsym_for_uuid_exe_path_cstr)
+ {
+ dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true);
+ g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
+ }
+
+ if (!g_dsym_for_uuid_exe_exists)
+ {
+ dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false);
+ g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
+ if (!g_dsym_for_uuid_exe_exists)
+ {
+ long bufsize;
+ if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1)
+ {
+ char buffer[bufsize];
+ struct passwd pwd;
+ struct passwd *tilde_rc = NULL;
+ // we are a library so we need to use the reentrant version of getpwnam()
+ if (getpwnam_r ("rc", &pwd, buffer, bufsize, &tilde_rc) == 0
+ && tilde_rc
+ && tilde_rc->pw_dir)
+ {
+ std::string dsymforuuid_path(tilde_rc->pw_dir);
+ dsymforuuid_path += "/bin/dsymForUUID";
+ dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), false);
+ g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
+ }
+ }
+ }
+ }
+ if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL)
+ {
+ dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, true);
+ g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
+ }
+
+ if (g_dsym_for_uuid_exe_exists)
+ dsym_for_uuid_exe_spec.GetPath (g_dsym_for_uuid_exe_path, sizeof(g_dsym_for_uuid_exe_path));
+ }
+ if (g_dsym_for_uuid_exe_exists)
+ {
+ std::string uuid_str;
+ char file_path[PATH_MAX];
+ file_path[0] = '\0';
+
+ if (uuid_ptr)
+ uuid_str = uuid_ptr->GetAsString();
+
+ if (file_spec_ptr)
+ file_spec_ptr->GetPath(file_path, sizeof(file_path));
+
+ StreamString command;
+ if (!uuid_str.empty())
+ command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, uuid_str.c_str());
+ else if (file_path[0] != '\0')
+ command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, file_path);
+
+ if (!command.GetString().empty())
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ int exit_status = -1;
+ int signo = -1;
+ std::string command_output;
+ if (log)
+ {
+ if (!uuid_str.empty())
+ log->Printf("Calling %s with UUID %s to find dSYM", g_dsym_for_uuid_exe_path, uuid_str.c_str());
+ else if (file_path[0] != '\0')
+ log->Printf("Calling %s with file %s to find dSYM", g_dsym_for_uuid_exe_path, file_path);
+ }
+ Error error = Host::RunShellCommand (command.GetData(),
+ NULL, // current working directory
+ &exit_status, // Exit status
+ &signo, // Signal int *
+ &command_output, // Command output
+ 30, // Large timeout to allow for long dsym download times
+ false); // Don't run in a shell (we don't need shell expansion)
+ if (error.Success() && exit_status == 0 && !command_output.empty())
+ {
+ CFCData data (CFDataCreateWithBytesNoCopy (NULL,
+ (const UInt8 *)command_output.data(),
+ command_output.size(),
+ kCFAllocatorNull));
+
+ CFCReleaser<CFDictionaryRef> plist((CFDictionaryRef)::CFPropertyListCreateFromXMLData (NULL, data.get(), kCFPropertyListImmutable, NULL));
+
+ if (plist.get() && CFGetTypeID (plist.get()) == CFDictionaryGetTypeID ())
+ {
+ if (!uuid_str.empty())
+ {
+ CFCString uuid_cfstr(uuid_str.c_str());
+ CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue (plist.get(), uuid_cfstr.get());
+ success = GetModuleSpecInfoFromUUIDDictionary (uuid_dict, module_spec);
+ }
+ else
+ {
+ const CFIndex num_values = ::CFDictionaryGetCount(plist.get());
+ if (num_values > 0)
+ {
+ std::vector<CFStringRef> keys (num_values, NULL);
+ std::vector<CFDictionaryRef> values (num_values, NULL);
+ ::CFDictionaryGetKeysAndValues(plist.get(), NULL, (const void **)&values[0]);
+ if (num_values == 1)
+ {
+ return GetModuleSpecInfoFromUUIDDictionary (values[0], module_spec);
+ }
+ else
+ {
+ for (CFIndex i=0; i<num_values; ++i)
+ {
+ ModuleSpec curr_module_spec;
+ if (GetModuleSpecInfoFromUUIDDictionary (values[i], curr_module_spec))
+ {
+ if (module_spec.GetArchitecture().IsCompatibleMatch(curr_module_spec.GetArchitecture()))
+ {
+ module_spec = curr_module_spec;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ {
+ if (!uuid_str.empty())
+ log->Printf("Called %s on %s, no matches", g_dsym_for_uuid_exe_path, uuid_str.c_str());
+ else if (file_path[0] != '\0')
+ log->Printf("Called %s on %s, no matches", g_dsym_for_uuid_exe_path, file_path);
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
diff --git a/source/Host/macosx/ThisThread.cpp b/source/Host/macosx/ThisThread.cpp
new file mode 100644
index 000000000000..95c7f2bf1e38
--- /dev/null
+++ b/source/Host/macosx/ThisThread.cpp
@@ -0,0 +1,39 @@
+//===-- ThisThread.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/ThisThread.h"
+
+#include <pthread.h>
+
+using namespace lldb_private;
+
+void
+ThisThread::SetName(llvm::StringRef name)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
+ ::pthread_setname_np(name);
+#endif
+}
+
+void
+ThisThread::GetName(llvm::SmallVectorImpl<char> &name)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
+ char pthread_name[1024];
+ dispatch_queue_t current_queue = ::dispatch_get_current_queue();
+ if (current_queue != NULL)
+ {
+ const char *queue_name = dispatch_queue_get_label(current_queue);
+ if (queue_name && queue_name[0])
+ {
+ name = queue_name;
+ }
+ }
+#endif
+}
diff --git a/source/Host/macosx/cfcpp/CFCBundle.cpp b/source/Host/macosx/cfcpp/CFCBundle.cpp
new file mode 100644
index 000000000000..71b074993661
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCBundle.cpp
@@ -0,0 +1,99 @@
+//===-- CFCBundle.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCBundle.h"
+#include "CFCString.h"
+
+//----------------------------------------------------------------------
+// CFCBundle constructor
+//----------------------------------------------------------------------
+CFCBundle::CFCBundle(const char *path) :
+ CFCReleaser<CFBundleRef>()
+{
+ if (path && path[0])
+ SetPath(path);
+}
+
+CFCBundle::CFCBundle(CFURLRef url) :
+ CFCReleaser<CFBundleRef>(url ? CFBundleCreate(NULL, url) : NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCBundle::~CFCBundle()
+{
+}
+
+//----------------------------------------------------------------------
+// Set the path for a bundle by supplying a
+//----------------------------------------------------------------------
+bool
+CFCBundle::SetPath (const char *path)
+{
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ // Release our old bundle and URL
+ reset();
+
+ // Make a CFStringRef from the supplied path
+ CFCString cf_path;
+ cf_path.SetFileSystemRepresentation(path);
+ if (cf_path.get())
+ {
+ // Make our Bundle URL
+ CFCReleaser<CFURLRef> bundle_url (::CFURLCreateWithFileSystemPath (alloc, cf_path.get(), kCFURLPOSIXPathStyle, true));
+ if (bundle_url.get())
+ reset (::CFBundleCreate (alloc, bundle_url.get()));
+ }
+ return get() != NULL;
+}
+
+bool
+CFCBundle::GetPath (char *dst, size_t dst_len)
+{
+ CFBundleRef bundle = get();
+ if (bundle)
+ {
+ CFCReleaser<CFURLRef> bundle_url (CFBundleCopyBundleURL (bundle));
+ if (bundle_url.get())
+ {
+ Boolean resolveAgainstBase = 0;
+ return ::CFURLGetFileSystemRepresentation (bundle_url.get(), resolveAgainstBase, (UInt8 *)dst, dst_len) != 0;
+ }
+ }
+ return false;
+}
+
+CFStringRef
+CFCBundle::GetIdentifier () const
+{
+ CFBundleRef bundle = get();
+ if (bundle != NULL)
+ return ::CFBundleGetIdentifier (bundle);
+ return NULL;
+}
+
+CFTypeRef
+CFCBundle::GetValueForInfoDictionaryKey(CFStringRef key) const
+{
+ CFBundleRef bundle = get();
+ if (bundle != NULL)
+ return ::CFBundleGetValueForInfoDictionaryKey(bundle, key);
+ return NULL;
+}
+
+CFURLRef
+CFCBundle::CopyExecutableURL () const
+{
+ CFBundleRef bundle = get();
+ if (bundle != NULL)
+ return CFBundleCopyExecutableURL(bundle);
+ return NULL;
+}
diff --git a/source/Host/macosx/cfcpp/CFCBundle.h b/source/Host/macosx/cfcpp/CFCBundle.h
new file mode 100644
index 000000000000..1cd1b681af84
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCBundle.h
@@ -0,0 +1,50 @@
+//===-- CFCBundle.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFBundle_h_
+#define CoreFoundationCPP_CFBundle_h_
+
+#include "CFCReleaser.h"
+
+class CFCBundle : public CFCReleaser<CFBundleRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCBundle (const char *path = NULL);
+ CFCBundle (CFURLRef url);
+
+ virtual
+ ~CFCBundle();
+
+ CFURLRef
+ CopyExecutableURL () const;
+
+ CFStringRef
+ GetIdentifier () const;
+
+ CFTypeRef
+ GetValueForInfoDictionaryKey(CFStringRef key) const;
+
+ bool
+ GetPath (char *dst, size_t dst_len);
+
+ bool
+ SetPath (const char *path);
+
+private:
+ // Disallow copy and assignment constructors
+ CFCBundle(const CFCBundle&);
+
+ const CFCBundle&
+ operator=(const CFCBundle&);
+};
+
+#endif // #ifndef CoreFoundationCPP_CFBundle_h_
diff --git a/source/Host/macosx/cfcpp/CFCData.cpp b/source/Host/macosx/cfcpp/CFCData.cpp
new file mode 100644
index 000000000000..4f49368ad8ad
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCData.cpp
@@ -0,0 +1,82 @@
+//===-- CFCData.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCData.h"
+
+//----------------------------------------------------------------------
+// CFCData constructor
+//----------------------------------------------------------------------
+CFCData::CFCData(CFDataRef data) :
+ CFCReleaser<CFDataRef>(data)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFCData copy constructor
+//----------------------------------------------------------------------
+CFCData::CFCData(const CFCData& rhs) :
+ CFCReleaser<CFDataRef>(rhs)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFCData copy constructor
+//----------------------------------------------------------------------
+CFCData&
+CFCData::operator=(const CFCData& rhs)
+
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCData::~CFCData()
+{
+}
+
+
+CFIndex
+CFCData::GetLength() const
+{
+ CFDataRef data = get();
+ if (data)
+ return CFDataGetLength (data);
+ return 0;
+}
+
+
+const uint8_t*
+CFCData::GetBytePtr() const
+{
+ CFDataRef data = get();
+ if (data)
+ return CFDataGetBytePtr (data);
+ return NULL;
+}
+
+CFDataRef
+CFCData::Serialize(CFPropertyListRef plist, CFPropertyListFormat format)
+{
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ reset();
+ CFCReleaser<CFWriteStreamRef> stream (::CFWriteStreamCreateWithAllocatedBuffers (alloc, alloc));
+ ::CFWriteStreamOpen (stream.get());
+ CFIndex len = ::CFPropertyListWriteToStream (plist, stream.get(), format, NULL);
+ if (len > 0)
+ reset((CFDataRef)::CFWriteStreamCopyProperty (stream.get(), kCFStreamPropertyDataWritten));
+ ::CFWriteStreamClose (stream.get());
+ return get();
+}
+
diff --git a/source/Host/macosx/cfcpp/CFCData.h b/source/Host/macosx/cfcpp/CFCData.h
new file mode 100644
index 000000000000..6a718f54c055
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCData.h
@@ -0,0 +1,35 @@
+//===-- CFCData.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFData_h_
+#define CoreFoundationCPP_CFData_h_
+
+#include "CFCReleaser.h"
+
+class CFCData : public CFCReleaser<CFDataRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCData(CFDataRef data = NULL);
+ CFCData(const CFCData& rhs);
+ CFCData& operator=(const CFCData& rhs);
+ virtual ~CFCData();
+
+ CFDataRef Serialize(CFPropertyListRef plist, CFPropertyListFormat format);
+ const uint8_t* GetBytePtr () const;
+ CFIndex GetLength () const;
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CFCData can see and modify these
+ //------------------------------------------------------------------
+};
+
+#endif // #ifndef CoreFoundationCPP_CFData_h_
diff --git a/source/Host/macosx/cfcpp/CFCMutableArray.cpp b/source/Host/macosx/cfcpp/CFCMutableArray.cpp
new file mode 100644
index 000000000000..c3c0a11193a7
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableArray.cpp
@@ -0,0 +1,166 @@
+//===-- CFCMutableArray.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCMutableArray.h"
+#include "CFCString.h"
+
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCMutableArray::CFCMutableArray(CFMutableArrayRef s) :
+ CFCReleaser<CFMutableArrayRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableArray copy constructor
+//----------------------------------------------------------------------
+CFCMutableArray::CFCMutableArray(const CFCMutableArray& rhs) :
+ CFCReleaser<CFMutableArrayRef> (rhs) // NOTE: this won't make a copy of the array, just add a new reference to it
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableArray copy constructor
+//----------------------------------------------------------------------
+CFCMutableArray&
+CFCMutableArray::operator=(const CFCMutableArray& rhs)
+{
+ if (this != &rhs)
+ *this = rhs; // NOTE: this operator won't make a copy of the array, just add a new reference to it
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCMutableArray::~CFCMutableArray()
+{
+}
+
+
+CFIndex
+CFCMutableArray::GetCount() const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ return ::CFArrayGetCount (array);
+ return 0;
+}
+
+CFIndex
+CFCMutableArray::GetCountOfValue(CFRange range, const void *value) const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ return ::CFArrayGetCountOfValue (array, range, value);
+ return 0;
+}
+
+CFIndex
+CFCMutableArray::GetCountOfValue(const void *value) const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ return ::CFArrayGetCountOfValue (array, CFRangeMake(0, GetCount()), value);
+ return 0;
+}
+
+const void *
+CFCMutableArray::GetValueAtIndex(CFIndex idx) const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ {
+ const CFIndex num_array_items = ::CFArrayGetCount (array);
+ if (0 <= idx && idx < num_array_items)
+ {
+ return ::CFArrayGetValueAtIndex (array, idx);
+ }
+ }
+ return NULL;
+}
+
+bool
+CFCMutableArray::SetValueAtIndex(CFIndex idx, const void *value)
+{
+ CFMutableArrayRef array = get();
+ if (array != NULL)
+ {
+ const CFIndex num_array_items = ::CFArrayGetCount (array);
+ if (0 <= idx && idx < num_array_items)
+ {
+ ::CFArraySetValueAtIndex (array, idx, value);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableArray::AppendValue(const void *value, bool can_create)
+{
+ CFMutableArrayRef array = get();
+ if (array == NULL)
+ {
+ if (can_create == false)
+ return false;
+ array = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ reset ( array );
+ }
+ if (array != NULL)
+ {
+ ::CFArrayAppendValue(array, value);
+ return true;
+ }
+ return false;
+}
+
+
+bool
+CFCMutableArray::AppendCStringAsCFString (const char *s, CFStringEncoding encoding, bool can_create)
+{
+ CFMutableArrayRef array = get();
+ if (array == NULL)
+ {
+ if (can_create == false)
+ return false;
+ array = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ reset ( array );
+ }
+ if (array != NULL)
+ {
+ CFCString cf_str (s, encoding);
+ ::CFArrayAppendValue (array, cf_str.get());
+ return true;
+ }
+ return false;
+}
+
+bool
+CFCMutableArray::AppendFileSystemRepresentationAsCFString (const char *s, bool can_create)
+{
+ CFMutableArrayRef array = get();
+ if (array == NULL)
+ {
+ if (can_create == false)
+ return false;
+ array = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ reset ( array );
+ }
+ if (array != NULL)
+ {
+ CFCString cf_path;
+ cf_path.SetFileSystemRepresentation(s);
+ ::CFArrayAppendValue (array, cf_path.get());
+ return true;
+ }
+ return false;
+}
diff --git a/source/Host/macosx/cfcpp/CFCMutableArray.h b/source/Host/macosx/cfcpp/CFCMutableArray.h
new file mode 100644
index 000000000000..f78cd92ffab1
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableArray.h
@@ -0,0 +1,39 @@
+//===-- CFCMutableArray.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFMutableArray_h_
+#define CoreFoundationCPP_CFMutableArray_h_
+
+#include "CFCReleaser.h"
+
+class CFCMutableArray : public CFCReleaser<CFMutableArrayRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCMutableArray(CFMutableArrayRef array = NULL);
+ CFCMutableArray(const CFCMutableArray& rhs); // This will copy the array contents into a new array
+ CFCMutableArray& operator=(const CFCMutableArray& rhs); // This will re-use the same array and just bump the ref count
+ virtual ~CFCMutableArray();
+
+ CFIndex GetCount() const;
+ CFIndex GetCountOfValue(const void *value) const;
+ CFIndex GetCountOfValue(CFRange range, const void *value) const;
+ const void * GetValueAtIndex(CFIndex idx) const;
+ bool SetValueAtIndex(CFIndex idx, const void *value);
+ bool AppendValue(const void *value, bool can_create = true); // Appends value and optionally creates a CFCMutableArray if this class doesn't contain one
+ bool AppendCStringAsCFString (const char *cstr,
+ CFStringEncoding encoding = kCFStringEncodingUTF8,
+ bool can_create = true);
+ bool AppendFileSystemRepresentationAsCFString (const char *s,
+ bool can_create = true);
+};
+
+#endif // #ifndef CoreFoundationCPP_CFMutableArray_h_
diff --git a/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp b/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp
new file mode 100644
index 000000000000..bce023bfd616
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp
@@ -0,0 +1,529 @@
+//===-- CFCMutableDictionary.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCMutableDictionary.h"
+#include "CFCString.h"
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCMutableDictionary::CFCMutableDictionary(CFMutableDictionaryRef s) :
+ CFCReleaser<CFMutableDictionaryRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableDictionary copy constructor
+//----------------------------------------------------------------------
+CFCMutableDictionary::CFCMutableDictionary(const CFCMutableDictionary& rhs) :
+ CFCReleaser<CFMutableDictionaryRef> (rhs)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableDictionary copy constructor
+//----------------------------------------------------------------------
+const CFCMutableDictionary&
+CFCMutableDictionary::operator=(const CFCMutableDictionary& rhs)
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCMutableDictionary::~CFCMutableDictionary()
+{
+}
+
+
+CFIndex
+CFCMutableDictionary::GetCount() const
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetCount (dict);
+ return 0;
+}
+
+CFIndex
+CFCMutableDictionary::GetCountOfKey(const void *key) const
+
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetCountOfKey (dict, key);
+ return 0;
+}
+
+CFIndex
+CFCMutableDictionary::GetCountOfValue(const void *value) const
+
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetCountOfValue (dict, value);
+ return 0;
+}
+
+void
+CFCMutableDictionary::GetKeysAndValues(const void **keys, const void **values) const
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryGetKeysAndValues (dict, keys, values);
+}
+
+
+const void *
+CFCMutableDictionary::GetValue(const void *key) const
+
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetValue (dict, key);
+ return NULL;
+}
+
+Boolean
+CFCMutableDictionary::GetValueIfPresent(const void *key, const void **value_handle) const
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetValueIfPresent (dict, key, value_handle);
+ return false;
+}
+
+
+CFMutableDictionaryRef
+CFCMutableDictionary::Dictionary(bool can_create)
+{
+ CFMutableDictionaryRef dict = get();
+ if (can_create && dict == NULL)
+ {
+ dict = ::CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ reset ( dict );
+ }
+ return dict;
+}
+
+bool
+CFCMutableDictionary::AddValue(CFStringRef key, const void *value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValue(CFStringRef key, const void *value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt8(CFStringRef key, int8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt8Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt8(CFStringRef key, int8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt8Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt16(CFStringRef key, int16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt16(CFStringRef key, int16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt32(CFStringRef key, int32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt32(CFStringRef key, int32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt64(CFStringRef key, int64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt64(CFStringRef key, int64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueUInt8(CFStringRef key, uint8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int16_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueUInt8(CFStringRef key, uint8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int16_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableDictionary::AddValueUInt16(CFStringRef key, uint16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int32_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueUInt16(CFStringRef key, uint16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int32_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueUInt32(CFStringRef key, uint32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int64_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueUInt32(CFStringRef key, uint32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int64_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableDictionary::AddValueUInt64(CFStringRef key, uint64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // The number may appear negative if the MSBit is set in "value". Due to a limitation of
+ // CFNumber, there isn't a way to have it show up otherwise as of this writing.
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableDictionary::SetValueUInt64(CFStringRef key, uint64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // The number may appear negative if the MSBit is set in "value". Due to a limitation of
+ // CFNumber, there isn't a way to have it show up otherwise as of this writing.
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueDouble(CFStringRef key, double value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // The number may appear negative if the MSBit is set in "value". Due to a limitation of
+ // CFNumber, there isn't a way to have it show up otherwise as of this writing.
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberDoubleType, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueDouble(CFStringRef key, double value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // The number may appear negative if the MSBit is set in "value". Due to a limitation of
+ // CFNumber, there isn't a way to have it show up otherwise as of this writing.
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberDoubleType, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueCString(CFStringRef key, const char *cstr, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCString cf_str(cstr, kCFStringEncodingUTF8);
+ if (cf_str.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_str.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueCString(CFStringRef key, const char *cstr, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCString cf_str(cstr, kCFStringEncodingUTF8);
+ if (cf_str.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_str.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void
+CFCMutableDictionary::RemoveAllValues()
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryRemoveAllValues(dict);
+}
+
+void
+CFCMutableDictionary::RemoveValue(const void *value)
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryRemoveValue(dict, value);
+}
+void
+CFCMutableDictionary::ReplaceValue(const void *key, const void *value)
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryReplaceValue (dict, key, value);
+}
+
diff --git a/source/Host/macosx/cfcpp/CFCMutableDictionary.h b/source/Host/macosx/cfcpp/CFCMutableDictionary.h
new file mode 100644
index 000000000000..a1cfb68f569e
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableDictionary.h
@@ -0,0 +1,79 @@
+//===-- CFCMutableDictionary.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFMutableDictionary_h_
+#define CoreFoundationCPP_CFMutableDictionary_h_
+
+#include "CFCReleaser.h"
+
+class CFCMutableDictionary : public CFCReleaser<CFMutableDictionaryRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCMutableDictionary(CFMutableDictionaryRef s = NULL);
+ CFCMutableDictionary(const CFCMutableDictionary& rhs);
+ virtual ~CFCMutableDictionary();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const CFCMutableDictionary&
+ operator=(const CFCMutableDictionary& rhs);
+
+
+ CFIndex GetCount() const;
+ CFIndex GetCountOfKey(const void *value) const;
+ CFIndex GetCountOfValue(const void *value) const;
+ void GetKeysAndValues(const void **keys, const void **values) const;
+ const void * GetValue(const void *key) const;
+ Boolean GetValueIfPresent(const void *key, const void **value_handle) const;
+ bool AddValue(CFStringRef key, const void *value, bool can_create = false);
+ bool SetValue(CFStringRef key, const void *value, bool can_create = false);
+ bool AddValueSInt8(CFStringRef key, int8_t value, bool can_create = false);
+ bool SetValueSInt8(CFStringRef key, int8_t value, bool can_create = false);
+ bool AddValueSInt16(CFStringRef key, int16_t value, bool can_create = false);
+ bool SetValueSInt16(CFStringRef key, int16_t value, bool can_create = false);
+ bool AddValueSInt32(CFStringRef key, int32_t value, bool can_create = false);
+ bool SetValueSInt32(CFStringRef key, int32_t value, bool can_create = false);
+ bool AddValueSInt64(CFStringRef key, int64_t value, bool can_create = false);
+ bool SetValueSInt64(CFStringRef key, int64_t value, bool can_create = false);
+ bool AddValueUInt8(CFStringRef key, uint8_t value, bool can_create = false);
+ bool SetValueUInt8(CFStringRef key, uint8_t value, bool can_create = false);
+ bool AddValueUInt16(CFStringRef key, uint16_t value, bool can_create = false);
+ bool SetValueUInt16(CFStringRef key, uint16_t value, bool can_create = false);
+ bool AddValueUInt32(CFStringRef key, uint32_t value, bool can_create = false);
+ bool SetValueUInt32(CFStringRef key, uint32_t value, bool can_create = false);
+ bool AddValueUInt64(CFStringRef key, uint64_t value, bool can_create = false);
+ bool SetValueUInt64(CFStringRef key, uint64_t value, bool can_create = false);
+ bool AddValueDouble(CFStringRef key, double value, bool can_create = false);
+ bool SetValueDouble(CFStringRef key, double value, bool can_create = false);
+ bool AddValueCString(CFStringRef key, const char *cstr, bool can_create = false);
+ bool SetValueCString(CFStringRef key, const char *cstr, bool can_create = false);
+ void RemoveValue(const void *value);
+ void ReplaceValue(const void *key, const void *value);
+ void RemoveAllValues();
+ CFMutableDictionaryRef Dictionary(bool can_create);
+
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CFCMutableDictionary can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For CFCMutableDictionary only
+ //------------------------------------------------------------------
+
+};
+
+
+#endif // CoreFoundationCPP_CFMutableDictionary_h_
diff --git a/source/Host/macosx/cfcpp/CFCMutableSet.cpp b/source/Host/macosx/cfcpp/CFCMutableSet.cpp
new file mode 100644
index 000000000000..afc09e180b6b
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableSet.cpp
@@ -0,0 +1,114 @@
+//===-- CFCMutableSet.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCMutableSet.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCMutableSet::CFCMutableSet(CFMutableSetRef s) :
+ CFCReleaser<CFMutableSetRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableSet copy constructor
+//----------------------------------------------------------------------
+CFCMutableSet::CFCMutableSet(const CFCMutableSet& rhs) :
+ CFCReleaser<CFMutableSetRef> (rhs)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableSet copy constructor
+//----------------------------------------------------------------------
+const CFCMutableSet&
+CFCMutableSet::operator=(const CFCMutableSet& rhs)
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCMutableSet::~CFCMutableSet()
+{
+}
+
+
+CFIndex
+CFCMutableSet::GetCount() const
+{
+ CFMutableSetRef set = get();
+ if (set)
+ return ::CFSetGetCount (set);
+ return 0;
+}
+
+CFIndex
+CFCMutableSet::GetCountOfValue(const void *value) const
+{
+ CFMutableSetRef set = get();
+ if (set)
+ return ::CFSetGetCountOfValue (set, value);
+ return 0;
+}
+
+const void *
+CFCMutableSet::GetValue(const void *value) const
+{
+ CFMutableSetRef set = get();
+ if (set)
+ return ::CFSetGetValue(set, value);
+ return NULL;
+}
+
+
+const void *
+CFCMutableSet::AddValue(const void *value, bool can_create)
+{
+ CFMutableSetRef set = get();
+ if (set == NULL)
+ {
+ if (can_create == false)
+ return NULL;
+ set = ::CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
+ reset ( set );
+ }
+ if (set != NULL)
+ {
+ ::CFSetAddValue(set, value);
+ return value;
+ }
+ return NULL;
+}
+
+void
+CFCMutableSet::RemoveValue(const void *value)
+{
+ CFMutableSetRef set = get();
+ if (set)
+ ::CFSetRemoveValue(set, value);
+}
+
+void
+CFCMutableSet::RemoveAllValues()
+{
+ CFMutableSetRef set = get();
+ if (set)
+ ::CFSetRemoveAllValues(set);
+}
+
diff --git a/source/Host/macosx/cfcpp/CFCMutableSet.h b/source/Host/macosx/cfcpp/CFCMutableSet.h
new file mode 100644
index 000000000000..78f7a8be81d2
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableSet.h
@@ -0,0 +1,53 @@
+//===-- CFCMutableSet.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFMutableSet_h_
+#define CoreFoundationCPP_CFMutableSet_h_
+
+#include "CFCReleaser.h"
+
+class CFCMutableSet : public CFCReleaser<CFMutableSetRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCMutableSet(CFMutableSetRef s = NULL);
+ CFCMutableSet(const CFCMutableSet& rhs);
+ virtual ~CFCMutableSet();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const CFCMutableSet&
+ operator=(const CFCMutableSet& rhs);
+
+
+ CFIndex GetCount() const;
+ CFIndex GetCountOfValue(const void *value) const;
+ const void * GetValue(const void *value) const;
+ const void * AddValue(const void *value, bool can_create);
+ void RemoveValue(const void *value);
+ void RemoveAllValues();
+
+
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CFCMutableSet can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For CFCMutableSet only
+ //------------------------------------------------------------------
+
+};
+
+#endif // CoreFoundationCPP_CFMutableSet_h_
diff --git a/source/Host/macosx/cfcpp/CFCReleaser.h b/source/Host/macosx/cfcpp/CFCReleaser.h
new file mode 100644
index 000000000000..67dd2ead5799
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCReleaser.h
@@ -0,0 +1,158 @@
+//===-- CFCReleaser.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFReleaser_h_
+#define CoreFoundationCPP_CFReleaser_h_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef __cplusplus
+
+#include <assert.h>
+
+//----------------------------------------------------------------------
+// Templatized CF helper class that can own any CF pointer and will
+// call CFRelease() on any valid pointer it owns unless that pointer is
+// explicitly released using the release() member function. This class
+// is designed to mimic the std::auto_ptr<T> class and has all of the
+// same functions. The one thing to watch out for is the
+// CFCReleaser<T>::release() function won't actually CFRelease any owned
+// pointer, it is designed to relinquish ownership of the pointer just
+// like std:auto_ptr<T>::release() does.
+//----------------------------------------------------------------------
+template <class T>
+class CFCReleaser
+{
+public:
+ //----------------------------------------------------------
+ // Constructor that takes a pointer to a CF object that is
+ // to be released when this object goes out of scope
+ //----------------------------------------------------------
+ CFCReleaser(T ptr = NULL) :
+ _ptr(ptr)
+ {
+ }
+
+ //----------------------------------------------------------
+ // Copy constructor
+ //
+ // Note that copying a CFCReleaser will not transfer
+ // ownership of the contained pointer, but it will bump its
+ // reference count. This is where this class differs from
+ // std::auto_ptr.
+ //----------------------------------------------------------
+ CFCReleaser(const CFCReleaser& rhs) :
+ _ptr(rhs.get())
+ {
+ if (get())
+ ::CFRetain(get());
+ }
+
+
+ //----------------------------------------------------------
+ // The destructor will release the pointer that it contains
+ // if it has a valid pointer.
+ //----------------------------------------------------------
+ virtual ~CFCReleaser()
+ {
+ reset();
+ }
+
+ //----------------------------------------------------------
+ // Assignment operator.
+ //
+ // Note that assigning one CFCReleaser to another will
+ // not transfer ownership of the contained pointer, but it
+ // will bump its reference count. This is where this class
+ // differs from std::auto_ptr.
+ //----------------------------------------------------------
+ CFCReleaser&
+ operator= (const CFCReleaser<T>& rhs)
+ {
+ if (this != &rhs)
+ {
+ // Replace our owned pointer with the new one
+ reset(rhs.get());
+ // Retain the current pointer that we own
+ if (get())
+ ::CFRetain(get());
+ }
+ return *this;
+ }
+
+ //----------------------------------------------------------
+ // Get the address of the contained type in case it needs
+ // to be passed to a function that will fill in a pointer
+ // value. The function currently will assert if _ptr is not
+ // NULL because the only time this method should be used is
+ // if another function will modify the contents, and we
+ // could leak a pointer if this is not NULL. If the
+ // assertion fires, check the offending code, or call
+ // reset() prior to using the "ptr_address()" member to make
+ // sure any owned objects has CFRelease called on it.
+ // I had to add the "enforce_null" bool here because some
+ // API's require the pointer address even though they don't change it.
+ //----------------------------------------------------------
+ T*
+ ptr_address(bool enforce_null = true)
+ {
+ if (enforce_null)
+ assert (_ptr == NULL);
+ return &_ptr;
+ }
+
+ //----------------------------------------------------------
+ // Access the pointer itself
+ //----------------------------------------------------------
+ T
+ get()
+ {
+ return _ptr;
+ }
+
+ const T
+ get() const
+ {
+ return _ptr;
+ }
+
+
+ //----------------------------------------------------------
+ // Set a new value for the pointer and CFRelease our old
+ // value if we had a valid one.
+ //----------------------------------------------------------
+ void
+ reset(T ptr = NULL)
+ {
+ if ((_ptr != NULL) && (ptr != _ptr))
+ ::CFRelease(_ptr);
+ _ptr = ptr;
+ }
+
+ //----------------------------------------------------------
+ // Release ownership without calling CFRelease. This class
+ // is designed to mimic std::auto_ptr<T>, so the release
+ // method releases ownership of the contained pointer
+ // and does NOT call CFRelease.
+ //----------------------------------------------------------
+ T
+ release()
+ {
+ T tmp = _ptr;
+ _ptr = NULL;
+ return tmp;
+ }
+
+private:
+ T _ptr;
+};
+
+#endif // #ifdef __cplusplus
+#endif // #ifndef CoreFoundationCPP_CFReleaser_h_
+
diff --git a/source/Host/macosx/cfcpp/CFCString.cpp b/source/Host/macosx/cfcpp/CFCString.cpp
new file mode 100644
index 000000000000..81a96b824999
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCString.cpp
@@ -0,0 +1,195 @@
+//===-- CFCString.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCString.h"
+#include <string>
+#include <glob.h>
+
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCString::CFCString(CFStringRef s) :
+ CFCReleaser<CFStringRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCString copy constructor
+//----------------------------------------------------------------------
+CFCString::CFCString(const CFCString& rhs) :
+ CFCReleaser<CFStringRef> (rhs)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFCString copy constructor
+//----------------------------------------------------------------------
+CFCString&
+CFCString::operator=(const CFCString& rhs)
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+CFCString::CFCString (const char *cstr, CFStringEncoding cstr_encoding) :
+ CFCReleaser<CFStringRef> ()
+{
+ if (cstr && cstr[0])
+ {
+ reset(::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding));
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCString::~CFCString()
+{
+}
+
+const char *
+CFCString::GetFileSystemRepresentation(std::string& s)
+{
+ return CFCString::FileSystemRepresentation(get(), s);
+}
+
+CFStringRef
+CFCString::SetFileSystemRepresentation (const char *path)
+{
+ CFStringRef new_value = NULL;
+ if (path && path[0])
+ new_value = ::CFStringCreateWithFileSystemRepresentation (kCFAllocatorDefault, path);
+ reset(new_value);
+ return get();
+}
+
+
+CFStringRef
+CFCString::SetFileSystemRepresentationFromCFType (CFTypeRef cf_type)
+{
+ CFStringRef new_value = NULL;
+ if (cf_type != NULL)
+ {
+ CFTypeID cf_type_id = ::CFGetTypeID(cf_type);
+
+ if (cf_type_id == ::CFStringGetTypeID())
+ {
+ // Retain since we are using the existing object
+ new_value = (CFStringRef)::CFRetain(cf_type);
+ }
+ else if (cf_type_id == ::CFURLGetTypeID())
+ {
+ new_value = ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle);
+ }
+ }
+ reset(new_value);
+ return get();
+}
+
+CFStringRef
+CFCString::SetFileSystemRepresentationAndExpandTilde (const char *path)
+{
+ std::string expanded_path;
+ if (CFCString::ExpandTildeInPath(path, expanded_path))
+ SetFileSystemRepresentation(expanded_path.c_str());
+ else
+ reset();
+ return get();
+}
+
+const char *
+CFCString::UTF8(std::string& str)
+{
+ return CFCString::UTF8(get(), str);
+}
+
+// Static function that puts a copy of the UTF8 contents of CF_STR into STR
+// and returns the C string pointer that is contained in STR when successful, else
+// NULL is returned. This allows the std::string parameter to own the extracted string,
+// and also allows that string to be returned as a C string pointer that can be used.
+
+const char *
+CFCString::UTF8 (CFStringRef cf_str, std::string& str)
+{
+ if (cf_str)
+ {
+ const CFStringEncoding encoding = kCFStringEncodingUTF8;
+ CFIndex max_utf8_str_len = CFStringGetLength (cf_str);
+ max_utf8_str_len = CFStringGetMaximumSizeForEncoding (max_utf8_str_len, encoding);
+ if (max_utf8_str_len > 0)
+ {
+ str.resize(max_utf8_str_len);
+ if (!str.empty())
+ {
+ if (CFStringGetCString (cf_str, &str[0], str.size(), encoding))
+ {
+ str.resize(strlen(str.c_str()));
+ return str.c_str();
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const char*
+CFCString::ExpandTildeInPath(const char* path, std::string &expanded_path)
+{
+ glob_t globbuf;
+ if (::glob (path, GLOB_TILDE, NULL, &globbuf) == 0)
+ {
+ expanded_path = globbuf.gl_pathv[0];
+ ::globfree (&globbuf);
+ }
+ else
+ expanded_path.clear();
+
+ return expanded_path.c_str();
+}
+
+// Static function that puts a copy of the file system representation of CF_STR
+// into STR and returns the C string pointer that is contained in STR when
+// successful, else NULL is returned. This allows the std::string parameter
+// to own the extracted string, and also allows that string to be returned as
+// a C string pointer that can be used.
+
+const char *
+CFCString::FileSystemRepresentation (CFStringRef cf_str, std::string& str)
+{
+ if (cf_str)
+ {
+ CFIndex max_length = ::CFStringGetMaximumSizeOfFileSystemRepresentation (cf_str);
+ if (max_length > 0)
+ {
+ str.resize(max_length);
+ if (!str.empty())
+ {
+ if (::CFStringGetFileSystemRepresentation (cf_str, &str[0], str.size()))
+ {
+ str.erase(::strlen(str.c_str()));
+ return str.c_str();
+ }
+ }
+ }
+ }
+ str.erase();
+ return NULL;
+}
+
+
+CFIndex
+CFCString::GetLength() const
+{
+ CFStringRef str = get();
+ if (str)
+ return CFStringGetLength (str);
+ return 0;
+}
diff --git a/source/Host/macosx/cfcpp/CFCString.h b/source/Host/macosx/cfcpp/CFCString.h
new file mode 100644
index 000000000000..27c090313ece
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCString.h
@@ -0,0 +1,41 @@
+//===-- CFCString.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFString_h_
+#define CoreFoundationCPP_CFString_h_
+
+#include <iosfwd>
+
+#include "CFCReleaser.h"
+
+class CFCString : public CFCReleaser<CFStringRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCString (CFStringRef cf_str = NULL);
+ CFCString (const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8);
+ CFCString (const CFCString& rhs);
+ CFCString& operator= (const CFCString& rhs);
+ virtual ~CFCString ();
+
+ const char * GetFileSystemRepresentation (std::string& str);
+ CFStringRef SetFileSystemRepresentation (const char *path);
+ CFStringRef SetFileSystemRepresentationFromCFType (CFTypeRef cf_type);
+ CFStringRef SetFileSystemRepresentationAndExpandTilde (const char *path);
+ const char * UTF8 (std::string& str);
+ CFIndex GetLength() const;
+ static const char *UTF8 (CFStringRef cf_str, std::string& str);
+ static const char *FileSystemRepresentation (CFStringRef cf_str, std::string& str);
+ static const char *ExpandTildeInPath(const char* path, std::string &expanded_path);
+
+};
+
+#endif // #ifndef CoreFoundationCPP_CFString_h_
diff --git a/source/Host/macosx/cfcpp/CoreFoundationCPP.h b/source/Host/macosx/cfcpp/CoreFoundationCPP.h
new file mode 100644
index 000000000000..6843e2649cda
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CoreFoundationCPP.h
@@ -0,0 +1,30 @@
+//===-- CoreFoundationCPP.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// CoreFoundationCPP.h
+// CoreFoundationCPP
+//
+// Created by Greg Clayton on 4/23/09.
+//
+//
+//----------------------------------------------------------------------
+
+#ifndef CoreFoundationCPP_CoreFoundationCPP_H_
+#define CoreFoundationCPP_CoreFoundationCPP_H_
+
+#include <CoreFoundationCPP/CFCBundle.h>
+#include <CoreFoundationCPP/CFCData.h>
+#include <CoreFoundationCPP/CFCReleaser.h>
+#include <CoreFoundationCPP/CFCMutableArray.h>
+#include <CoreFoundationCPP/CFCMutableDictionary.h>
+#include <CoreFoundationCPP/CFCMutableSet.h>
+#include <CoreFoundationCPP/CFCString.h>
+
+#endif // CoreFoundationCPP_CoreFoundationCPP_H_
diff --git a/source/Host/netbsd/Makefile b/source/Host/netbsd/Makefile
new file mode 100644
index 000000000000..2502cc49c15b
--- /dev/null
+++ b/source/Host/netbsd/Makefile
@@ -0,0 +1,14 @@
+##===- source/Host/netbsd/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../..
+LIBRARYNAME := lldbHostNetBSD
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Host/windows/Condition.cpp b/source/Host/windows/Condition.cpp
new file mode 100644
index 000000000000..2f16ad77d7a3
--- /dev/null
+++ b/source/Host/windows/Condition.cpp
@@ -0,0 +1,98 @@
+//===-- Condition.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <errno.h>
+
+#include "lldb/Host/Condition.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Host/windows/windows.h"
+
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//
+// The default constructor will initialize a new pthread condition
+// and maintain the condition in the object state.
+//----------------------------------------------------------------------
+Condition::Condition () :
+ m_condition()
+{
+ m_condition = static_cast<PCONDITION_VARIABLE>(malloc(sizeof(CONDITION_VARIABLE)));
+ InitializeConditionVariable(static_cast<PCONDITION_VARIABLE>(m_condition));
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// Destroys the pthread condition that the object owns.
+//----------------------------------------------------------------------
+Condition::~Condition ()
+{
+ free(m_condition);
+}
+
+//----------------------------------------------------------------------
+// Unblock all threads waiting for a condition variable
+//----------------------------------------------------------------------
+int
+Condition::Broadcast ()
+{
+ WakeAllConditionVariable(static_cast<PCONDITION_VARIABLE>(m_condition));
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Unblocks one thread waiting for the condition variable
+//----------------------------------------------------------------------
+int
+Condition::Signal ()
+{
+ WakeConditionVariable(static_cast<PCONDITION_VARIABLE>(m_condition));
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// The Wait() function atomically blocks the current thread
+// waiting on the owned condition variable, and unblocks the mutex
+// specified by "mutex". The waiting thread unblocks only after
+// another thread calls Signal(), or Broadcast() with the same
+// condition variable, or if "abstime" is valid (non-NULL) this
+// function will return when the system time reaches the time
+// specified in "abstime". If "abstime" is NULL this function will
+// wait for an infinite amount of time for the condition variable
+// to be signaled or broadcasted.
+//
+// The current thread re-acquires the lock on "mutex".
+//----------------------------------------------------------------------
+int
+Condition::Wait (Mutex &mutex, const TimeValue *abstime, bool *timed_out)
+{
+ DWORD wait = INFINITE;
+ if (abstime != NULL) {
+ int wval = (*abstime - TimeValue::Now()) / 1000000;
+ if (wval < 0) wval = 0;
+
+ wait = wval;
+ }
+
+ int err = SleepConditionVariableCS(static_cast<PCONDITION_VARIABLE>(m_condition), static_cast<PCRITICAL_SECTION>(mutex.m_mutex), wait);
+
+ if (timed_out != NULL)
+ {
+ if ((err == 0) && GetLastError() == ERROR_TIMEOUT)
+ *timed_out = true;
+ else
+ *timed_out = false;
+ }
+
+ return err == 0;
+}
+
diff --git a/source/Host/windows/ConnectionGenericFileWindows.cpp b/source/Host/windows/ConnectionGenericFileWindows.cpp
new file mode 100644
index 000000000000..eebf3d4f633c
--- /dev/null
+++ b/source/Host/windows/ConnectionGenericFileWindows.cpp
@@ -0,0 +1,354 @@
+//===-- ConnectionGenericFileWindows.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/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+// This is a simple helper class to package up the information needed to return from a Read/Write
+// operation function. Since there is a lot of code to be run before exit regardless of whether the
+// operation succeeded or failed, combined with many possible return paths, this is the cleanest
+// way to represent it.
+class ReturnInfo
+{
+ public:
+ void
+ Set(size_t bytes, ConnectionStatus status, DWORD error_code)
+ {
+ m_error.SetError(error_code, eErrorTypeWin32);
+ m_bytes = bytes;
+ m_status = status;
+ }
+
+ void
+ Set(size_t bytes, ConnectionStatus status, llvm::StringRef error_msg)
+ {
+ m_error.SetErrorString(error_msg.data());
+ m_bytes = bytes;
+ m_status = status;
+ }
+
+ size_t
+ GetBytes() const
+ {
+ return m_bytes;
+ }
+ ConnectionStatus
+ GetStatus() const
+ {
+ return m_status;
+ }
+ const Error &
+ GetError() const
+ {
+ return m_error;
+ }
+
+ private:
+ Error m_error;
+ size_t m_bytes;
+ ConnectionStatus m_status;
+};
+}
+
+ConnectionGenericFile::ConnectionGenericFile()
+ : m_file(INVALID_HANDLE_VALUE)
+ , m_owns_file(false)
+{
+ ::ZeroMemory(&m_overlapped, sizeof(m_overlapped));
+ ::ZeroMemory(&m_file_position, sizeof(m_file_position));
+ InitializeEventHandles();
+}
+
+ConnectionGenericFile::ConnectionGenericFile(lldb::file_t file, bool owns_file)
+ : m_file(file)
+ , m_owns_file(owns_file)
+{
+ ::ZeroMemory(&m_overlapped, sizeof(m_overlapped));
+ ::ZeroMemory(&m_file_position, sizeof(m_file_position));
+ InitializeEventHandles();
+}
+
+ConnectionGenericFile::~ConnectionGenericFile()
+{
+ if (m_owns_file && IsConnected())
+ ::CloseHandle(m_file);
+
+ ::CloseHandle(m_event_handles[kBytesAvailableEvent]);
+ ::CloseHandle(m_event_handles[kInterruptEvent]);
+}
+
+void
+ConnectionGenericFile::InitializeEventHandles()
+{
+ m_event_handles[kInterruptEvent] = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ // Note, we should use a manual reset event for the hEvent argument of the OVERLAPPED. This
+ // is because both WaitForMultipleObjects and GetOverlappedResult (if you set the bWait
+ // argument to TRUE) will wait for the event to be signalled. If we use an auto-reset event,
+ // WaitForMultipleObjects will reset the event, return successfully, and then
+ // GetOverlappedResult will block since the event is no longer signalled.
+ m_event_handles[kBytesAvailableEvent] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+}
+
+bool
+ConnectionGenericFile::IsConnected() const
+{
+ return m_file && (m_file != INVALID_HANDLE_VALUE);
+}
+
+lldb::ConnectionStatus
+ConnectionGenericFile::Connect(const char *s, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionGenericFile::Connect (url = '%s')", static_cast<void *>(this), s);
+
+ if (strstr(s, "file://") != s)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", s);
+ return eConnectionStatusError;
+ }
+
+ if (IsConnected())
+ {
+ ConnectionStatus status = Disconnect(error_ptr);
+ if (status != eConnectionStatusSuccess)
+ return status;
+ }
+
+ // file://PATH
+ const char *path = s + strlen("file://");
+ // Open the file for overlapped access. If it does not exist, create it. We open it overlapped
+ // so that we can issue asynchronous reads and then use WaitForMultipleObjects to allow the read
+ // to be interrupted by an event object.
+ m_file = ::CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL);
+ if (m_file == INVALID_HANDLE_VALUE)
+ {
+ if (error_ptr)
+ error_ptr->SetError(::GetLastError(), eErrorTypeWin32);
+ return eConnectionStatusError;
+ }
+
+ m_owns_file = true;
+ m_uri.assign(s);
+ return eConnectionStatusSuccess;
+}
+
+lldb::ConnectionStatus
+ConnectionGenericFile::Disconnect(Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionGenericFile::Disconnect ()", static_cast<void *>(this));
+
+ if (!IsConnected())
+ return eConnectionStatusSuccess;
+
+ // Reset the handle so that after we unblock any pending reads, subsequent calls to Read() will
+ // see a disconnected state.
+ HANDLE old_file = m_file;
+ m_file = INVALID_HANDLE_VALUE;
+
+ // Set the disconnect event so that any blocking reads unblock, then cancel any pending IO operations.
+ ::CancelIoEx(old_file, &m_overlapped);
+
+ // Close the file handle if we owned it, but don't close the event handles. We could always
+ // reconnect with the same Connection instance.
+ if (m_owns_file)
+ ::CloseHandle(old_file);
+
+ ::ZeroMemory(&m_file_position, sizeof(m_file_position));
+ m_owns_file = false;
+ m_uri.clear();
+ return eConnectionStatusSuccess;
+}
+
+size_t
+ConnectionGenericFile::Read(void *dst, size_t dst_len, uint32_t timeout_usec, lldb::ConnectionStatus &status, Error *error_ptr)
+{
+ ReturnInfo return_info;
+ BOOL result = 0;
+ DWORD bytes_read = 0;
+
+ if (error_ptr)
+ error_ptr->Clear();
+
+ if (!IsConnected())
+ {
+ return_info.Set(0, eConnectionStatusNoConnection, ERROR_INVALID_HANDLE);
+ goto finish;
+ }
+
+ m_overlapped.hEvent = m_event_handles[kBytesAvailableEvent];
+
+ result = ::ReadFile(m_file, dst, dst_len, NULL, &m_overlapped);
+ if (result || ::GetLastError() == ERROR_IO_PENDING)
+ {
+ if (!result)
+ {
+ // The expected return path. The operation is pending. Wait for the operation to complete
+ // or be interrupted.
+ TimeValue time_value;
+ time_value.OffsetWithMicroSeconds(timeout_usec);
+ DWORD milliseconds = time_value.milliseconds();
+ DWORD wait_result = ::WaitForMultipleObjects(llvm::array_lengthof(m_event_handles), m_event_handles, FALSE, milliseconds);
+ // All of the events are manual reset events, so make sure we reset them to non-signalled.
+ switch (wait_result)
+ {
+ case WAIT_OBJECT_0 + kBytesAvailableEvent:
+ break;
+ case WAIT_OBJECT_0 + kInterruptEvent:
+ return_info.Set(0, eConnectionStatusInterrupted, 0);
+ goto finish;
+ case WAIT_TIMEOUT:
+ return_info.Set(0, eConnectionStatusTimedOut, 0);
+ goto finish;
+ case WAIT_FAILED:
+ return_info.Set(0, eConnectionStatusError, ::GetLastError());
+ goto finish;
+ }
+ }
+ // The data is ready. Figure out how much was read and return;
+ if (!::GetOverlappedResult(m_file, &m_overlapped, &bytes_read, FALSE))
+ {
+ DWORD result_error = ::GetLastError();
+ // ERROR_OPERATION_ABORTED occurs when someone calls Disconnect() during a blocking read.
+ // This triggers a call to CancelIoEx, which causes the operation to complete and the
+ // result to be ERROR_OPERATION_ABORTED.
+ if (result_error == ERROR_HANDLE_EOF || result_error == ERROR_OPERATION_ABORTED || result_error == ERROR_BROKEN_PIPE)
+ return_info.Set(bytes_read, eConnectionStatusEndOfFile, 0);
+ else
+ return_info.Set(bytes_read, eConnectionStatusError, result_error);
+ }
+ else if (bytes_read == 0)
+ return_info.Set(bytes_read, eConnectionStatusEndOfFile, 0);
+ else
+ return_info.Set(bytes_read, eConnectionStatusSuccess, 0);
+
+ goto finish;
+ }
+ else if (::GetLastError() == ERROR_BROKEN_PIPE)
+ {
+ // The write end of a pipe was closed. This is equivalent to EOF.
+ return_info.Set(0, eConnectionStatusEndOfFile, 0);
+ }
+ else
+ {
+ // An unknown error occurred. Fail out.
+ return_info.Set(0, eConnectionStatusError, ::GetLastError());
+ }
+ goto finish;
+
+finish:
+ status = return_info.GetStatus();
+ if (error_ptr)
+ *error_ptr = return_info.GetError();
+
+ // kBytesAvailableEvent is a manual reset event. Make sure it gets reset here so that any
+ // subsequent operations don't immediately see bytes available.
+ ResetEvent(m_event_handles[kBytesAvailableEvent]);
+
+ IncrementFilePointer(return_info.GetBytes());
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ if (log)
+ {
+ log->Printf("%" PRIxPTR " ConnectionGenericFile::Read() handle = %" PRIxPTR ", dst = %" PRIxPTR ", dst_len = %" PRIu64
+ ") => %" PRIu64 ", error = %s",
+ this, m_file, dst, static_cast<uint64_t>(dst_len), static_cast<uint64_t>(return_info.GetBytes()),
+ return_info.GetError().AsCString());
+ }
+
+ return return_info.GetBytes();
+}
+
+size_t
+ConnectionGenericFile::Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, Error *error_ptr)
+{
+ ReturnInfo return_info;
+ DWORD bytes_written = 0;
+ BOOL result = 0;
+
+ if (error_ptr)
+ error_ptr->Clear();
+
+ if (!IsConnected())
+ {
+ return_info.Set(0, eConnectionStatusNoConnection, ERROR_INVALID_HANDLE);
+ goto finish;
+ }
+
+ m_overlapped.hEvent = NULL;
+
+ // Writes are not interruptible like reads are, so just block until it's done.
+ result = ::WriteFile(m_file, src, src_len, NULL, &m_overlapped);
+ if (!result && ::GetLastError() != ERROR_IO_PENDING)
+ {
+ return_info.Set(0, eConnectionStatusError, ::GetLastError());
+ goto finish;
+ }
+
+ if (!::GetOverlappedResult(m_file, &m_overlapped, &bytes_written, TRUE))
+ {
+ return_info.Set(bytes_written, eConnectionStatusError, ::GetLastError());
+ goto finish;
+ }
+
+ return_info.Set(bytes_written, eConnectionStatusSuccess, 0);
+ goto finish;
+
+finish:
+ status = return_info.GetStatus();
+ if (error_ptr)
+ *error_ptr = return_info.GetError();
+
+ IncrementFilePointer(return_info.GetBytes());
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ if (log)
+ {
+ log->Printf("%" PRIxPTR " ConnectionGenericFile::Write() handle = %" PRIxPTR ", src = %" PRIxPTR ", src_len = %" PRIu64
+ ") => %" PRIu64 ", error = %s",
+ this, m_file, src, static_cast<uint64_t>(src_len), static_cast<uint64_t>(return_info.GetBytes()),
+ return_info.GetError().AsCString());
+ }
+ return return_info.GetBytes();
+}
+
+std::string
+ConnectionGenericFile::GetURI()
+{
+ return m_uri;
+}
+
+bool
+ConnectionGenericFile::InterruptRead()
+{
+ return ::SetEvent(m_event_handles[kInterruptEvent]);
+}
+
+void
+ConnectionGenericFile::IncrementFilePointer(DWORD amount)
+{
+ LARGE_INTEGER old_pos;
+ old_pos.HighPart = m_overlapped.OffsetHigh;
+ old_pos.LowPart = m_overlapped.Offset;
+ old_pos.QuadPart += amount;
+ m_overlapped.Offset = old_pos.LowPart;
+ m_overlapped.OffsetHigh = old_pos.HighPart;
+}
diff --git a/source/Host/windows/EditLineWin.cpp b/source/Host/windows/EditLineWin.cpp
new file mode 100644
index 000000000000..55fe52dc8ccd
--- /dev/null
+++ b/source/Host/windows/EditLineWin.cpp
@@ -0,0 +1,435 @@
+//===-- EditLineWin.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// this file is only relevant for Visual C++
+#if defined( _WIN32 )
+
+#include "lldb/Host/windows/windows.h"
+
+#include "lldb/Host/windows/editlinewin.h"
+#include <vector>
+#include <assert.h>
+
+// edit line EL_ADDFN function pointer type
+typedef unsigned char(*el_addfn_func)(EditLine *e, int ch);
+typedef const char* (*el_prompt_func)(EditLine *);
+
+// edit line wrapper binding container
+struct el_binding
+{
+ //
+ const char *name;
+ const char *help;
+ // function pointer to callback routine
+ el_addfn_func func;
+ // ascii key this function is bound to
+ const char *key;
+};
+
+// stored key bindings
+static std::vector<el_binding*> _bindings;
+
+//TODO: this should in fact be related to the exact edit line context we create
+static void *clientData = NULL;
+
+// store the current prompt string
+// default to what we expect to receive anyway
+static const char *_prompt = "(lldb) ";
+
+#if !defined( _WIP_INPUT_METHOD )
+
+static char *
+el_get_s (char *buffer, int chars)
+{
+ return gets_s(buffer, chars);
+}
+#else
+
+static void
+con_output (char _in)
+{
+ HANDLE hout = GetStdHandle( STD_OUTPUT_HANDLE );
+ DWORD written = 0;
+ // get the cursor position
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ GetConsoleScreenBufferInfo( hout, &info );
+ // output this char
+ WriteConsoleOutputCharacterA( hout, &_in, 1, info.dwCursorPosition, &written );
+ // advance cursor position
+ info.dwCursorPosition.X++;
+ SetConsoleCursorPosition( hout, info.dwCursorPosition );
+}
+
+static void
+con_backspace (void)
+{
+ HANDLE hout = GetStdHandle( STD_OUTPUT_HANDLE );
+ DWORD written = 0;
+ // get cursor position
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ GetConsoleScreenBufferInfo( hout, &info );
+ // nudge cursor backwards
+ info.dwCursorPosition.X--;
+ SetConsoleCursorPosition( hout, info.dwCursorPosition );
+ // blank out the last character
+ WriteConsoleOutputCharacterA( hout, " ", 1, info.dwCursorPosition, &written );
+}
+
+static void
+con_return (void)
+{
+ HANDLE hout = GetStdHandle( STD_OUTPUT_HANDLE );
+ DWORD written = 0;
+ // get cursor position
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ GetConsoleScreenBufferInfo( hout, &info );
+ // move onto the new line
+ info.dwCursorPosition.X = 0;
+ info.dwCursorPosition.Y++;
+ SetConsoleCursorPosition( hout, info.dwCursorPosition );
+}
+
+static bool
+runBind (char _key)
+{
+ for ( int i=0; i<_bindings.size(); i++ )
+ {
+ el_binding *bind = _bindings[i];
+ if ( bind->key[0] == _key )
+ {
+ bind->func( (EditLine*) -1, _key );
+ return true;
+ }
+ }
+ return false;
+}
+
+// replacement get_s which is EL_BIND aware
+static char *
+el_get_s (char *buffer, int chars)
+{
+ //
+ char *head = buffer;
+ //
+ for ( ;; Sleep( 10 ) )
+ {
+ //
+ INPUT_RECORD _record;
+ //
+ DWORD _read = 0;
+ if ( ReadConsoleInputA( GetStdHandle( STD_INPUT_HANDLE ), &_record, 1, &_read ) == FALSE )
+ break;
+ // if we didn't read a key
+ if ( _read == 0 )
+ continue;
+ // only interested in key events
+ if ( _record.EventType != KEY_EVENT )
+ continue;
+ // is the key down
+ if (! _record.Event.KeyEvent.bKeyDown )
+ continue;
+ // read the ascii key character
+ char _key = _record.Event.KeyEvent.uChar.AsciiChar;
+ // non ascii conformant key press
+ if ( _key == 0 )
+ {
+ // check the scan code
+ // if VK_UP scroll back through history
+ // if VK_DOWN scroll forward through history
+ continue;
+ }
+ // try to execute any bind this key may have
+ if ( runBind( _key ) )
+ continue;
+ // if we read a return key
+ if ( _key == '\n' || _key == '\r' )
+ {
+ con_return( );
+ break;
+ }
+ // key is backspace
+ if ( _key == 0x8 )
+ {
+ // avoid deleting past beginning
+ if ( head > buffer )
+ {
+ con_backspace( );
+ head--;
+ }
+ continue;
+ }
+
+ // add this key to the input buffer
+ if ( (head-buffer) < (chars-1) )
+ {
+ con_output( _key );
+ *(head++) = _key;
+ }
+ }
+ // insert end of line character
+ *head = '\0';
+
+ return buffer;
+}
+#endif
+
+// edit line initialize
+EditLine *
+el_init (const char *, FILE *, FILE *, FILE *)
+{
+ //
+ SetConsoleTitleA( "lldb" );
+ // return dummy handle
+ return (EditLine*) -1;
+}
+
+const char *
+el_gets (EditLine *el, int *length)
+{
+ // print the prompt if we have one
+ if ( _prompt != NULL )
+ printf("%s", _prompt);
+ // create a buffer for the user input
+ char *buffer = new char[ MAX_PATH ];
+ // try to get user input string
+ if ( el_get_s( buffer, MAX_PATH ) )
+ {
+ // get the string length in 'length'
+ while ( buffer[ *length ] != '\0' )
+ (*length)++;
+ // return the input buffer
+ // remember that this memory has the be free'd somewhere
+ return buffer;
+ }
+ else
+ {
+ // on error
+ delete [] buffer;
+ return NULL;
+ }
+}
+
+int
+el_set (EditLine *el, int code, ...)
+{
+ va_list vl;
+ va_start(vl, code);
+ //
+ switch ( code )
+ {
+ // edit line set prompt message
+ case ( EL_PROMPT ):
+ {
+ // EL_PROMPT, char *(*f)( EditLine *)
+ // define a prompt printing function as 'f', which is to return a string that
+ // contains the prompt.
+
+ // get the function pointer from the arg list
+ void *func_vp = (void*)va_arg(vl, el_prompt_func);
+ // cast to suitable prototype
+ el_prompt_func func_fp = (el_prompt_func)func_vp;
+ // call to get the prompt as a string
+ _prompt = func_fp( el );
+ }
+ break;
+
+ case (EL_PROMPT_ESC) :
+ {
+ // EL_PROMPT, char *(*f)( EditLine *)
+ // define a prompt printing function as 'f', which is to return a string that
+ // contains the prompt.
+
+ // get the function pointer from the arg list
+ void *func_vp = (void*)va_arg(vl, el_prompt_func);
+ va_arg(vl, int);
+ // call to get the prompt as a string
+ el_prompt_func func_fp = (el_prompt_func)func_vp;
+ _prompt = func_fp(el);
+ }
+ break;
+
+ case ( EL_EDITOR ):
+ {
+ // EL_EDITOR, const char *mode
+ // set editing mode to "emacs" or "vi"
+ }
+ break;
+ case ( EL_HIST ):
+ {
+ // EL_HIST, History *(*fun)(History *, int op, ... ), const char *ptr
+ // defines which history function to use, which is usually history(). Ptr should be the
+ // value returned by history_init().
+ }
+ break;
+ case ( EL_ADDFN ):
+ {
+ // EL_ADDFN, const char *name, const char *help, unsigned char (*func)(EditLine *e, int ch)
+ // add a user defined function, func), referred to as 'name' which is invoked when a key which is bound to 'name' is
+ // entered. 'help' is a description of 'name'. at invocation time, 'ch' is the key which caused the invocation. the
+ // return value of 'func()' should be one of:
+ // CC_NORM add a normal character
+ // CC_NEWLINE end of line was entered
+ // CC_EOF EOF was entered
+ // CC_ARGHACK expecting further command input as arguments, do nothing visually.
+ // CC_REFRESH refresh display.
+ // CC_REFRESH_BEEP refresh display and beep.
+ // CC_CURSOR cursor moved so update and perform CC_REFRESH
+ // CC_REDISPLAY redisplay entire input line. this is useful if a key binding outputs extra information.
+ // CC_ERROR an error occurred. beep and flush tty.
+ // CC_FATAL fatal error, reset tty to known state.
+
+ el_binding *binding = new el_binding;
+ binding->name = va_arg( vl, const char *);
+ binding->help = va_arg( vl, const char *);
+ binding->func = va_arg( vl, el_addfn_func );
+ binding->key = 0;
+ // add this to the bindings list
+ _bindings.push_back( binding );
+ }
+ break;
+ case ( EL_BIND ):
+ {
+ // EL_BIND, const char *, ..., NULL
+ // perform the BIND built-in command. Refer to editrc(5) for more information.
+
+ const char *name = va_arg( vl, const char* );
+
+ for ( int i=0; i<_bindings.size(); i++ )
+ {
+ el_binding *bind = _bindings[i];
+ if ( strcmp( bind->name, name ) == 0 )
+ {
+ bind->key = va_arg( vl, const char * );
+ break;
+ }
+ }
+
+ }
+ break;
+ case ( EL_CLIENTDATA ):
+ {
+ clientData = va_arg(vl, void*);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+el_end (EditLine *el)
+{
+ //assert( !"Not implemented!" );
+}
+
+void
+el_reset (EditLine *)
+{
+ assert( !"Not implemented!" );
+}
+
+int
+el_getc (EditLine *, char *)
+{
+ assert( !"Not implemented!" );
+ return 0;
+}
+
+void
+el_push (EditLine *, const char *)
+{
+}
+
+void
+el_beep (EditLine *)
+{
+ Beep( 1000, 500 );
+}
+
+int
+el_parse (EditLine *, int, const char **)
+{
+ assert( !"Not implemented!" );
+ return 0;
+}
+
+int
+el_get (EditLine *el, int code, ...)
+{
+ va_list vl;
+ va_start( vl, code );
+
+ switch ( code )
+ {
+ case ( EL_CLIENTDATA ):
+ {
+ void **dout = va_arg( vl, void** );
+ *dout = clientData;
+ }
+ break;
+ default:
+ assert( !"Not implemented!" );
+ }
+ return 0;
+}
+
+int
+el_source (EditLine *el, const char *file)
+{
+ // init edit line by reading the contents of 'file'
+ // nothing to do here on windows...
+ return 0;
+}
+
+void
+el_resize (EditLine *)
+{
+ assert( !"Not implemented!" );
+}
+
+const LineInfo *
+el_line (EditLine *el)
+{
+ return 0;
+}
+
+int
+el_insertstr (EditLine *, const char *)
+{
+// assert( !"Not implemented!" );
+ return 0;
+}
+
+void
+el_deletestr (EditLine *, int)
+{
+ assert( !"Not implemented!" );
+}
+
+History *
+history_init (void)
+{
+ // return dummy handle
+ return (History*) -1;
+}
+
+void
+history_end (History *)
+{
+// assert( !"Not implemented!" );
+}
+
+int
+history (History *, HistEvent *, int op, ...)
+{
+ // perform operation 'op' on the history list with
+ // optional arguments as needed by the operation.
+ return 0;
+}
+
+#endif
diff --git a/source/Host/windows/FileSystem.cpp b/source/Host/windows/FileSystem.cpp
new file mode 100644
index 000000000000..2cca12b92711
--- /dev/null
+++ b/source/Host/windows/FileSystem.cpp
@@ -0,0 +1,221 @@
+//===-- FileSystem.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/windows/windows.h"
+
+#include <shellapi.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/windows/AutoHandle.h"
+#include "llvm/Support/FileSystem.h"
+
+using namespace lldb_private;
+
+const char *
+FileSystem::DEV_NULL = "nul";
+
+FileSpec::PathSyntax
+FileSystem::GetNativePathSyntax()
+{
+ return FileSpec::ePathSyntaxWindows;
+}
+
+Error
+FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions)
+{
+ // On Win32, the mode parameter is ignored, as Windows files and directories support a
+ // different permission model than POSIX.
+ Error error;
+ const auto err_code = llvm::sys::fs::create_directories(file_spec.GetPath(), true);
+ if (err_code)
+ {
+ error.SetErrorString(err_code.message().c_str());
+ }
+
+ return error;
+}
+
+Error
+FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse)
+{
+ Error error;
+ if (!recurse)
+ {
+ BOOL result = ::RemoveDirectory(file_spec.GetCString());
+ if (!result)
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ }
+ else
+ {
+ // SHFileOperation() accepts a list of paths, and so must be double-null-terminated to
+ // indicate the end of the list.
+ std::string path_buffer{file_spec.GetPath()};
+ path_buffer.push_back(0);
+
+ SHFILEOPSTRUCT shfos = {0};
+ shfos.wFunc = FO_DELETE;
+ shfos.pFrom = path_buffer.c_str();
+ shfos.fFlags = FOF_NO_UI;
+
+ int result = ::SHFileOperation(&shfos);
+ // TODO(zturner): Correctly handle the intricacies of SHFileOperation return values.
+ if (result != 0)
+ error.SetErrorStringWithFormat("SHFileOperation failed");
+ }
+ return error;
+}
+
+Error
+FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions)
+{
+ Error error;
+ // Beware that Windows's permission model is different from Unix's, and it's
+ // not clear if this API is supposed to check ACLs. To match the caller's
+ // expectations as closely as possible, we'll use Microsoft's _stat, which
+ // attempts to emulate POSIX stat. This should be good enough for basic
+ // checks like FileSpec::Readable.
+ struct _stat file_stats;
+ if (::_stat(file_spec.GetCString(), &file_stats) == 0)
+ {
+ // The owner permission bits in "st_mode" currently match the definitions
+ // for the owner file mode bits.
+ file_permissions = file_stats.st_mode & (_S_IREAD | _S_IWRITE | _S_IEXEC);
+ }
+ else
+ {
+ error.SetErrorToErrno();
+ }
+
+ return error;
+}
+
+Error
+FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions)
+{
+ Error error;
+ error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
+ return error;
+}
+
+lldb::user_id_t
+FileSystem::GetFileSize(const FileSpec &file_spec)
+{
+ return file_spec.GetByteSize();
+}
+
+bool
+FileSystem::GetFileExists(const FileSpec &file_spec)
+{
+ return file_spec.Exists();
+}
+
+Error
+FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst)
+{
+ Error error;
+ if (!::CreateHardLink(src.GetCString(), dst.GetCString(), nullptr))
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ return error;
+}
+
+int
+FileSystem::GetHardlinkCount(const FileSpec &file_spec)
+{
+ HANDLE file_handle = ::CreateFile(file_spec.GetCString(),
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ nullptr);
+
+ if (file_handle == INVALID_HANDLE_VALUE)
+ return -1;
+
+ AutoHandle auto_file_handle(file_handle);
+ BY_HANDLE_FILE_INFORMATION file_info;
+ if (::GetFileInformationByHandle(file_handle, &file_info))
+ return file_info.nNumberOfLinks;
+
+ return -1;
+}
+
+Error
+FileSystem::Symlink(const FileSpec &src, const FileSpec &dst)
+{
+ Error error;
+ DWORD attrib = ::GetFileAttributes(dst.GetCString());
+ if (attrib == INVALID_FILE_ATTRIBUTES)
+ {
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ return error;
+ }
+ bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY);
+ DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
+ BOOL result = ::CreateSymbolicLink(src.GetCString(), dst.GetCString(), flag);
+ if (!result)
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ return error;
+}
+
+Error
+FileSystem::Unlink(const FileSpec &file_spec)
+{
+ Error error;
+ BOOL result = ::DeleteFile(file_spec.GetCString());
+ if (!result)
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ return error;
+}
+
+Error
+FileSystem::Readlink(const FileSpec &src, FileSpec &dst)
+{
+ Error error;
+ HANDLE h = ::CreateFile(src.GetCString(), GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ return error;
+ }
+
+ char buf[PATH_MAX];
+ // Subtract 1 from the path length since this function does not add a null terminator.
+ DWORD result = ::GetFinalPathNameByHandle(h, buf, sizeof(buf) - 1,
+ FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+ if (result == 0)
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ else
+ dst.SetFile(buf, false);
+
+ ::CloseHandle(h);
+ return error;
+}
+
+Error
+FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst)
+{
+ return Error("ResolveSymbolicLink() isn't implemented on Windows");
+}
+
+bool
+FileSystem::IsLocal(const FileSpec &spec)
+{
+ if (spec)
+ {
+ // TODO: return true if the file is on a locally mounted file system
+ return true;
+ }
+
+ return false;
+}
diff --git a/source/Host/windows/Host.cpp b/source/Host/windows/Host.cpp
new file mode 100644
index 000000000000..2c9a139df256
--- /dev/null
+++ b/source/Host/windows/Host.cpp
@@ -0,0 +1,326 @@
+//===-- source/Host/windows/Host.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdio.h>
+#include "lldb/Host/windows/windows.h"
+#include "lldb/Host/windows/AutoHandle.h"
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StructuredData.h"
+
+// Windows includes
+#include <TlHelp32.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+ bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple)
+ {
+ // Open the PE File as a binary file, and parse just enough information to determine the
+ // machine type.
+ File imageBinary(
+ executable.GetPath().c_str(),
+ File::eOpenOptionRead,
+ lldb::eFilePermissionsUserRead);
+ imageBinary.SeekFromStart(0x3c);
+ int32_t peOffset = 0;
+ uint32_t peHead = 0;
+ uint16_t machineType = 0;
+ size_t readSize = sizeof(peOffset);
+ imageBinary.Read(&peOffset, readSize);
+ imageBinary.SeekFromStart(peOffset);
+ imageBinary.Read(&peHead, readSize);
+ if (peHead != 0x00004550) // "PE\0\0", little-endian
+ return false; // Error: Can't find PE header
+ readSize = 2;
+ imageBinary.Read(&machineType, readSize);
+ triple.setVendor(llvm::Triple::PC);
+ triple.setOS(llvm::Triple::Win32);
+ triple.setArch(llvm::Triple::UnknownArch);
+ if (machineType == 0x8664)
+ triple.setArch(llvm::Triple::x86_64);
+ else if (machineType == 0x14c)
+ triple.setArch(llvm::Triple::x86);
+
+ return true;
+ }
+
+ bool GetExecutableForProcess(const AutoHandle &handle, std::string &path)
+ {
+ // Get the process image path. MAX_PATH isn't long enough, paths can actually be up to 32KB.
+ std::vector<char> buffer(32768);
+ DWORD dwSize = buffer.size();
+ if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize))
+ return false;
+ path.assign(&buffer[0]);
+ return true;
+ }
+
+ void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
+ {
+ // We may not have permissions to read the path from the process. So start off by
+ // setting the executable file to whatever Toolhelp32 gives us, and then try to
+ // enhance this with more detailed information, but fail gracefully.
+ std::string executable;
+ llvm::Triple triple;
+ triple.setVendor(llvm::Triple::PC);
+ triple.setOS(llvm::Triple::Win32);
+ triple.setArch(llvm::Triple::UnknownArch);
+ if (GetExecutableForProcess(handle, executable))
+ {
+ FileSpec executableFile(executable.c_str(), false);
+ process.SetExecutableFile(executableFile, true);
+ GetTripleForProcess(executableFile, triple);
+ }
+ process.SetArchitecture(ArchSpec(triple));
+
+ // TODO(zturner): Add the ability to get the process user name.
+ }
+}
+
+lldb::DataBufferSP
+Host::GetAuxvData(lldb_private::Process *process)
+{
+ return 0;
+}
+
+lldb::tid_t
+Host::GetCurrentThreadID()
+{
+ return lldb::tid_t(::GetCurrentThreadId());
+}
+
+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);
+}
+
+
+const char *
+Host::GetSignalAsCString(int signo)
+{
+ return NULL;
+}
+
+FileSpec
+Host::GetModuleFileSpecForHostAddress (const void *host_addr)
+{
+ FileSpec module_filespec;
+
+ HMODULE hmodule = NULL;
+ if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule))
+ return module_filespec;
+
+ std::vector<char> buffer(MAX_PATH);
+ DWORD chars_copied = 0;
+ do {
+ chars_copied = ::GetModuleFileName(hmodule, &buffer[0], buffer.size());
+ if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ buffer.resize(buffer.size() * 2);
+ } while (chars_copied >= buffer.size());
+
+ module_filespec.SetFile(&buffer[0], false);
+ return module_filespec;
+}
+
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+ process_infos.Clear();
+
+ AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
+ if (!snapshot.IsValid())
+ return 0;
+
+ PROCESSENTRY32 pe = {0};
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ if (Process32First(snapshot.get(), &pe))
+ {
+ do
+ {
+ AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr);
+
+ ProcessInstanceInfo process;
+ process.SetExecutableFile(FileSpec(pe.szExeFile, false), true);
+ process.SetProcessID(pe.th32ProcessID);
+ process.SetParentProcessID(pe.th32ParentProcessID);
+ GetProcessExecutableAndTriple(handle, process);
+
+ if (match_info.MatchAllProcesses() || match_info.Matches(process))
+ process_infos.Append(process);
+ } while (Process32Next(snapshot.get(), &pe));
+ }
+ return process_infos.GetSize();
+}
+
+bool
+Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.Clear();
+
+ AutoHandle handle(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
+ nullptr);
+ if (!handle.IsValid())
+ return false;
+
+ process_info.SetProcessID(pid);
+ GetProcessExecutableAndTriple(handle, process_info);
+
+ // Need to read the PEB to get parent process and command line arguments.
+ return true;
+}
+
+HostThread
+Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
+{
+ return HostThread();
+}
+
+Error
+Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
+ {
+ FileSpec expand_tool_spec;
+ if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
+ {
+ error.SetErrorString("could not find support executable directory for the lldb-argdumper tool");
+ return error;
+ }
+ expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
+ if (!expand_tool_spec.Exists())
+ {
+ error.SetErrorString("could not find the lldb-argdumper tool");
+ return error;
+ }
+
+ std::string quoted_cmd_string;
+ launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
+ std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
+ StreamString expand_command;
+
+ expand_command.Printf("\"%s\" %s",
+ expand_tool_spec.GetPath().c_str(),
+ quoted_cmd_string.c_str());
+
+ int status;
+ std::string output;
+ RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), &status, nullptr, &output, 10);
+
+ if (status != 0)
+ {
+ error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", status);
+ return error;
+ }
+
+ auto data_sp = StructuredData::ParseJSON(output);
+ if (!data_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto dict_sp = data_sp->GetAsDictionary();
+ if (!data_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
+ if (!args_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto args_array_sp = args_sp->GetAsArray();
+ if (!args_array_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ launch_info.GetArguments().Clear();
+
+ for (size_t i = 0;
+ i < args_array_sp->GetSize();
+ i++)
+ {
+ auto item_sp = args_array_sp->GetItemAtIndex(i);
+ if (!item_sp)
+ continue;
+ auto str_sp = item_sp->GetAsString();
+ if (!str_sp)
+ continue;
+
+ launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
+ }
+ }
+
+ return error;
+}
+
+size_t
+Host::GetEnvironment(StringList &env)
+{
+ // The environment block on Windows is a contiguous buffer of NULL terminated strings,
+ // where the end of the environment block is indicated by two consecutive NULLs.
+ LPCH environment_block = ::GetEnvironmentStrings();
+ env.Clear();
+ while (*environment_block != '\0')
+ {
+ llvm::StringRef current_var(environment_block);
+ if (current_var[0] != '=')
+ env.AppendString(current_var);
+
+ environment_block += current_var.size()+1;
+ }
+ return env.GetSize();
+}
diff --git a/source/Host/windows/HostInfoWindows.cpp b/source/Host/windows/HostInfoWindows.cpp
new file mode 100644
index 000000000000..6dce71d9172a
--- /dev/null
+++ b/source/Host/windows/HostInfoWindows.cpp
@@ -0,0 +1,118 @@
+//===-- HostInfoWindows.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/windows/windows.h"
+
+#include <mutex> // std::once
+
+#include "lldb/Host/windows/HostInfoWindows.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Path.h"
+
+using namespace lldb_private;
+
+FileSpec HostInfoWindows::m_program_filespec;
+
+size_t
+HostInfoWindows::GetPageSize()
+{
+ SYSTEM_INFO systemInfo;
+ GetNativeSystemInfo(&systemInfo);
+ return systemInfo.dwPageSize;
+}
+
+bool
+HostInfoWindows::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update)
+{
+ OSVERSIONINFOEX info;
+
+ ZeroMemory(&info, sizeof(OSVERSIONINFOEX));
+ info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+#pragma warning(push)
+#pragma warning(disable : 4996)
+ // Starting with Microsoft SDK for Windows 8.1, this function is deprecated in favor of the
+ // new Windows Version Helper APIs. Since we don't specify a minimum SDK version, it's easier
+ // to simply disable the warning rather than try to support both APIs.
+ if (GetVersionEx((LPOSVERSIONINFO)&info) == 0)
+ {
+ return false;
+ }
+#pragma warning(pop)
+
+ major = info.dwMajorVersion;
+ minor = info.dwMinorVersion;
+ update = info.wServicePackMajor;
+
+ return true;
+}
+
+bool
+HostInfoWindows::GetOSBuildString(std::string &s)
+{
+ s.clear();
+ uint32_t major, minor, update;
+ if (!GetOSVersion(major, minor, update))
+ return false;
+
+ llvm::raw_string_ostream stream(s);
+ stream << "Windows NT " << major << "." << minor << "." << update;
+ return true;
+}
+
+bool
+HostInfoWindows::GetOSKernelDescription(std::string &s)
+{
+ return GetOSBuildString(s);
+}
+
+bool
+HostInfoWindows::GetHostname(std::string &s)
+{
+ char buffer[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
+ if (!::GetComputerName(buffer, &dwSize))
+ return false;
+
+ s.assign(buffer, buffer + dwSize);
+ return true;
+}
+
+FileSpec
+HostInfoWindows::GetProgramFileSpec()
+{
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+ char buffer[PATH_MAX];
+ ::GetModuleFileName(NULL, buffer, sizeof(buffer));
+ m_program_filespec.SetFile(buffer, false);
+ });
+ return m_program_filespec;
+}
+
+FileSpec
+HostInfoWindows::GetDefaultShell()
+{
+ return FileSpec(::getenv("ComSpec"), false);
+}
+
+bool
+HostInfoWindows::ComputePythonDirectory(FileSpec &file_spec)
+{
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+ llvm::SmallString<64> path(lldb_file_spec.GetDirectory().AsCString());
+ llvm::sys::path::remove_filename(path);
+ llvm::sys::path::append(path, "lib", "site-packages");
+ std::replace(path.begin(), path.end(), '\\', '/');
+ file_spec.GetDirectory().SetString(path.c_str());
+ return true;
+}
diff --git a/source/Host/windows/HostProcessWindows.cpp b/source/Host/windows/HostProcessWindows.cpp
new file mode 100644
index 000000000000..0f81c18d34af
--- /dev/null
+++ b/source/Host/windows/HostProcessWindows.cpp
@@ -0,0 +1,137 @@
+//===-- HostProcessWindows.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/FileSpec.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/windows/windows.h"
+#include "lldb/Host/windows/HostProcessWindows.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+#include <Psapi.h>
+
+using namespace lldb_private;
+
+namespace
+{
+struct MonitorInfo
+{
+ HostProcess::MonitorCallback callback;
+ void *baton;
+ HANDLE process_handle;
+};
+}
+
+HostProcessWindows::HostProcessWindows()
+ : HostNativeProcessBase()
+ , m_owns_handle(true)
+{
+}
+
+HostProcessWindows::HostProcessWindows(lldb::process_t process)
+ : HostNativeProcessBase(process)
+ , m_owns_handle(true)
+{
+}
+
+HostProcessWindows::~HostProcessWindows()
+{
+ Close();
+}
+
+void
+HostProcessWindows::SetOwnsHandle(bool owns)
+{
+ m_owns_handle = owns;
+}
+
+Error HostProcessWindows::Terminate()
+{
+ Error error;
+ if (m_process == nullptr)
+ error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32);
+
+ if (!::TerminateProcess(m_process, 0))
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+
+ return error;
+}
+
+Error HostProcessWindows::GetMainModule(FileSpec &file_spec) const
+{
+ Error error;
+ if (m_process == nullptr)
+ error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32);
+
+ char path[MAX_PATH] = { 0 };
+ if (::GetProcessImageFileName(m_process, path, llvm::array_lengthof(path)))
+ file_spec.SetFile(path, false);
+ else
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+
+ return error;
+}
+
+lldb::pid_t HostProcessWindows::GetProcessId() const
+{
+ return (m_process == LLDB_INVALID_PROCESS) ? -1 : ::GetProcessId(m_process);
+}
+
+bool HostProcessWindows::IsRunning() const
+{
+ if (m_process == nullptr)
+ return false;
+
+ DWORD code = 0;
+ if (!::GetExitCodeProcess(m_process, &code))
+ return false;
+
+ return (code == STILL_ACTIVE);
+}
+
+HostThread
+HostProcessWindows::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals)
+{
+ HostThread monitor_thread;
+ MonitorInfo *info = new MonitorInfo;
+ info->callback = callback;
+ info->baton = callback_baton;
+
+ // Since the life of this HostProcessWindows instance and the life of the process may be different, duplicate the handle so that
+ // the monitor thread can have ownership over its own copy of the handle.
+ HostThread result;
+ if (::DuplicateHandle(GetCurrentProcess(), m_process, GetCurrentProcess(), &info->process_handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
+ result = ThreadLauncher::LaunchThread("ChildProcessMonitor", HostProcessWindows::MonitorThread, info, nullptr);
+ return result;
+}
+
+lldb::thread_result_t
+HostProcessWindows::MonitorThread(void *thread_arg)
+{
+ DWORD exit_code;
+
+ MonitorInfo *info = static_cast<MonitorInfo *>(thread_arg);
+ if (info)
+ {
+ ::WaitForSingleObject(info->process_handle, INFINITE);
+ ::GetExitCodeProcess(info->process_handle, &exit_code);
+ info->callback(info->baton, ::GetProcessId(info->process_handle), true, 0, exit_code);
+ ::CloseHandle(info->process_handle);
+ delete (info);
+ }
+ return 0;
+}
+
+void HostProcessWindows::Close()
+{
+ if (m_owns_handle && m_process != LLDB_INVALID_PROCESS)
+ ::CloseHandle(m_process);
+ m_process = nullptr;
+}
diff --git a/source/Host/windows/HostThreadWindows.cpp b/source/Host/windows/HostThreadWindows.cpp
new file mode 100644
index 000000000000..d59064fb1c15
--- /dev/null
+++ b/source/Host/windows/HostThreadWindows.cpp
@@ -0,0 +1,98 @@
+//===-- HostThreadWindows.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/Core/Error.h"
+
+#include "lldb/Host/windows/windows.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+void __stdcall ExitThreadProxy(ULONG_PTR dwExitCode)
+{
+ ::ExitThread(dwExitCode);
+}
+}
+
+HostThreadWindows::HostThreadWindows()
+ : HostNativeThreadBase()
+ , m_owns_handle(true)
+{
+}
+
+HostThreadWindows::HostThreadWindows(lldb::thread_t thread)
+ : HostNativeThreadBase(thread)
+ , m_owns_handle(true)
+{
+}
+
+HostThreadWindows::~HostThreadWindows()
+{
+ Reset();
+}
+
+void
+HostThreadWindows::SetOwnsHandle(bool owns)
+{
+ m_owns_handle = owns;
+}
+
+Error
+HostThreadWindows::Join(lldb::thread_result_t *result)
+{
+ Error error;
+ if (IsJoinable())
+ {
+ DWORD wait_result = ::WaitForSingleObject(m_thread, INFINITE);
+ if (WAIT_OBJECT_0 == wait_result && result)
+ {
+ DWORD exit_code = 0;
+ if (!::GetExitCodeThread(m_thread, &exit_code))
+ *result = 0;
+ *result = exit_code;
+ }
+ else if (WAIT_OBJECT_0 != wait_result)
+ error.SetError(::GetLastError(), eErrorTypeWin32);
+ }
+ else
+ error.SetError(ERROR_INVALID_HANDLE, eErrorTypeWin32);
+
+ Reset ();
+ return error;
+}
+
+Error
+HostThreadWindows::Cancel()
+{
+ Error error;
+
+ DWORD result = ::QueueUserAPC(::ExitThreadProxy, m_thread, 0);
+ error.SetError(result, eErrorTypeWin32);
+ return error;
+}
+
+lldb::tid_t
+HostThreadWindows::GetThreadId() const
+{
+ return ::GetThreadId(m_thread);
+}
+
+void
+HostThreadWindows::Reset()
+{
+ if (m_owns_handle && m_thread != LLDB_INVALID_HOST_THREAD)
+ ::CloseHandle(m_thread);
+
+ HostNativeThreadBase::Reset();
+}
diff --git a/source/Host/windows/LockFileWindows.cpp b/source/Host/windows/LockFileWindows.cpp
new file mode 100644
index 000000000000..161d3dbd8260
--- /dev/null
+++ b/source/Host/windows/LockFileWindows.cpp
@@ -0,0 +1,93 @@
+//===-- LockFileWindows.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/windows/LockFileWindows.h"
+
+#include <io.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+
+Error fileLock (HANDLE file_handle, DWORD flags, const uint64_t start, const uint64_t len)
+{
+ if (start != 0)
+ return Error ("Non-zero start lock regions are not supported");
+
+ OVERLAPPED overlapped = {0};
+
+ if (!::LockFileEx (file_handle, flags, 0, len, 0, &overlapped) && ::GetLastError () != ERROR_IO_PENDING)
+ return Error (::GetLastError (), eErrorTypeWin32);
+
+ DWORD bytes;
+ if (!::GetOverlappedResult (file_handle, &overlapped, &bytes, TRUE))
+ return Error (::GetLastError (), eErrorTypeWin32);
+
+ return Error ();
+}
+
+} // namespace
+
+LockFileWindows::LockFileWindows (int fd)
+ : LockFileBase (fd),
+ m_file (reinterpret_cast<HANDLE> (_get_osfhandle (fd)))
+{
+}
+
+LockFileWindows::~LockFileWindows ()
+{
+ Unlock ();
+}
+
+bool
+LockFileWindows::IsValidFile () const
+{
+ return LockFileBase::IsValidFile() && m_file != INVALID_HANDLE_VALUE;
+}
+
+Error
+LockFileWindows::DoWriteLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_file, LOCKFILE_EXCLUSIVE_LOCK, start, len);
+}
+
+Error
+LockFileWindows::DoTryWriteLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_file, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, start, len);
+}
+
+Error
+LockFileWindows::DoReadLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_file, 0, start, len);
+}
+
+Error
+LockFileWindows::DoTryReadLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_file, LOCKFILE_FAIL_IMMEDIATELY, start, len);
+}
+
+Error
+LockFileWindows::DoUnlock ()
+{
+ OVERLAPPED overlapped = {0};
+
+ if (!::UnlockFileEx (m_file, 0, m_len, 0, &overlapped) && ::GetLastError () != ERROR_IO_PENDING)
+ return Error (::GetLastError (), eErrorTypeWin32);
+
+ DWORD bytes;
+ if (!::GetOverlappedResult (m_file, &overlapped, &bytes, TRUE))
+ return Error (::GetLastError (), eErrorTypeWin32);
+
+ return Error ();
+}
diff --git a/source/Host/windows/Mutex.cpp b/source/Host/windows/Mutex.cpp
new file mode 100644
index 000000000000..ed90f46eb54b
--- /dev/null
+++ b/source/Host/windows/Mutex.cpp
@@ -0,0 +1,109 @@
+//===-- Mutex.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/Mutex.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/windows/windows.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#if 0
+// This logging is way too verbose to enable even for a log channel.
+// This logging can be enabled by changing the "#if 0", but should be
+// reverted prior to checking in.
+#include <cstdio>
+#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_LOG(fmt, ...)
+#endif
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor.
+//
+// Creates a pthread mutex with no attributes.
+//----------------------------------------------------------------------
+Mutex::Mutex () :
+ m_mutex()
+{
+ m_mutex = static_cast<PCRITICAL_SECTION>(malloc(sizeof(CRITICAL_SECTION)));
+ InitializeCriticalSection(static_cast<PCRITICAL_SECTION>(m_mutex));
+}
+
+//----------------------------------------------------------------------
+// Default constructor.
+//
+// Creates a pthread mutex with "type" as the mutex type.
+//----------------------------------------------------------------------
+Mutex::Mutex (Mutex::Type type) :
+ m_mutex()
+{
+ m_mutex = static_cast<PCRITICAL_SECTION>(malloc(sizeof(CRITICAL_SECTION)));
+ InitializeCriticalSection(static_cast<PCRITICAL_SECTION>(m_mutex));
+}
+
+//----------------------------------------------------------------------
+// Destructor.
+//
+// Destroys the mutex owned by this object.
+//----------------------------------------------------------------------
+Mutex::~Mutex()
+{
+ DeleteCriticalSection(static_cast<PCRITICAL_SECTION>(m_mutex));
+ free(m_mutex);
+}
+
+//----------------------------------------------------------------------
+// Locks the mutex owned by this object, if the mutex is already
+// locked, the calling thread will block until the mutex becomes
+// available.
+//
+// RETURNS
+// The error code from the pthread_mutex_lock() function call.
+//----------------------------------------------------------------------
+int
+Mutex::Lock()
+{
+ DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p)...\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_mutex);
+
+ EnterCriticalSection(static_cast<PCRITICAL_SECTION>(m_mutex));
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Attempts to lock the mutex owned by this object without blocking.
+// If the mutex is already locked, TryLock() will not block waiting
+// for the mutex, but will return an error condition.
+//
+// RETURNS
+// The error code from the pthread_mutex_trylock() function call.
+//----------------------------------------------------------------------
+int
+Mutex::TryLock(const char *failure_message)
+{
+ return TryEnterCriticalSection(static_cast<PCRITICAL_SECTION>(m_mutex)) == 0;
+}
+
+//----------------------------------------------------------------------
+// If the current thread holds the lock on the owned mutex, then
+// Unlock() will unlock the mutex. Calling Unlock() on this object
+// that the calling thread does not hold will result in undefined
+// behavior.
+//
+// RETURNS
+// The error code from the pthread_mutex_unlock() function call.
+//----------------------------------------------------------------------
+int
+Mutex::Unlock()
+{
+ LeaveCriticalSection(static_cast<PCRITICAL_SECTION>(m_mutex));
+ return 0;
+}
diff --git a/source/Host/windows/PipeWindows.cpp b/source/Host/windows/PipeWindows.cpp
new file mode 100644
index 000000000000..d4afd6e74943
--- /dev/null
+++ b/source/Host/windows/PipeWindows.cpp
@@ -0,0 +1,336 @@
+//===-- PipeWindows.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/windows/PipeWindows.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <fcntl.h>
+#include <io.h>
+#include <rpc.h>
+
+#include <atomic>
+#include <string>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+std::atomic<uint32_t> g_pipe_serial(0);
+}
+
+PipeWindows::PipeWindows()
+{
+ m_read = INVALID_HANDLE_VALUE;
+ m_write = INVALID_HANDLE_VALUE;
+
+ m_read_fd = -1;
+ m_write_fd = -1;
+ ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
+ ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
+}
+
+PipeWindows::~PipeWindows()
+{
+ Close();
+}
+
+Error
+PipeWindows::CreateNew(bool child_process_inherit)
+{
+ // Even for anonymous pipes, we open a named pipe. This is because you cannot get
+ // overlapped i/o on Windows without using a named pipe. So we synthesize a unique
+ // name.
+ uint32_t serial = g_pipe_serial.fetch_add(1);
+ std::string pipe_name;
+ llvm::raw_string_ostream pipe_name_stream(pipe_name);
+ pipe_name_stream << "lldb.pipe." << ::GetCurrentProcessId() << "." << serial;
+ pipe_name_stream.flush();
+
+ return CreateNew(pipe_name.c_str(), child_process_inherit);
+}
+
+Error
+PipeWindows::CreateNew(llvm::StringRef name, bool child_process_inherit)
+{
+ if (name.empty())
+ return Error(ERROR_INVALID_PARAMETER, eErrorTypeWin32);
+
+ if (CanRead() || CanWrite())
+ return Error(ERROR_ALREADY_EXISTS, eErrorTypeWin32);
+
+ std::string pipe_path = "\\\\.\\Pipe\\";
+ pipe_path.append(name);
+
+ // Always open for overlapped i/o. We implement blocking manually in Read and Write.
+ DWORD read_mode = FILE_FLAG_OVERLAPPED;
+ m_read =
+ ::CreateNamedPipe(pipe_path.c_str(), PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024, 120 * 1000, NULL);
+ if (INVALID_HANDLE_VALUE == m_read)
+ return Error(::GetLastError(), eErrorTypeWin32);
+ m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);
+ ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
+ m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
+
+ // Open the write end of the pipe.
+ Error result = OpenNamedPipe(name, child_process_inherit, false);
+ if (!result.Success())
+ {
+ CloseReadFileDescriptor();
+ return result;
+ }
+
+ return result;
+}
+
+Error
+PipeWindows::CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit, llvm::SmallVectorImpl<char>& name)
+{
+ llvm::SmallString<128> pipe_name;
+ Error error;
+ ::UUID unique_id;
+ RPC_CSTR unique_string;
+ RPC_STATUS status = ::UuidCreate(&unique_id);
+ if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
+ status = ::UuidToStringA(&unique_id, &unique_string);
+ if (status == RPC_S_OK)
+ {
+ pipe_name = prefix;
+ pipe_name += "-";
+ pipe_name += reinterpret_cast<char *>(unique_string);
+ ::RpcStringFreeA(&unique_string);
+ error = CreateNew(pipe_name, child_process_inherit);
+ }
+ else
+ {
+ error.SetError(status, eErrorTypeWin32);
+ }
+ if (error.Success())
+ name = pipe_name;
+ return error;
+}
+
+Error
+PipeWindows::OpenAsReader(llvm::StringRef name, bool child_process_inherit)
+{
+ if (CanRead() || CanWrite())
+ return Error(ERROR_ALREADY_EXISTS, eErrorTypeWin32);
+
+ return OpenNamedPipe(name, child_process_inherit, true);
+}
+
+Error
+PipeWindows::OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, const std::chrono::microseconds &timeout)
+{
+ if (CanRead() || CanWrite())
+ return Error(ERROR_ALREADY_EXISTS, eErrorTypeWin32);
+
+ return OpenNamedPipe(name, child_process_inherit, false);
+}
+
+Error
+PipeWindows::OpenNamedPipe(llvm::StringRef name, bool child_process_inherit, bool is_read)
+{
+ if (name.empty())
+ return Error(ERROR_INVALID_PARAMETER, eErrorTypeWin32);
+
+ assert(is_read ? !CanRead() : !CanWrite());
+
+ SECURITY_ATTRIBUTES attributes = {0};
+ attributes.bInheritHandle = child_process_inherit;
+
+ std::string pipe_path = "\\\\.\\Pipe\\";
+ pipe_path.append(name);
+
+ if (is_read)
+ {
+ m_read = ::CreateFile(pipe_path.c_str(), GENERIC_READ, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+ if (INVALID_HANDLE_VALUE == m_read)
+ return Error(::GetLastError(), eErrorTypeWin32);
+
+ m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);
+
+ ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
+ m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ }
+ else
+ {
+ m_write = ::CreateFile(pipe_path.c_str(), GENERIC_WRITE, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+ if (INVALID_HANDLE_VALUE == m_write)
+ return Error(::GetLastError(), eErrorTypeWin32);
+
+ m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY);
+
+ ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
+ }
+
+ return Error();
+}
+
+int
+PipeWindows::GetReadFileDescriptor() const
+{
+ return m_read_fd;
+}
+
+int
+PipeWindows::GetWriteFileDescriptor() const
+{
+ return m_write_fd;
+}
+
+int
+PipeWindows::ReleaseReadFileDescriptor()
+{
+ if (!CanRead())
+ return -1;
+ int result = m_read_fd;
+ m_read_fd = -1;
+ if (m_read_overlapped.hEvent)
+ ::CloseHandle(m_read_overlapped.hEvent);
+ m_read = INVALID_HANDLE_VALUE;
+ ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
+ return result;
+}
+
+int
+PipeWindows::ReleaseWriteFileDescriptor()
+{
+ if (!CanWrite())
+ return -1;
+ int result = m_write_fd;
+ m_write_fd = -1;
+ m_write = INVALID_HANDLE_VALUE;
+ ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
+ return result;
+}
+
+void
+PipeWindows::CloseReadFileDescriptor()
+{
+ if (!CanRead())
+ return;
+
+ if (m_read_overlapped.hEvent)
+ ::CloseHandle(m_read_overlapped.hEvent);
+ _close(m_read_fd);
+ m_read = INVALID_HANDLE_VALUE;
+ m_read_fd = -1;
+ ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
+}
+
+void
+PipeWindows::CloseWriteFileDescriptor()
+{
+ if (!CanWrite())
+ return;
+
+ _close(m_write_fd);
+ m_write = INVALID_HANDLE_VALUE;
+ m_write_fd = -1;
+ ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
+}
+
+void
+PipeWindows::Close()
+{
+ CloseReadFileDescriptor();
+ CloseWriteFileDescriptor();
+}
+
+Error
+PipeWindows::Delete(llvm::StringRef name)
+{
+ return Error();
+}
+
+bool
+PipeWindows::CanRead() const
+{
+ return (m_read != INVALID_HANDLE_VALUE);
+}
+
+bool
+PipeWindows::CanWrite() const
+{
+ return (m_write != INVALID_HANDLE_VALUE);
+}
+
+HANDLE
+PipeWindows::GetReadNativeHandle()
+{
+ return m_read;
+}
+
+HANDLE
+PipeWindows::GetWriteNativeHandle()
+{
+ return m_write;
+}
+
+Error
+PipeWindows::ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &duration, size_t &bytes_read)
+{
+ if (!CanRead())
+ return Error(ERROR_INVALID_HANDLE, eErrorTypeWin32);
+
+ bytes_read = 0;
+ DWORD sys_bytes_read = size;
+ BOOL result = ::ReadFile(m_read, buf, sys_bytes_read, &sys_bytes_read, &m_read_overlapped);
+ if (!result && GetLastError() != ERROR_IO_PENDING)
+ return Error(::GetLastError(), eErrorTypeWin32);
+
+ DWORD timeout = (duration == std::chrono::microseconds::zero()) ? INFINITE : duration.count() * 1000;
+ DWORD wait_result = ::WaitForSingleObject(m_read_overlapped.hEvent, timeout);
+ if (wait_result != WAIT_OBJECT_0)
+ {
+ // The operation probably failed. However, if it timed out, we need to cancel the I/O.
+ // Between the time we returned from WaitForSingleObject and the time we call CancelIoEx,
+ // the operation may complete. If that hapens, CancelIoEx will fail and return ERROR_NOT_FOUND.
+ // If that happens, the original operation should be considered to have been successful.
+ bool failed = true;
+ DWORD failure_error = ::GetLastError();
+ if (wait_result == WAIT_TIMEOUT)
+ {
+ BOOL cancel_result = CancelIoEx(m_read, &m_read_overlapped);
+ if (!cancel_result && GetLastError() == ERROR_NOT_FOUND)
+ failed = false;
+ }
+ if (failed)
+ return Error(failure_error, eErrorTypeWin32);
+ }
+
+ // Now we call GetOverlappedResult setting bWait to false, since we've already waited
+ // as long as we're willing to.
+ if (!GetOverlappedResult(m_read, &m_read_overlapped, &sys_bytes_read, FALSE))
+ return Error(::GetLastError(), eErrorTypeWin32);
+
+ bytes_read = sys_bytes_read;
+ return Error();
+}
+
+Error
+PipeWindows::Write(const void *buf, size_t num_bytes, size_t &bytes_written)
+{
+ if (!CanWrite())
+ return Error(ERROR_INVALID_HANDLE, eErrorTypeWin32);
+
+ DWORD sys_bytes_written = 0;
+ BOOL write_result = ::WriteFile(m_write, buf, num_bytes, &sys_bytes_written, &m_write_overlapped);
+ if (!write_result && GetLastError() != ERROR_IO_PENDING)
+ return Error(::GetLastError(), eErrorTypeWin32);
+
+ BOOL result = GetOverlappedResult(m_write, &m_write_overlapped, &sys_bytes_written, TRUE);
+ if (!result)
+ return Error(::GetLastError(), eErrorTypeWin32);
+ return Error();
+}
diff --git a/source/Host/windows/ProcessLauncherWindows.cpp b/source/Host/windows/ProcessLauncherWindows.cpp
new file mode 100644
index 000000000000..355dd40544f9
--- /dev/null
+++ b/source/Host/windows/ProcessLauncherWindows.cpp
@@ -0,0 +1,105 @@
+//===-- ProcessLauncherWindows.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/HostProcess.h"
+#include "lldb/Host/windows/ProcessLauncherWindows.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+
+#include <string>
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostProcess
+ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error)
+{
+ error.Clear();
+
+ std::string executable;
+ std::string commandLine;
+ std::vector<char> environment;
+ STARTUPINFO startupinfo = {0};
+ PROCESS_INFORMATION pi = {0};
+
+ HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO);
+ HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO);
+ HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO);
+
+ startupinfo.cb = sizeof(startupinfo);
+ startupinfo.dwFlags |= STARTF_USESTDHANDLES;
+ startupinfo.hStdError = stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE);
+ startupinfo.hStdInput = stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE);
+ startupinfo.hStdOutput = stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE);
+
+ const char *hide_console_var = getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
+ if (hide_console_var && llvm::StringRef(hide_console_var).equals_lower("true"))
+ {
+ startupinfo.dwFlags |= STARTF_USESHOWWINDOW;
+ startupinfo.wShowWindow = SW_HIDE;
+ }
+
+ DWORD flags = CREATE_NEW_CONSOLE;
+ if (launch_info.GetFlags().Test(eLaunchFlagDebug))
+ flags |= DEBUG_ONLY_THIS_PROCESS;
+
+ executable = launch_info.GetExecutableFile().GetPath();
+ launch_info.GetArguments().GetQuotedCommandString(commandLine);
+ BOOL result = ::CreateProcessA(executable.c_str(), const_cast<char *>(commandLine.c_str()), NULL, NULL, TRUE, flags, NULL,
+ launch_info.GetWorkingDirectory().GetCString(), &startupinfo, &pi);
+ if (result)
+ {
+ // Do not call CloseHandle on pi.hProcess, since we want to pass that back through the HostProcess.
+ ::CloseHandle(pi.hThread);
+ }
+
+ if (stdin_handle)
+ ::CloseHandle(stdin_handle);
+ if (stdout_handle)
+ ::CloseHandle(stdout_handle);
+ if (stderr_handle)
+ ::CloseHandle(stderr_handle);
+
+ if (!result)
+ error.SetError(::GetLastError(), eErrorTypeWin32);
+ return HostProcess(pi.hProcess);
+}
+
+HANDLE
+ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd)
+{
+ const FileAction *action = launch_info.GetFileActionForFD(fd);
+ if (action == nullptr)
+ return NULL;
+ SECURITY_ATTRIBUTES secattr = {0};
+ secattr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ secattr.bInheritHandle = TRUE;
+
+ const char *path = action->GetPath();
+ DWORD access = 0;
+ DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ DWORD create = 0;
+ DWORD flags = 0;
+ if (fd == STDIN_FILENO)
+ {
+ access = GENERIC_READ;
+ create = OPEN_EXISTING;
+ flags = FILE_ATTRIBUTE_READONLY;
+ }
+ if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
+ {
+ access = GENERIC_WRITE;
+ create = CREATE_ALWAYS;
+ if (fd == STDERR_FILENO)
+ flags = FILE_FLAG_WRITE_THROUGH;
+ }
+
+ HANDLE result = ::CreateFile(path, access, share, &secattr, create, flags, NULL);
+ return (result == INVALID_HANDLE_VALUE) ? NULL : result;
+}
diff --git a/source/Host/windows/ProcessRunLock.cpp b/source/Host/windows/ProcessRunLock.cpp
new file mode 100644
index 000000000000..1f21552a3062
--- /dev/null
+++ b/source/Host/windows/ProcessRunLock.cpp
@@ -0,0 +1,106 @@
+#include "lldb/Host/ProcessRunLock.h"
+#include "lldb/Host/windows/windows.h"
+
+namespace
+{
+#if defined(__MINGW32__)
+// Taken from WinNT.h
+typedef struct _RTL_SRWLOCK {
+ PVOID Ptr;
+} RTL_SRWLOCK, *PRTL_SRWLOCK;
+
+// Taken from WinBase.h
+typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
+#endif
+}
+
+
+static PSRWLOCK GetLock(lldb::rwlock_t lock)
+{
+ return static_cast<PSRWLOCK>(lock);
+}
+
+static bool ReadLock(lldb::rwlock_t rwlock)
+{
+ ::AcquireSRWLockShared(GetLock(rwlock));
+ return true;
+}
+
+static bool ReadUnlock(lldb::rwlock_t rwlock)
+{
+ ::ReleaseSRWLockShared(GetLock(rwlock));
+ return true;
+}
+
+static bool WriteLock(lldb::rwlock_t rwlock)
+{
+ ::AcquireSRWLockExclusive(GetLock(rwlock));
+ return true;
+}
+
+static bool WriteTryLock(lldb::rwlock_t rwlock)
+{
+ return !!::TryAcquireSRWLockExclusive(GetLock(rwlock));
+}
+
+static bool WriteUnlock(lldb::rwlock_t rwlock)
+{
+ ::ReleaseSRWLockExclusive(GetLock(rwlock));
+ return true;
+}
+
+using namespace lldb_private;
+
+ProcessRunLock::ProcessRunLock()
+ : m_running(false)
+{
+ m_rwlock = new SRWLOCK;
+ InitializeSRWLock(GetLock(m_rwlock));
+}
+
+ProcessRunLock::~ProcessRunLock()
+{
+ delete m_rwlock;
+}
+
+bool ProcessRunLock::ReadTryLock()
+{
+ ::ReadLock(m_rwlock);
+ if (m_running == false)
+ return true;
+ ::ReadUnlock(m_rwlock);
+ return false;
+}
+
+bool ProcessRunLock::ReadUnlock()
+{
+ return ::ReadUnlock(m_rwlock);
+}
+
+bool ProcessRunLock::SetRunning ()
+{
+ WriteLock(m_rwlock);
+ m_running = true;
+ WriteUnlock(m_rwlock);
+ return true;
+}
+
+bool ProcessRunLock::TrySetRunning ()
+{
+ if (WriteTryLock(m_rwlock))
+ {
+ bool was_running = m_running;
+ m_running = true;
+ WriteUnlock(m_rwlock);
+ return !was_running;
+ }
+ return false;
+}
+
+bool ProcessRunLock::SetStopped ()
+{
+ WriteLock(m_rwlock);
+ m_running = false;
+ WriteUnlock(m_rwlock);
+ return true;
+}
diff --git a/source/Host/windows/ThisThread.cpp b/source/Host/windows/ThisThread.cpp
new file mode 100644
index 000000000000..bcd5b8d1c1d0
--- /dev/null
+++ b/source/Host/windows/ThisThread.cpp
@@ -0,0 +1,66 @@
+//===-- ThisThread.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/Core/Error.h"
+
+#include "lldb/Host/windows/windows.h"
+#include "lldb/Host/ThisThread.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#if defined(_MSC_VER) && !defined(__clang__)
+
+namespace
+{
+static const DWORD MS_VC_EXCEPTION = 0x406D1388;
+
+#pragma pack(push, 8)
+struct THREADNAME_INFO
+{
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to thread name
+ DWORD dwThreadId; // Thread ID (-1 == current thread)
+ DWORD dwFlags; // Reserved. Do not use.
+};
+#pragma pack(pop)
+}
+
+#endif
+
+void
+ThisThread::SetName(llvm::StringRef name)
+{
+// Other compilers don't yet support SEH, so we can only set the thread if compiling with MSVC.
+// TODO(zturner): Once clang-cl supports SEH, relax this conditional.
+#if defined(_MSC_VER) && !defined(__clang__)
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = name.data();
+ info.dwThreadId = ::GetCurrentThreadId();
+ info.dwFlags = 0;
+
+ __try {
+ ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER) {}
+#endif
+}
+
+void
+ThisThread::GetName(llvm::SmallVectorImpl<char> &name)
+{
+ // Getting the thread name is not supported on Windows.
+ // TODO(zturner): In SetName(), make a TLS entry that contains the thread's name, and in this function
+ // try to extract that TLS entry.
+ name.clear();
+}
diff --git a/source/Host/windows/Windows.cpp b/source/Host/windows/Windows.cpp
new file mode 100644
index 000000000000..71bff7a9d2e2
--- /dev/null
+++ b/source/Host/windows/Windows.cpp
@@ -0,0 +1,231 @@
+//===-- Windows.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This file provides Windows support functions
+
+#include "lldb/Host/windows/windows.h"
+#include "lldb/Host/windows/win32.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <io.h>
+#include <cerrno>
+#include <ctype.h>
+
+// These prototypes are defined in <direct.h>, but it also defines chdir() and getcwd(), giving multiply defined errors
+extern "C"
+{
+ char *_getcwd(char *buffer, int maxlen);
+ int _chdir(const char *path);
+}
+
+int vasprintf(char **ret, const char *fmt, va_list ap)
+{
+ char *buf;
+ int len;
+ size_t buflen;
+ va_list ap2;
+
+#if defined(_MSC_VER) || defined(__MINGW64)
+ ap2 = ap;
+ len = _vscprintf(fmt, ap2);
+#else
+ va_copy(ap2, ap);
+ len = vsnprintf(NULL, 0, fmt, ap2);
+#endif
+
+ if (len >= 0 && (buf = (char*) malloc ((buflen = (size_t) (len + 1)))) != NULL) {
+ len = vsnprintf(buf, buflen, fmt, ap);
+ *ret = buf;
+ } else {
+ *ret = NULL;
+ len = -1;
+ }
+
+ va_end(ap2);
+ return len;
+}
+
+char* strcasestr(const char *s, const char* find)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != 0) {
+ c = tolower((unsigned char) c);
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == 0)
+ return 0;
+ } while ((char) tolower((unsigned char) sc) != c);
+ } while (strncasecmp(s, find, len) != 0);
+ s--;
+ }
+ return ((char *) s);
+}
+
+char* realpath(const char * name, char * resolved)
+{
+ char *retname = NULL; /* we will return this, if we fail */
+
+ /* SUSv3 says we must set `errno = EINVAL', and return NULL,
+ * if `name' is passed as a NULL pointer.
+ */
+
+ if (name == NULL)
+ errno = EINVAL;
+
+ /* Otherwise, `name' must refer to a readable filesystem object,
+ * if we are going to resolve its absolute path name.
+ */
+
+ else if (access(name, 4) == 0)
+ {
+ /* If `name' didn't point to an existing entity,
+ * then we don't get to here; we simply fall past this block,
+ * returning NULL, with `errno' appropriately set by `access'.
+ *
+ * When we _do_ get to here, then we can use `_fullpath' to
+ * resolve the full path for `name' into `resolved', but first,
+ * check that we have a suitable buffer, in which to return it.
+ */
+
+ if ((retname = resolved) == NULL)
+ {
+ /* Caller didn't give us a buffer, so we'll exercise the
+ * option granted by SUSv3, and allocate one.
+ *
+ * `_fullpath' would do this for us, but it uses `malloc', and
+ * Microsoft's implementation doesn't set `errno' on failure.
+ * If we don't do this explicitly ourselves, then we will not
+ * know if `_fullpath' fails on `malloc' failure, or for some
+ * other reason, and we want to set `errno = ENOMEM' for the
+ * `malloc' failure case.
+ */
+
+ retname = (char*) malloc(_MAX_PATH);
+ }
+
+ /* By now, we should have a valid buffer.
+ * If we don't, then we know that `malloc' failed,
+ * so we can set `errno = ENOMEM' appropriately.
+ */
+
+ if (retname == NULL)
+ errno = ENOMEM;
+
+ /* Otherwise, when we do have a valid buffer,
+ * `_fullpath' should only fail if the path name is too long.
+ */
+
+ else if ((retname = _fullpath(retname, name, _MAX_PATH)) == NULL)
+ errno = ENAMETOOLONG;
+ }
+
+ /* By the time we get to here,
+ * `retname' either points to the required resolved path name,
+ * or it is NULL, with `errno' set appropriately, either of which
+ * is our required return condition.
+ */
+
+ if (retname != NULL)
+ {
+ // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS
+ int initialLength = strlen(retname);
+ TCHAR buffer[MAX_PATH];
+ GetShortPathName(retname, buffer, MAX_PATH);
+ GetLongPathName(buffer, retname, initialLength + 1);
+
+ // Force drive to be upper case
+ if (retname[1] == ':')
+ retname[0] = toupper(retname[0]);
+ }
+
+ return retname;
+}
+
+#ifdef _MSC_VER
+
+char* basename(char *path)
+{
+ char* l1 = strrchr(path, '\\');
+ char* l2 = strrchr(path, '/');
+ if (l2 > l1) l1 = l2;
+ if (!l1) return path; // no base name
+ return &l1[1];
+}
+
+// use _getcwd() instead of GetCurrentDirectory() because it updates errno
+char* getcwd(char* path, int max)
+{
+ return _getcwd(path, max);
+}
+
+// use _chdir() instead of SetCurrentDirectory() because it updates errno
+int chdir(const char* path)
+{
+ return _chdir(path);
+}
+
+char *dirname(char *path)
+{
+ char* l1 = strrchr(path, '\\');
+ char* l2 = strrchr(path, '/');
+ if (l2 > l1) l1 = l2;
+ if (!l1) return NULL; // no dir name
+ *l1 = 0;
+ return path;
+}
+
+int strcasecmp(const char* s1, const char* s2)
+{
+ return stricmp(s1, s2);
+}
+
+int strncasecmp(const char* s1, const char* s2, size_t n)
+{
+ return strnicmp(s1, s2, n);
+}
+
+int usleep(uint32_t useconds)
+{
+ Sleep(useconds / 1000);
+ return 0;
+}
+
+#if _MSC_VER < 1900
+namespace lldb_private {
+int vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
+{
+ int old_errno = errno;
+ int r = ::vsnprintf(buffer, count, format, argptr);
+ int new_errno = errno;
+ buffer[count-1] = '\0';
+ if (r == -1 || r == count)
+ {
+ FILE *nul = fopen("nul", "w");
+ int bytes_written = ::vfprintf(nul, format, argptr);
+ fclose(nul);
+ if (bytes_written < count)
+ errno = new_errno;
+ else
+ {
+ errno = old_errno;
+ r = bytes_written;
+ }
+ }
+ return r;
+}
+} // namespace lldb_private
+#endif
+
+#endif // _MSC_VER
diff --git a/source/Initialization/CMakeLists.txt b/source/Initialization/CMakeLists.txt
new file mode 100644
index 000000000000..f23a2b4339b8
--- /dev/null
+++ b/source/Initialization/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_lldb_library(lldbInitialization
+ SystemInitializerCommon.cpp
+ SystemInitializer.cpp
+ SystemLifetimeManager.cpp
+ )
diff --git a/source/Initialization/Makefile b/source/Initialization/Makefile
new file mode 100644
index 000000000000..a63f4733bb6e
--- /dev/null
+++ b/source/Initialization/Makefile
@@ -0,0 +1,14 @@
+##===- source/Initialize/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbInitialization
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Interpreter/CMakeLists.txt b/source/Interpreter/CMakeLists.txt
new file mode 100644
index 000000000000..b92128cd3011
--- /dev/null
+++ b/source/Interpreter/CMakeLists.txt
@@ -0,0 +1,45 @@
+add_lldb_library(lldbInterpreter
+ Args.cpp
+ CommandHistory.cpp
+ CommandInterpreter.cpp
+ CommandObject.cpp
+ CommandObjectRegexCommand.cpp
+ CommandObjectScript.cpp
+ CommandOptionValidators.cpp
+ CommandReturnObject.cpp
+ OptionGroupArchitecture.cpp
+ OptionGroupBoolean.cpp
+ OptionGroupFile.cpp
+ OptionGroupFormat.cpp
+ OptionGroupOutputFile.cpp
+ OptionGroupPlatform.cpp
+ OptionGroupString.cpp
+ OptionGroupUInt64.cpp
+ OptionGroupUUID.cpp
+ OptionGroupValueObjectDisplay.cpp
+ OptionValue.cpp
+ OptionValueArch.cpp
+ OptionValueArgs.cpp
+ OptionValueArray.cpp
+ OptionValueBoolean.cpp
+ OptionValueChar.cpp
+ OptionValueDictionary.cpp
+ OptionValueEnumeration.cpp
+ OptionValueFileSpec.cpp
+ OptionValueFileSpecLIst.cpp
+ OptionValueFormat.cpp
+ OptionValueFormatEntity.cpp
+ OptionValueLanguage.cpp
+ OptionValuePathMappings.cpp
+ OptionValueProperties.cpp
+ OptionValueRegex.cpp
+ OptionValueSInt64.cpp
+ OptionValueString.cpp
+ OptionValueUInt64.cpp
+ OptionValueUUID.cpp
+ OptionGroupVariable.cpp
+ OptionGroupWatchpoint.cpp
+ Options.cpp
+ Property.cpp
+ ScriptInterpreter.cpp
+ )
diff --git a/source/Interpreter/CommandHistory.cpp b/source/Interpreter/CommandHistory.cpp
index bbe64b446acc..9d3c814697b0 100644
--- a/source/Interpreter/CommandHistory.cpp
+++ b/source/Interpreter/CommandHistory.cpp
@@ -130,9 +130,9 @@ CommandHistory::Dump (Stream& stream,
size_t stop_idx) const
{
Mutex::Locker locker(m_mutex);
- stop_idx = std::min(stop_idx, m_history.size() - 1);
+ stop_idx = std::min(stop_idx + 1, m_history.size());
for (size_t counter = start_idx;
- counter <= stop_idx;
+ counter < stop_idx;
counter++)
{
const std::string hist_item = m_history[counter];
diff --git a/source/Interpreter/Makefile b/source/Interpreter/Makefile
new file mode 100644
index 000000000000..2f25e6796604
--- /dev/null
+++ b/source/Interpreter/Makefile
@@ -0,0 +1,51 @@
+##===- source/Interpreter/Makefile ------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbInterpreter
+BUILD_ARCHIVE = 1
+include $(LLDB_LEVEL)/../../Makefile.config
+
+ifneq ($(HOST_OS),MingW)
+ifeq (,$(findstring -DLLDB_DISABLE_PYTHON,$(CXXFLAGS)))
+DO_BUILD_LLDBWrapPython = 1
+BUILT_SOURCES := LLDBWrapPython.cpp
+endif
+endif
+
+include $(LLDB_LEVEL)/Makefile
+-include $(PROJ_OBJ_DIR)/LLDBWrapPython.cpp.d
+
+ifeq ($(DO_BUILD_LLDBWrapPython),1)
+# Drop -Wfour-char-constants, which we are not currently clean with.
+EXTRA_OPTIONS += -Wno-four-char-constants
+
+# Drop -Wself-assign, -Wmissing-field-initializers, -Wsometimes-uninitialized,
+# -Wcast-qual, and -Wdeprecated-register which we are not clean with due to SWIG
+# generated cpp source.
+EXTRA_OPTIONS += -Wno-missing-field-initializers -Wno-self-assign -Wno-sometimes-uninitialized -Wno-cast-qual -Wno-deprecated-register
+
+PYTHON_DIR := $(PROJ_OBJ_ROOT)/$(BuildMode)
+
+SWIG_SOURCES := $(shell find $(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts -type f -name '*.swig' -print)
+
+LLDBWrapPython.cpp lldb.py: $(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/Python/modify-python-lldb.py \
+ $(wildcard $(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/interface/*.i) \
+ ${SWIG_SOURCES}
+ $(Echo) Generating LLDBWrapPython.cpp
+ $(Verb) "$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/prepare_bindings.py" "--src-root=$(PROJ_SRC_DIR)/$(LLDB_LEVEL)" "--target-dir=$(PROJ_OBJ_DIR)" "--config-build-dir=$(PROJ_OBJ_DIR)" "--prefix=$(PYTHON_DIR)" $(if $(DISABLE_AUTO_DEPENDENCIES),,-M) --find-swig
+ $(Verb) "$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/finish-swig-wrapper-classes.sh" "$(PROJ_SRC_DIR)/$(LLDB_LEVEL)" "$(PROJ_OBJ_DIR)" "$(PROJ_OBJ_DIR)" "$(PYTHON_DIR)" -m
+
+install-local:: lldb.py
+ $(Echo) Installing $(BuildMode) LLDB python modules
+ $(Verb) "$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/prepare_bindings.py" "--src-root=$(PROJ_SRC_DIR)/$(LLDB_LEVEL)" "--target-dir=$(PROJ_OBJ_DIR)" "--config-build-dir=$(PROJ_OBJ_DIR)" "--prefix=$(DESTDIR)$(prefix)" --find-swig
+
+clean-local::
+ $(Verb) $(RM) -f LLDBWrapPython.cpp lldb.py
+endif
diff --git a/source/Makefile b/source/Makefile
new file mode 100644
index 000000000000..0ad56ffa5e0c
--- /dev/null
+++ b/source/Makefile
@@ -0,0 +1,37 @@
+##===- source/Makefile -------------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ..
+PARALLEL_DIRS := API Initialization Breakpoint Commands Core DataFormatters Expression Host Interpreter Plugins Symbol Target Utility
+LIBRARYNAME := lldbBase
+BUILD_ARCHIVE = 1
+
+# Although LLVM makefiles provide $(HOST_OS), we cannot use that here because it is defined by including the $(LLDB_LEVEL)/Makefile
+# below. Instead, we use uname -s to detect the HOST_OS and generate LLDB_vers.c only on Mac. On Linux, the version number is
+# calculated in the same way as Clang's version.
+ifeq (Darwin,$(shell uname -s))
+BUILT_SOURCES = LLDB_vers.c
+endif
+
+SOURCES := lldb.cpp
+
+include $(LLDB_LEVEL)/Makefile
+
+ifeq ($(HOST_OS),Darwin)
+LLDB_vers.c: $(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/generate-vers.pl $(PROJ_SRC_DIR)/$(LLDB_LEVEL)/lldb.xcodeproj/project.pbxproj
+ "$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/generate-vers.pl" "$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/lldb.xcodeproj/project.pbxproj" liblldb_core > LLDB_vers.c
+else
+LLDB_REVISION := $(strip \
+ $(shell $(LLVM_SRC_ROOT)/utils/GetSourceVersion $(LLVM_SRC_ROOT)/tools/lldb))
+
+LLDB_REPOSITORY := $(strip \
+ $(shell $(LLVM_SRC_ROOT)/utils/GetRepositoryPath $(LLVM_SRC_ROOT)/tools/lldb))
+
+CPP.Defines += -DLLDB_REVISION='"$(LLDB_REVISION)"' -DLLDB_REPOSITORY='"$(LLDB_REPOSITORY)"'
+endif
diff --git a/source/Plugins/ABI/CMakeLists.txt b/source/Plugins/ABI/CMakeLists.txt
new file mode 100644
index 000000000000..08452c5dad62
--- /dev/null
+++ b/source/Plugins/ABI/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_subdirectory(SysV-arm)
+add_subdirectory(SysV-arm64)
+add_subdirectory(SysV-hexagon)
+add_subdirectory(SysV-ppc)
+add_subdirectory(SysV-ppc64)
+add_subdirectory(SysV-mips)
+add_subdirectory(SysV-mips64)
+add_subdirectory(SysV-i386)
+add_subdirectory(SysV-x86_64)
+add_subdirectory(MacOSX-i386)
+add_subdirectory(MacOSX-arm)
+add_subdirectory(MacOSX-arm64)
diff --git a/source/Plugins/ABI/MacOSX-arm/CMakeLists.txt b/source/Plugins/ABI/MacOSX-arm/CMakeLists.txt
new file mode 100644
index 000000000000..ea8b011b1984
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-arm/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABIMacOSX_arm
+ ABIMacOSX_arm.cpp
+ )
diff --git a/source/Plugins/ABI/MacOSX-arm/Makefile b/source/Plugins/ABI/MacOSX-arm/Makefile
new file mode 100644
index 000000000000..18073266d34d
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-arm/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/MacOSX-arm/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===--------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABIMacOSX_arm
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/MacOSX-arm64/CMakeLists.txt b/source/Plugins/ABI/MacOSX-arm64/CMakeLists.txt
new file mode 100644
index 000000000000..498bb7218637
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-arm64/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABIMacOSX_arm64
+ ABIMacOSX_arm64.cpp
+ )
diff --git a/source/Plugins/ABI/MacOSX-arm64/Makefile b/source/Plugins/ABI/MacOSX-arm64/Makefile
new file mode 100644
index 000000000000..7fc6909e43cc
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-arm64/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/MacOSX-arm64/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABIMacOSX_arm64
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/MacOSX-i386/CMakeLists.txt b/source/Plugins/ABI/MacOSX-i386/CMakeLists.txt
new file mode 100644
index 000000000000..f6a543a66da7
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-i386/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABIMacOSX_i386
+ ABIMacOSX_i386.cpp
+ )
diff --git a/source/Plugins/ABI/MacOSX-i386/Makefile b/source/Plugins/ABI/MacOSX-i386/Makefile
new file mode 100644
index 000000000000..d9bc73922563
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-i386/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/MacOSX-i386/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABIMacOSX_i386
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/SysV-arm/CMakeLists.txt b/source/Plugins/ABI/SysV-arm/CMakeLists.txt
new file mode 100644
index 000000000000..c25ce5a1c633
--- /dev/null
+++ b/source/Plugins/ABI/SysV-arm/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABISysV_arm
+ ABISysV_arm.cpp
+ )
diff --git a/source/Plugins/ABI/SysV-arm/Makefile b/source/Plugins/ABI/SysV-arm/Makefile
new file mode 100644
index 000000000000..a1d95dc17320
--- /dev/null
+++ b/source/Plugins/ABI/SysV-arm/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/SysV-arm/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===--------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABISysV_arm
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/SysV-arm64/CMakeLists.txt b/source/Plugins/ABI/SysV-arm64/CMakeLists.txt
new file mode 100644
index 000000000000..0ddb37043ace
--- /dev/null
+++ b/source/Plugins/ABI/SysV-arm64/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABISysV_arm64
+ ABISysV_arm64.cpp
+ )
diff --git a/source/Plugins/ABI/SysV-arm64/Makefile b/source/Plugins/ABI/SysV-arm64/Makefile
new file mode 100644
index 000000000000..a72ecd83404d
--- /dev/null
+++ b/source/Plugins/ABI/SysV-arm64/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/SysV-arm64/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABISysV_arm64
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/SysV-hexagon/CMakeLists.txt b/source/Plugins/ABI/SysV-hexagon/CMakeLists.txt
new file mode 100644
index 000000000000..b8fbb0744719
--- /dev/null
+++ b/source/Plugins/ABI/SysV-hexagon/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABISysV_hexagon
+ ABISysV_hexagon.cpp
+ )
diff --git a/source/Plugins/ABI/SysV-hexagon/Makefile b/source/Plugins/ABI/SysV-hexagon/Makefile
new file mode 100644
index 000000000000..23733c7e551e
--- /dev/null
+++ b/source/Plugins/ABI/SysV-hexagon/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/SysV-hexagon/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABISysV_hexagon
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/SysV-i386/CMakeLists.txt b/source/Plugins/ABI/SysV-i386/CMakeLists.txt
new file mode 100644
index 000000000000..3528f01ad75e
--- /dev/null
+++ b/source/Plugins/ABI/SysV-i386/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABISysV_i386
+ ABISysV_i386.cpp
+ )
diff --git a/source/Plugins/ABI/SysV-i386/Makefile b/source/Plugins/ABI/SysV-i386/Makefile
new file mode 100644
index 000000000000..0ac3cbee2d54
--- /dev/null
+++ b/source/Plugins/ABI/SysV-i386/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/SysV-i386/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABISysV_i386
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/SysV-mips/CMakeLists.txt b/source/Plugins/ABI/SysV-mips/CMakeLists.txt
new file mode 100644
index 000000000000..0db3e5c1c7e0
--- /dev/null
+++ b/source/Plugins/ABI/SysV-mips/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABISysV_mips
+ ABISysV_mips.cpp
+ )
diff --git a/source/Plugins/ABI/SysV-mips/Makefile b/source/Plugins/ABI/SysV-mips/Makefile
new file mode 100644
index 000000000000..c61130628433
--- /dev/null
+++ b/source/Plugins/ABI/SysV-mips/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/SysV-mips/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABISysV_mips
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/SysV-mips64/CMakeLists.txt b/source/Plugins/ABI/SysV-mips64/CMakeLists.txt
new file mode 100644
index 000000000000..099464821edd
--- /dev/null
+++ b/source/Plugins/ABI/SysV-mips64/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABISysV_mips64
+ ABISysV_mips64.cpp
+ )
diff --git a/source/Plugins/ABI/SysV-mips64/Makefile b/source/Plugins/ABI/SysV-mips64/Makefile
new file mode 100644
index 000000000000..b7e6dc615cb0
--- /dev/null
+++ b/source/Plugins/ABI/SysV-mips64/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/SysV-mips64/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABISysV_mips64
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/SysV-ppc/CMakeLists.txt b/source/Plugins/ABI/SysV-ppc/CMakeLists.txt
new file mode 100644
index 000000000000..a7784195f771
--- /dev/null
+++ b/source/Plugins/ABI/SysV-ppc/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABISysV_ppc
+ ABISysV_ppc.cpp
+ )
diff --git a/source/Plugins/ABI/SysV-ppc/Makefile b/source/Plugins/ABI/SysV-ppc/Makefile
new file mode 100644
index 000000000000..7a6d38d68337
--- /dev/null
+++ b/source/Plugins/ABI/SysV-ppc/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/SysV-hexagon/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABISysV_ppc
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt b/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt
new file mode 100644
index 000000000000..7a33d2922047
--- /dev/null
+++ b/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABISysV_ppc64
+ ABISysV_ppc64.cpp
+ )
diff --git a/source/Plugins/ABI/SysV-ppc64/Makefile b/source/Plugins/ABI/SysV-ppc64/Makefile
new file mode 100644
index 000000000000..43fc41d42713
--- /dev/null
+++ b/source/Plugins/ABI/SysV-ppc64/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/SysV-hexagon/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABISysV_ppc64
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ABI/SysV-x86_64/CMakeLists.txt b/source/Plugins/ABI/SysV-x86_64/CMakeLists.txt
new file mode 100644
index 000000000000..a2b62d7240fd
--- /dev/null
+++ b/source/Plugins/ABI/SysV-x86_64/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginABISysV_x86_64
+ ABISysV_x86_64.cpp
+ )
diff --git a/source/Plugins/ABI/SysV-x86_64/Makefile b/source/Plugins/ABI/SysV-x86_64/Makefile
new file mode 100644
index 000000000000..32990a64f956
--- /dev/null
+++ b/source/Plugins/ABI/SysV-x86_64/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ABI/SysV-x86_64/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginABISysV_x86_64
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/CMakeLists.txt b/source/Plugins/CMakeLists.txt
new file mode 100644
index 000000000000..928332fb6ba4
--- /dev/null
+++ b/source/Plugins/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_subdirectory(ABI)
+add_subdirectory(Disassembler)
+add_subdirectory(DynamicLoader)
+add_subdirectory(ExpressionParser)
+add_subdirectory(Instruction)
+add_subdirectory(InstrumentationRuntime)
+add_subdirectory(JITLoader)
+add_subdirectory(Language)
+add_subdirectory(LanguageRuntime)
+add_subdirectory(MemoryHistory)
+add_subdirectory(ObjectContainer)
+add_subdirectory(ObjectFile)
+add_subdirectory(OperatingSystem)
+add_subdirectory(Platform)
+add_subdirectory(Process)
+add_subdirectory(ScriptInterpreter)
+add_subdirectory(SymbolFile)
+add_subdirectory(SystemRuntime)
+add_subdirectory(SymbolVendor)
+add_subdirectory(UnwindAssembly)
diff --git a/source/Plugins/Disassembler/CMakeLists.txt b/source/Plugins/Disassembler/CMakeLists.txt
new file mode 100644
index 000000000000..6e3c904d5a60
--- /dev/null
+++ b/source/Plugins/Disassembler/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(llvm)
diff --git a/source/Plugins/Disassembler/llvm/CMakeLists.txt b/source/Plugins/Disassembler/llvm/CMakeLists.txt
new file mode 100644
index 000000000000..ada81dc55e97
--- /dev/null
+++ b/source/Plugins/Disassembler/llvm/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginDisassemblerLLVM
+ DisassemblerLLVMC.cpp
+ )
diff --git a/source/Plugins/Disassembler/llvm/Makefile b/source/Plugins/Disassembler/llvm/Makefile
new file mode 100644
index 000000000000..a1309cdd081f
--- /dev/null
+++ b/source/Plugins/Disassembler/llvm/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Disassembler/llvm/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginDisassemblerLLVM
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/DynamicLoader/CMakeLists.txt b/source/Plugins/DynamicLoader/CMakeLists.txt
new file mode 100644
index 000000000000..8e1b316a3c25
--- /dev/null
+++ b/source/Plugins/DynamicLoader/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_subdirectory(MacOSX-DYLD)
+add_subdirectory(POSIX-DYLD)
+add_subdirectory(Static)
+add_subdirectory(Hexagon-DYLD)
+add_subdirectory(Windows-DYLD)
+
+if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ add_subdirectory(Darwin-Kernel)
+endif()
diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/CMakeLists.txt b/source/Plugins/DynamicLoader/Darwin-Kernel/CMakeLists.txt
new file mode 100644
index 000000000000..02752b78a4c7
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Darwin-Kernel/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginDynamicLoaderDarwinKernel
+ DynamicLoaderDarwinKernel.cpp
+ )
diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
new file mode 100644
index 000000000000..218b0b7a1eee
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -0,0 +1,1698 @@
+//===-- DynamicLoaderDarwinKernel.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/Utility/SafeMachO.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h"
+
+#include "DynamicLoaderDarwinKernel.h"
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
+#ifdef ENABLE_DEBUG_PRINTF
+#include <stdio.h>
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Progressively greater amounts of scanning we will allow
+// For some targets very early in startup, we can't do any random reads of memory or we can crash the device
+// so a setting is needed that can completely disable the KASLR scans.
+
+enum KASLRScanType
+{
+ eKASLRScanNone = 0, // No reading into the inferior at all
+ eKASLRScanLowgloAddresses, // Check one word of memory for a possible kernel addr, then see if a kernel is there
+ eKASLRScanNearPC, // Scan backwards from the current $pc looking for kernel; checking at 96 locations total
+ eKASLRScanExhaustiveScan // Scan through the entire possible kernel address range looking for a kernel
+};
+
+OptionEnumValueElement
+g_kaslr_kernel_scan_enum_values[] =
+{
+ { eKASLRScanNone, "none", "Do not read memory looking for a Darwin kernel when attaching." },
+ { eKASLRScanLowgloAddresses, "basic", "Check for the Darwin kernel's load addr in the lowglo page (boot-args=debug) only." },
+ { eKASLRScanNearPC, "fast-scan", "Scan near the pc value on attach to find the Darwin kernel's load address."},
+ { eKASLRScanExhaustiveScan, "exhaustive-scan", "Scan through the entire potential address range of Darwin kernel (only on 32-bit targets)."},
+ { 0, NULL, NULL }
+};
+
+static PropertyDefinition
+g_properties[] =
+{
+ { "load-kexts" , OptionValue::eTypeBoolean, true, true, NULL, NULL, "Automatically loads kext images when attaching to a kernel." },
+ { "scan-type", OptionValue::eTypeEnum, true, eKASLRScanNearPC, NULL, g_kaslr_kernel_scan_enum_values, "Control how many reads lldb will make while searching for a Darwin kernel on attach." },
+ { NULL , OptionValue::eTypeInvalid, false, 0 , NULL, NULL, NULL }
+};
+
+enum {
+ ePropertyLoadKexts,
+ ePropertyScanType
+};
+
+class DynamicLoaderDarwinKernelProperties : public Properties
+{
+public:
+
+ static ConstString &
+ GetSettingName ()
+ {
+ static ConstString g_setting_name("darwin-kernel");
+ return g_setting_name;
+ }
+
+ DynamicLoaderDarwinKernelProperties() :
+ Properties ()
+ {
+ m_collection_sp.reset (new OptionValueProperties(GetSettingName()));
+ m_collection_sp->Initialize(g_properties);
+ }
+
+ virtual
+ ~DynamicLoaderDarwinKernelProperties()
+ {
+ }
+
+ bool
+ GetLoadKexts() const
+ {
+ const uint32_t idx = ePropertyLoadKexts;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+ }
+
+ KASLRScanType
+ GetScanType() const
+ {
+ const uint32_t idx = ePropertyScanType;
+ return (KASLRScanType) m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value);
+ }
+
+
+};
+
+typedef std::shared_ptr<DynamicLoaderDarwinKernelProperties> DynamicLoaderDarwinKernelPropertiesSP;
+
+static const DynamicLoaderDarwinKernelPropertiesSP &
+GetGlobalProperties()
+{
+ static DynamicLoaderDarwinKernelPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ g_settings_sp.reset (new DynamicLoaderDarwinKernelProperties ());
+ return g_settings_sp;
+}
+
+//----------------------------------------------------------------------
+// Create an instance of this class. This function is filled into
+// the plugin info class that gets handed out by the plugin factory and
+// allows the lldb to instantiate an instance of this class.
+//----------------------------------------------------------------------
+DynamicLoader *
+DynamicLoaderDarwinKernel::CreateInstance (Process* process, bool force)
+{
+ if (!force)
+ {
+ // If the user provided an executable binary and it is not a kernel,
+ // this plugin should not create an instance.
+ Module* exe_module = process->GetTarget().GetExecutableModulePointer();
+ if (exe_module)
+ {
+ ObjectFile *object_file = exe_module->GetObjectFile();
+ if (object_file)
+ {
+ if (object_file->GetStrata() != ObjectFile::eStrataKernel)
+ {
+ return NULL;
+ }
+ }
+ }
+
+ // If the target's architecture does not look like an Apple environment,
+ // this plugin should not create an instance.
+ const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
+ switch (triple_ref.getOS())
+ {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
+ case llvm::Triple::TvOS:
+ case llvm::Triple::WatchOS:
+ if (triple_ref.getVendor() != llvm::Triple::Apple)
+ {
+ return NULL;
+ }
+ break;
+ // If we have triple like armv7-unknown-unknown, we should try looking for a Darwin kernel.
+ case llvm::Triple::UnknownOS:
+ break;
+ default:
+ return NULL;
+ break;
+ }
+ }
+
+ // At this point if there is an ExecutableModule, it is a kernel and the Target is some variant of an Apple system.
+ // If the Process hasn't provided the kernel load address, we need to look around in memory to find it.
+
+ addr_t kernel_load_address = SearchForDarwinKernel (process);
+ if (kernel_load_address != LLDB_INVALID_ADDRESS)
+ {
+ process->SetCanRunCode(false);
+ return new DynamicLoaderDarwinKernel (process, kernel_load_address);
+ }
+ return NULL;
+}
+
+lldb::addr_t
+DynamicLoaderDarwinKernel::SearchForDarwinKernel (Process *process)
+{
+ addr_t kernel_load_address = process->GetImageInfoAddress();
+ if (kernel_load_address == LLDB_INVALID_ADDRESS)
+ {
+ kernel_load_address = SearchForKernelAtSameLoadAddr (process);
+ if (kernel_load_address == LLDB_INVALID_ADDRESS)
+ {
+ kernel_load_address = SearchForKernelWithDebugHints (process);
+ if (kernel_load_address == LLDB_INVALID_ADDRESS)
+ {
+ kernel_load_address = SearchForKernelNearPC (process);
+ if (kernel_load_address == LLDB_INVALID_ADDRESS)
+ {
+ kernel_load_address = SearchForKernelViaExhaustiveSearch (process);
+ }
+ }
+ }
+ }
+ return kernel_load_address;
+}
+
+//----------------------------------------------------------------------
+// Check if the kernel binary is loaded in memory without a slide.
+// First verify that the ExecutableModule is a kernel before we proceed.
+// Returns the address of the kernel if one was found, else LLDB_INVALID_ADDRESS.
+//----------------------------------------------------------------------
+lldb::addr_t
+DynamicLoaderDarwinKernel::SearchForKernelAtSameLoadAddr (Process *process)
+{
+ Module *exe_module = process->GetTarget().GetExecutableModulePointer();
+ if (exe_module == NULL)
+ return LLDB_INVALID_ADDRESS;
+
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ if (exe_objfile == NULL)
+ return LLDB_INVALID_ADDRESS;
+
+ if (exe_objfile->GetType() != ObjectFile::eTypeExecutable || exe_objfile->GetStrata() != ObjectFile::eStrataKernel)
+ return LLDB_INVALID_ADDRESS;
+
+ if (!exe_objfile->GetHeaderAddress().IsValid())
+ return LLDB_INVALID_ADDRESS;
+
+ if (CheckForKernelImageAtAddress (exe_objfile->GetHeaderAddress().GetFileAddress(), process) == exe_module->GetUUID())
+ return exe_objfile->GetHeaderAddress().GetFileAddress();
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+//----------------------------------------------------------------------
+// If the debug flag is included in the boot-args nvram setting, the kernel's load address
+// will be noted in the lowglo page at a fixed address
+// Returns the address of the kernel if one was found, else LLDB_INVALID_ADDRESS.
+//----------------------------------------------------------------------
+lldb::addr_t
+DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints (Process *process)
+{
+ if (GetGlobalProperties()->GetScanType() == eKASLRScanNone)
+ return LLDB_INVALID_ADDRESS;
+
+ Error read_err;
+ addr_t addr = LLDB_INVALID_ADDRESS;
+ if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 8)
+ {
+ addr = process->ReadUnsignedIntegerFromMemory (0xffffff8000002010ULL, 8, LLDB_INVALID_ADDRESS, read_err);
+ if (CheckForKernelImageAtAddress (addr, process).IsValid())
+ {
+ return addr;
+ }
+ addr = process->ReadUnsignedIntegerFromMemory (0xffffff8000004010ULL, 8, LLDB_INVALID_ADDRESS, read_err);
+ if (CheckForKernelImageAtAddress (addr, process).IsValid())
+ {
+ return addr;
+ }
+ }
+ else
+ {
+ addr = process->ReadUnsignedIntegerFromMemory (0xffff0110, 4, LLDB_INVALID_ADDRESS, read_err);
+ if (CheckForKernelImageAtAddress (addr, process).IsValid())
+ {
+ return addr;
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+//----------------------------------------------------------------------
+// If the kernel is currently executing when lldb attaches, and we don't have
+// a better way of finding the kernel's load address, try searching backwards
+// from the current pc value looking for the kernel's Mach header in memory.
+// Returns the address of the kernel if one was found, else LLDB_INVALID_ADDRESS.
+//----------------------------------------------------------------------
+lldb::addr_t
+DynamicLoaderDarwinKernel::SearchForKernelNearPC (Process *process)
+{
+ if (GetGlobalProperties()->GetScanType() == eKASLRScanNone
+ || GetGlobalProperties()->GetScanType() == eKASLRScanLowgloAddresses)
+ {
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ ThreadSP thread = process->GetThreadList().GetSelectedThread ();
+ if (thread.get() == NULL)
+ return LLDB_INVALID_ADDRESS;
+ addr_t pc = thread->GetRegisterContext ()->GetPC(LLDB_INVALID_ADDRESS);
+
+ if (pc == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ addr_t kernel_range_low;
+ if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 8)
+ {
+ kernel_range_low = 1ULL << 63;
+ }
+ else
+ {
+ kernel_range_low = 1ULL << 31;
+ }
+
+ // Outside the normal kernel address range, this is probably userland code running right now
+ if (pc < kernel_range_low)
+ return LLDB_INVALID_ADDRESS;
+
+ // The kernel will load at at one megabyte boundary (0x100000), or at that boundary plus
+ // an offset of one page (0x1000) or two, depending on the device.
+
+ // Round the current pc down to the nearest one megabyte boundary - the place where we will start searching.
+ addr_t addr = pc & ~0xfffff;
+
+ int i = 0;
+ while (i < 32 && pc >= kernel_range_low)
+ {
+ if (CheckForKernelImageAtAddress (addr, process).IsValid())
+ return addr;
+ if (CheckForKernelImageAtAddress (addr + 0x1000, process).IsValid())
+ return addr + 0x1000;
+ if (CheckForKernelImageAtAddress (addr + 0x2000, process).IsValid())
+ return addr + 0x2000;
+ if (CheckForKernelImageAtAddress (addr + 0x4000, process).IsValid())
+ return addr + 0x4000;
+ i++;
+ addr -= 0x100000;
+ }
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+//----------------------------------------------------------------------
+// Scan through the valid address range for a kernel binary.
+// This is uselessly slow in 64-bit environments so we don't even try it.
+// This scan is not enabled by default even for 32-bit targets.
+// Returns the address of the kernel if one was found, else LLDB_INVALID_ADDRESS.
+//----------------------------------------------------------------------
+lldb::addr_t
+DynamicLoaderDarwinKernel::SearchForKernelViaExhaustiveSearch (Process *process)
+{
+ if (GetGlobalProperties()->GetScanType() != eKASLRScanExhaustiveScan)
+ {
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ addr_t kernel_range_low, kernel_range_high;
+ if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 8)
+ {
+ kernel_range_low = 1ULL << 63;
+ kernel_range_high = UINT64_MAX;
+ }
+ else
+ {
+ kernel_range_low = 1ULL << 31;
+ kernel_range_high = UINT32_MAX;
+ }
+
+ // Stepping through memory at one-megabyte resolution looking for a kernel
+ // rarely works (fast enough) with a 64-bit address space -- for now, let's
+ // not even bother. We may be attaching to something which *isn't* a kernel
+ // and we don't want to spin for minutes on-end looking for a kernel.
+ if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 8)
+ return LLDB_INVALID_ADDRESS;
+
+ addr_t addr = kernel_range_low;
+
+ while (addr >= kernel_range_low && addr < kernel_range_high)
+ {
+ if (CheckForKernelImageAtAddress (addr, process).IsValid())
+ return addr;
+ if (CheckForKernelImageAtAddress (addr + 0x1000, process).IsValid())
+ return addr + 0x1000;
+ if (CheckForKernelImageAtAddress (addr + 0x2000, process).IsValid())
+ return addr + 0x2000;
+ if (CheckForKernelImageAtAddress (addr + 0x4000, process).IsValid())
+ return addr + 0x4000;
+ addr += 0x100000;
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+//----------------------------------------------------------------------
+// Given an address in memory, look to see if there is a kernel image at that
+// address.
+// Returns a UUID; if a kernel was not found at that address, UUID.IsValid() will be false.
+//----------------------------------------------------------------------
+lldb_private::UUID
+DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress (lldb::addr_t addr, Process *process)
+{
+ if (addr == LLDB_INVALID_ADDRESS)
+ return UUID();
+
+ // First try a quick test -- read the first 4 bytes and see if there is a valid Mach-O magic field there
+ // (the first field of the mach_header/mach_header_64 struct).
+
+ Error read_error;
+ uint64_t result = process->ReadUnsignedIntegerFromMemory (addr, 4, LLDB_INVALID_ADDRESS, read_error);
+ if (result != llvm::MachO::MH_MAGIC_64
+ && result != llvm::MachO::MH_MAGIC
+ && result != llvm::MachO::MH_CIGAM
+ && result != llvm::MachO::MH_CIGAM_64)
+ {
+ return UUID();
+ }
+
+ // Read the mach header and see whether it looks like a kernel
+ llvm::MachO::mach_header header;
+ if (process->DoReadMemory (addr, &header, sizeof(header), read_error) != sizeof(header))
+ return UUID();
+
+ if (header.magic == llvm::MachO::MH_CIGAM ||
+ header.magic == llvm::MachO::MH_CIGAM_64)
+ {
+ header.magic = llvm::ByteSwap_32(header.magic);
+ header.cputype = llvm::ByteSwap_32(header.cputype);
+ header.cpusubtype = llvm::ByteSwap_32(header.cpusubtype);
+ header.filetype = llvm::ByteSwap_32(header.filetype);
+ header.ncmds = llvm::ByteSwap_32(header.ncmds);
+ header.sizeofcmds = llvm::ByteSwap_32(header.sizeofcmds);
+ header.flags = llvm::ByteSwap_32(header.flags);
+ }
+
+ // A kernel is an executable which does not have the dynamic link object flag set.
+ if (header.filetype == llvm::MachO::MH_EXECUTE
+ && (header.flags & llvm::MachO::MH_DYLDLINK) == 0)
+ {
+ // Create a full module to get the UUID
+ ModuleSP memory_module_sp = process->ReadModuleFromMemory (FileSpec ("temp_mach_kernel", false), addr);
+ if (!memory_module_sp.get())
+ return UUID();
+
+ ObjectFile *exe_objfile = memory_module_sp->GetObjectFile();
+ if (exe_objfile == NULL)
+ return UUID();
+
+ if (exe_objfile->GetType() == ObjectFile::eTypeExecutable && exe_objfile->GetStrata() == ObjectFile::eStrataKernel)
+ {
+ ArchSpec kernel_arch (eArchTypeMachO, header.cputype, header.cpusubtype);
+ if (!process->GetTarget().GetArchitecture().IsCompatibleMatch(kernel_arch))
+ {
+ process->GetTarget().SetArchitecture (kernel_arch);
+ }
+ return memory_module_sp->GetUUID();
+ }
+ }
+
+ return UUID();
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DynamicLoaderDarwinKernel::DynamicLoaderDarwinKernel (Process* process, lldb::addr_t kernel_addr) :
+ DynamicLoader(process),
+ m_kernel_load_address (kernel_addr),
+ m_kernel(),
+ m_kext_summary_header_ptr_addr (),
+ m_kext_summary_header_addr (),
+ m_kext_summary_header (),
+ m_known_kexts (),
+ m_mutex(Mutex::eMutexTypeRecursive),
+ m_break_id (LLDB_INVALID_BREAK_ID)
+{
+ Error error;
+ PlatformSP platform_sp(Platform::Create(PlatformDarwinKernel::GetPluginNameStatic(), error));
+ // Only select the darwin-kernel Platform if we've been asked to load kexts.
+ // It can take some time to scan over all of the kext info.plists and that
+ // shouldn't be done if kext loading is explicitly disabled.
+ if (platform_sp.get() && GetGlobalProperties()->GetLoadKexts())
+ {
+ process->GetTarget().SetPlatform (platform_sp);
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoaderDarwinKernel::~DynamicLoaderDarwinKernel()
+{
+ Clear(true);
+}
+
+void
+DynamicLoaderDarwinKernel::UpdateIfNeeded()
+{
+ LoadKernelModuleIfNeeded();
+ SetNotificationBreakpointIfNeeded ();
+}
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderDarwinKernel::DidAttach ()
+{
+ PrivateInitialize(m_process);
+ UpdateIfNeeded();
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderDarwinKernel::DidLaunch ()
+{
+ PrivateInitialize(m_process);
+ UpdateIfNeeded();
+}
+
+
+//----------------------------------------------------------------------
+// Clear out the state of this class.
+//----------------------------------------------------------------------
+void
+DynamicLoaderDarwinKernel::Clear (bool clear_process)
+{
+ Mutex::Locker locker(m_mutex);
+
+ if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id))
+ m_process->ClearBreakpointSiteByID(m_break_id);
+
+ if (clear_process)
+ m_process = NULL;
+ m_kernel.Clear();
+ m_known_kexts.clear();
+ m_kext_summary_header_ptr_addr.Clear();
+ m_kext_summary_header_addr.Clear();
+ m_break_id = LLDB_INVALID_BREAK_ID;
+}
+
+
+bool
+DynamicLoaderDarwinKernel::KextImageInfo::LoadImageAtFileAddress (Process *process)
+{
+ if (IsLoaded())
+ return true;
+
+ if (m_module_sp)
+ {
+ bool changed = false;
+ if (m_module_sp->SetLoadAddress (process->GetTarget(), 0, true, changed))
+ m_load_process_stop_id = process->GetStopID();
+ }
+ return false;
+}
+
+void
+DynamicLoaderDarwinKernel::KextImageInfo::SetModule (ModuleSP module_sp)
+{
+ m_module_sp = module_sp;
+ if (module_sp.get() && module_sp->GetObjectFile())
+ {
+ if (module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeExecutable
+ && module_sp->GetObjectFile()->GetStrata() == ObjectFile::eStrataKernel)
+ {
+ m_kernel_image = true;
+ }
+ else
+ {
+ m_kernel_image = false;
+ }
+ }
+}
+
+ModuleSP
+DynamicLoaderDarwinKernel::KextImageInfo::GetModule ()
+{
+ return m_module_sp;
+}
+
+void
+DynamicLoaderDarwinKernel::KextImageInfo::SetLoadAddress (addr_t load_addr)
+{
+ m_load_address = load_addr;
+}
+
+addr_t
+DynamicLoaderDarwinKernel::KextImageInfo::GetLoadAddress () const
+{
+ return m_load_address;
+}
+
+uint64_t
+DynamicLoaderDarwinKernel::KextImageInfo::GetSize () const
+{
+ return m_size;
+}
+
+void
+DynamicLoaderDarwinKernel::KextImageInfo::SetSize (uint64_t size)
+{
+ m_size = size;
+}
+
+uint32_t
+DynamicLoaderDarwinKernel::KextImageInfo::GetProcessStopId () const
+{
+ return m_load_process_stop_id;
+}
+
+void
+DynamicLoaderDarwinKernel::KextImageInfo::SetProcessStopId (uint32_t stop_id)
+{
+ m_load_process_stop_id = stop_id;
+}
+
+bool
+DynamicLoaderDarwinKernel::KextImageInfo::operator== (const KextImageInfo &rhs)
+{
+ if (m_uuid.IsValid() || rhs.GetUUID().IsValid())
+ {
+ if (m_uuid == rhs.GetUUID())
+ {
+ return true;
+ }
+ return false;
+ }
+
+ if (m_name == rhs.GetName() && m_load_address == rhs.GetLoadAddress())
+ return true;
+
+ return false;
+}
+
+void
+DynamicLoaderDarwinKernel::KextImageInfo::SetName (const char *name)
+{
+ m_name = name;
+}
+
+std::string
+DynamicLoaderDarwinKernel::KextImageInfo::GetName () const
+{
+ return m_name;
+}
+
+void
+DynamicLoaderDarwinKernel::KextImageInfo::SetUUID (const UUID &uuid)
+{
+ m_uuid = uuid;
+}
+
+UUID
+DynamicLoaderDarwinKernel::KextImageInfo::GetUUID () const
+{
+ return m_uuid;
+}
+
+// Given the m_load_address from the kext summaries, and a UUID, try to create an in-memory
+// Module at that address. Require that the MemoryModule have a matching UUID and detect
+// if this MemoryModule is a kernel or a kext.
+//
+// Returns true if m_memory_module_sp is now set to a valid Module.
+
+bool
+DynamicLoaderDarwinKernel::KextImageInfo::ReadMemoryModule (Process *process)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (m_memory_module_sp.get() != NULL)
+ return true;
+ if (m_load_address == LLDB_INVALID_ADDRESS)
+ return false;
+
+ FileSpec file_spec;
+ file_spec.SetFile (m_name.c_str(), false);
+
+ ModuleSP memory_module_sp = process->ReadModuleFromMemory (file_spec, m_load_address);
+
+ if (memory_module_sp.get() == NULL)
+ return false;
+
+ bool is_kernel = false;
+ if (memory_module_sp->GetObjectFile())
+ {
+ if (memory_module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeExecutable
+ && memory_module_sp->GetObjectFile()->GetStrata() == ObjectFile::eStrataKernel)
+ {
+ is_kernel = true;
+ }
+ else if (memory_module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeSharedLibrary)
+ {
+ is_kernel = false;
+ }
+ }
+
+ // If this is a kext, and the kernel specified what UUID we should find at this
+ // load address, require that the memory module have a matching UUID or something
+ // has gone wrong and we should discard it.
+ if (m_uuid.IsValid())
+ {
+ if (m_uuid != memory_module_sp->GetUUID())
+ {
+ if (log)
+ {
+ log->Printf ("KextImageInfo::ReadMemoryModule the kernel said to find uuid %s at 0x%" PRIx64 " but instead we found uuid %s, throwing it away", m_uuid.GetAsString().c_str(), m_load_address, memory_module_sp->GetUUID().GetAsString().c_str());
+ }
+ return false;
+ }
+ }
+
+ // If the in-memory Module has a UUID, let's use that.
+ if (!m_uuid.IsValid() && memory_module_sp->GetUUID().IsValid())
+ {
+ m_uuid = memory_module_sp->GetUUID();
+ }
+
+ m_memory_module_sp = memory_module_sp;
+ m_kernel_image = is_kernel;
+ if (is_kernel)
+ {
+ if (log)
+ {
+ // This is unusual and probably not intended
+ log->Printf ("KextImageInfo::ReadMemoryModule read the kernel binary out of memory");
+ }
+ if (memory_module_sp->GetArchitecture().IsValid())
+ {
+ process->GetTarget().SetArchitecture(memory_module_sp->GetArchitecture());
+ }
+ if (m_uuid.IsValid())
+ {
+ ModuleSP exe_module_sp = process->GetTarget().GetExecutableModule();
+ if (exe_module_sp.get() && exe_module_sp->GetUUID().IsValid())
+ {
+ if (m_uuid != exe_module_sp->GetUUID())
+ {
+ // The user specified a kernel binary that has a different UUID than
+ // the kernel actually running in memory. This never ends well;
+ // clear the user specified kernel binary from the Target.
+
+ m_module_sp.reset();
+
+ ModuleList user_specified_kernel_list;
+ user_specified_kernel_list.Append (exe_module_sp);
+ process->GetTarget().GetImages().Remove (user_specified_kernel_list);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+DynamicLoaderDarwinKernel::KextImageInfo::IsKernel () const
+{
+ return m_kernel_image == true;
+}
+
+void
+DynamicLoaderDarwinKernel::KextImageInfo::SetIsKernel (bool is_kernel)
+{
+ m_kernel_image = is_kernel;
+}
+
+bool
+DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule (Process *process)
+{
+ if (IsLoaded())
+ return true;
+
+
+ Target &target = process->GetTarget();
+
+ // If we don't have / can't create a memory module for this kext, don't try to load it - we won't
+ // have the correct segment load addresses.
+ if (!ReadMemoryModule (process))
+ {
+ return false;
+ }
+
+ bool uuid_is_valid = m_uuid.IsValid();
+
+ if (IsKernel() && uuid_is_valid && m_memory_module_sp.get())
+ {
+ Stream *s = target.GetDebugger().GetOutputFile().get();
+ if (s)
+ {
+ s->Printf ("Kernel UUID: %s\n", m_memory_module_sp->GetUUID().GetAsString().c_str());
+ s->Printf ("Load Address: 0x%" PRIx64 "\n", m_load_address);
+ }
+ }
+
+ if (!m_module_sp)
+ {
+ // See if the kext has already been loaded into the target, probably by the user doing target modules add.
+ const ModuleList &target_images = target.GetImages();
+ m_module_sp = target_images.FindModule(m_uuid);
+
+ // Search for the kext on the local filesystem via the UUID
+ if (!m_module_sp && uuid_is_valid)
+ {
+ ModuleSpec module_spec;
+ module_spec.GetUUID() = m_uuid;
+ module_spec.GetArchitecture() = target.GetArchitecture();
+
+ // For the kernel, we really do need an on-disk file copy of the binary to do anything useful.
+ // This will force a clal to
+ if (IsKernel())
+ {
+ if (Symbols::DownloadObjectAndSymbolFile (module_spec, true))
+ {
+ if (module_spec.GetFileSpec().Exists())
+ {
+ m_module_sp.reset(new Module (module_spec.GetFileSpec(), target.GetArchitecture()));
+ if (m_module_sp.get() && m_module_sp->MatchesModuleSpec (module_spec))
+ {
+ ModuleList loaded_module_list;
+ loaded_module_list.Append (m_module_sp);
+ target.ModulesDidLoad (loaded_module_list);
+ }
+ }
+ }
+ }
+
+ // If the current platform is PlatformDarwinKernel, create a ModuleSpec with the filename set
+ // to be the bundle ID for this kext, e.g. "com.apple.filesystems.msdosfs", and ask the platform
+ // to find it.
+ PlatformSP platform_sp (target.GetPlatform());
+ if (!m_module_sp && platform_sp)
+ {
+ ConstString platform_name (platform_sp->GetPluginName());
+ static ConstString g_platform_name (PlatformDarwinKernel::GetPluginNameStatic());
+ if (platform_name == g_platform_name)
+ {
+ ModuleSpec kext_bundle_module_spec(module_spec);
+ FileSpec kext_filespec(m_name.c_str(), false);
+ kext_bundle_module_spec.GetFileSpec() = kext_filespec;
+ platform_sp->GetSharedModule (kext_bundle_module_spec, process, m_module_sp, &target.GetExecutableSearchPaths(), NULL, NULL);
+ }
+ }
+
+ // Ask the Target to find this file on the local system, if possible.
+ // This will search in the list of currently-loaded files, look in the
+ // standard search paths on the system, and on a Mac it will try calling
+ // the DebugSymbols framework with the UUID to find the binary via its
+ // search methods.
+ if (!m_module_sp)
+ {
+ m_module_sp = target.GetSharedModule (module_spec);
+ }
+
+ if (IsKernel() && !m_module_sp)
+ {
+ Stream *s = target.GetDebugger().GetOutputFile().get();
+ if (s)
+ {
+ s->Printf ("WARNING: Unable to locate kernel binary on the debugger system.\n");
+ }
+ }
+ }
+
+ // If we managed to find a module, append it to the target's list of images.
+ // If we also have a memory module, require that they have matching UUIDs
+ if (m_module_sp)
+ {
+ bool uuid_match_ok = true;
+ if (m_memory_module_sp)
+ {
+ if (m_module_sp->GetUUID() != m_memory_module_sp->GetUUID())
+ {
+ uuid_match_ok = false;
+ }
+ }
+ if (uuid_match_ok)
+ {
+ target.GetImages().AppendIfNeeded(m_module_sp);
+ if (IsKernel() && target.GetExecutableModulePointer() != m_module_sp.get())
+ {
+ target.SetExecutableModule (m_module_sp, false);
+ }
+ }
+ }
+ }
+
+ if (!m_module_sp && !IsKernel() && m_uuid.IsValid() && !m_name.empty())
+ {
+ Stream *s = target.GetDebugger().GetOutputFile().get();
+ if (s)
+ {
+ s->Printf ("warning: Can't find binary/dSYM for %s (%s)\n",
+ m_name.c_str(), m_uuid.GetAsString().c_str());
+ }
+ }
+
+ static ConstString g_section_name_LINKEDIT ("__LINKEDIT");
+
+ if (m_memory_module_sp && m_module_sp)
+ {
+ if (m_module_sp->GetUUID() == m_memory_module_sp->GetUUID())
+ {
+ ObjectFile *ondisk_object_file = m_module_sp->GetObjectFile();
+ ObjectFile *memory_object_file = m_memory_module_sp->GetObjectFile();
+
+ if (memory_object_file && ondisk_object_file)
+ {
+ // The memory_module for kexts may have an invalid __LINKEDIT seg; skip it.
+ const bool ignore_linkedit = !IsKernel ();
+
+ SectionList *ondisk_section_list = ondisk_object_file->GetSectionList ();
+ SectionList *memory_section_list = memory_object_file->GetSectionList ();
+ if (memory_section_list && ondisk_section_list)
+ {
+ const uint32_t num_ondisk_sections = ondisk_section_list->GetSize();
+ // There may be CTF sections in the memory image so we can't
+ // always just compare the number of sections (which are actually
+ // segments in mach-o parlance)
+ uint32_t sect_idx = 0;
+
+ // Use the memory_module's addresses for each section to set the
+ // file module's load address as appropriate. We don't want to use
+ // a single slide value for the entire kext - different segments may
+ // be slid different amounts by the kext loader.
+
+ uint32_t num_sections_loaded = 0;
+ for (sect_idx=0; sect_idx<num_ondisk_sections; ++sect_idx)
+ {
+ SectionSP ondisk_section_sp(ondisk_section_list->GetSectionAtIndex(sect_idx));
+ if (ondisk_section_sp)
+ {
+ // Don't ever load __LINKEDIT as it may or may not be actually
+ // mapped into memory and there is no current way to tell.
+ // I filed rdar://problem/12851706 to track being able to tell
+ // if the __LINKEDIT is actually mapped, but until then, we need
+ // to not load the __LINKEDIT
+ if (ignore_linkedit && ondisk_section_sp->GetName() == g_section_name_LINKEDIT)
+ continue;
+
+ const Section *memory_section = memory_section_list->FindSectionByName(ondisk_section_sp->GetName()).get();
+ if (memory_section)
+ {
+ target.SetSectionLoadAddress (ondisk_section_sp, memory_section->GetFileAddress());
+ ++num_sections_loaded;
+ }
+ }
+ }
+ if (num_sections_loaded > 0)
+ m_load_process_stop_id = process->GetStopID();
+ else
+ m_module_sp.reset(); // No sections were loaded
+ }
+ else
+ m_module_sp.reset(); // One or both section lists
+ }
+ else
+ m_module_sp.reset(); // One or both object files missing
+ }
+ else
+ m_module_sp.reset(); // UUID mismatch
+ }
+
+ bool is_loaded = IsLoaded();
+
+ if (is_loaded && m_module_sp && IsKernel())
+ {
+ Stream *s = target.GetDebugger().GetOutputFile().get();
+ if (s)
+ {
+ ObjectFile *kernel_object_file = m_module_sp->GetObjectFile();
+ if (kernel_object_file)
+ {
+ addr_t file_address = kernel_object_file->GetHeaderAddress().GetFileAddress();
+ if (m_load_address != LLDB_INVALID_ADDRESS && file_address != LLDB_INVALID_ADDRESS)
+ {
+ s->Printf ("Kernel slid 0x%" PRIx64 " in memory.\n", m_load_address - file_address);
+ }
+ }
+ {
+ s->Printf ("Loaded kernel file %s\n",
+ m_module_sp->GetFileSpec().GetPath().c_str());
+ }
+ s->Flush ();
+ }
+ }
+ return is_loaded;
+}
+
+uint32_t
+DynamicLoaderDarwinKernel::KextImageInfo::GetAddressByteSize ()
+{
+ if (m_memory_module_sp)
+ return m_memory_module_sp->GetArchitecture().GetAddressByteSize();
+ if (m_module_sp)
+ return m_module_sp->GetArchitecture().GetAddressByteSize();
+ return 0;
+}
+
+lldb::ByteOrder
+DynamicLoaderDarwinKernel::KextImageInfo::GetByteOrder()
+{
+ if (m_memory_module_sp)
+ return m_memory_module_sp->GetArchitecture().GetByteOrder();
+ if (m_module_sp)
+ return m_module_sp->GetArchitecture().GetByteOrder();
+ return endian::InlHostByteOrder();
+}
+
+lldb_private::ArchSpec
+DynamicLoaderDarwinKernel::KextImageInfo::GetArchitecture () const
+{
+ if (m_memory_module_sp)
+ return m_memory_module_sp->GetArchitecture();
+ if (m_module_sp)
+ return m_module_sp->GetArchitecture();
+ return lldb_private::ArchSpec ();
+}
+
+
+//----------------------------------------------------------------------
+// Load the kernel module and initialize the "m_kernel" member. Return
+// true _only_ if the kernel is loaded the first time through (subsequent
+// calls to this function should return false after the kernel has been
+// already loaded).
+//----------------------------------------------------------------------
+void
+DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded()
+{
+ if (!m_kext_summary_header_ptr_addr.IsValid())
+ {
+ m_kernel.Clear();
+ m_kernel.SetModule (m_process->GetTarget().GetExecutableModule());
+ m_kernel.SetIsKernel(true);
+
+ ConstString kernel_name("mach_kernel");
+ if (m_kernel.GetModule().get()
+ && m_kernel.GetModule()->GetObjectFile()
+ && !m_kernel.GetModule()->GetObjectFile()->GetFileSpec().GetFilename().IsEmpty())
+ {
+ kernel_name = m_kernel.GetModule()->GetObjectFile()->GetFileSpec().GetFilename();
+ }
+ m_kernel.SetName (kernel_name.AsCString());
+
+ if (m_kernel.GetLoadAddress() == LLDB_INVALID_ADDRESS)
+ {
+ m_kernel.SetLoadAddress(m_kernel_load_address);
+ if (m_kernel.GetLoadAddress() == LLDB_INVALID_ADDRESS && m_kernel.GetModule())
+ {
+ // We didn't get a hint from the process, so we will
+ // try the kernel at the address that it exists at in
+ // the file if we have one
+ ObjectFile *kernel_object_file = m_kernel.GetModule()->GetObjectFile();
+ if (kernel_object_file)
+ {
+ addr_t load_address = kernel_object_file->GetHeaderAddress().GetLoadAddress(&m_process->GetTarget());
+ addr_t file_address = kernel_object_file->GetHeaderAddress().GetFileAddress();
+ if (load_address != LLDB_INVALID_ADDRESS && load_address != 0)
+ {
+ m_kernel.SetLoadAddress (load_address);
+ if (load_address != file_address)
+ {
+ // Don't accidentally relocate the kernel to the File address --
+ // the Load address has already been set to its actual in-memory address.
+ // Mark it as IsLoaded.
+ m_kernel.SetProcessStopId (m_process->GetStopID());
+ }
+ }
+ else
+ {
+ m_kernel.SetLoadAddress(file_address);
+ }
+ }
+ }
+ }
+
+ if (m_kernel.GetLoadAddress() != LLDB_INVALID_ADDRESS)
+ {
+ if (!m_kernel.LoadImageUsingMemoryModule (m_process))
+ {
+ m_kernel.LoadImageAtFileAddress (m_process);
+ }
+ }
+
+ if (m_kernel.IsLoaded() && m_kernel.GetModule())
+ {
+ static ConstString kext_summary_symbol ("gLoadedKextSummaries");
+ const Symbol *symbol = m_kernel.GetModule()->FindFirstSymbolWithNameAndType (kext_summary_symbol, eSymbolTypeData);
+ if (symbol)
+ {
+ m_kext_summary_header_ptr_addr = symbol->GetAddress();
+ // Update all image infos
+ ReadAllKextSummaries ();
+ }
+ }
+ else
+ {
+ m_kernel.Clear();
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Static callback function that gets called when our DYLD notification
+// breakpoint gets hit. We update all of our image infos and then
+// let our super class DynamicLoader class decide if we should stop
+// or not (based on global preference).
+//----------------------------------------------------------------------
+bool
+DynamicLoaderDarwinKernel::BreakpointHitCallback (void *baton,
+ StoppointCallbackContext *context,
+ user_id_t break_id,
+ user_id_t break_loc_id)
+{
+ return static_cast<DynamicLoaderDarwinKernel*>(baton)->BreakpointHit (context, break_id, break_loc_id);
+}
+
+bool
+DynamicLoaderDarwinKernel::BreakpointHit (StoppointCallbackContext *context,
+ user_id_t break_id,
+ user_id_t break_loc_id)
+{
+ Log *log(GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf ("DynamicLoaderDarwinKernel::BreakpointHit (...)\n");
+
+ ReadAllKextSummaries ();
+
+ if (log)
+ PutToLog(log);
+
+ return GetStopWhenImagesChange();
+}
+
+
+bool
+DynamicLoaderDarwinKernel::ReadKextSummaryHeader ()
+{
+ Mutex::Locker locker(m_mutex);
+
+ // the all image infos is already valid for this process stop ID
+
+ if (m_kext_summary_header_ptr_addr.IsValid())
+ {
+ const uint32_t addr_size = m_kernel.GetAddressByteSize ();
+ const ByteOrder byte_order = m_kernel.GetByteOrder();
+ Error error;
+ // Read enough bytes for a "OSKextLoadedKextSummaryHeader" structure
+ // which is currently 4 uint32_t and a pointer.
+ uint8_t buf[24];
+ DataExtractor data (buf, sizeof(buf), byte_order, addr_size);
+ const size_t count = 4 * sizeof(uint32_t) + addr_size;
+ const bool prefer_file_cache = false;
+ if (m_process->GetTarget().ReadPointerFromMemory (m_kext_summary_header_ptr_addr,
+ prefer_file_cache,
+ error,
+ m_kext_summary_header_addr))
+ {
+ // We got a valid address for our kext summary header and make sure it isn't NULL
+ if (m_kext_summary_header_addr.IsValid() &&
+ m_kext_summary_header_addr.GetFileAddress() != 0)
+ {
+ const size_t bytes_read = m_process->GetTarget().ReadMemory (m_kext_summary_header_addr, prefer_file_cache, buf, count, error);
+ if (bytes_read == count)
+ {
+ lldb::offset_t offset = 0;
+ m_kext_summary_header.version = data.GetU32(&offset);
+ if (m_kext_summary_header.version > 128)
+ {
+ Stream *s = m_process->GetTarget().GetDebugger().GetOutputFile().get();
+ s->Printf ("WARNING: Unable to read kext summary header, got improbable version number %u\n", m_kext_summary_header.version);
+ // If we get an improbably large version number, we're probably getting bad memory.
+ m_kext_summary_header_addr.Clear();
+ return false;
+ }
+ if (m_kext_summary_header.version >= 2)
+ {
+ m_kext_summary_header.entry_size = data.GetU32(&offset);
+ if (m_kext_summary_header.entry_size > 4096)
+ {
+ // If we get an improbably large entry_size, we're probably getting bad memory.
+ Stream *s = m_process->GetTarget().GetDebugger().GetOutputFile().get();
+ s->Printf ("WARNING: Unable to read kext summary header, got improbable entry_size %u\n", m_kext_summary_header.entry_size);
+ m_kext_summary_header_addr.Clear();
+ return false;
+ }
+ }
+ else
+ {
+ // Versions less than 2 didn't have an entry size, it was hard coded
+ m_kext_summary_header.entry_size = KERNEL_MODULE_ENTRY_SIZE_VERSION_1;
+ }
+ m_kext_summary_header.entry_count = data.GetU32(&offset);
+ if (m_kext_summary_header.entry_count > 10000)
+ {
+ // If we get an improbably large number of kexts, we're probably getting bad memory.
+ Stream *s = m_process->GetTarget().GetDebugger().GetOutputFile().get();
+ s->Printf ("WARNING: Unable to read kext summary header, got improbable number of kexts %u\n", m_kext_summary_header.entry_count);
+ m_kext_summary_header_addr.Clear();
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ }
+ m_kext_summary_header_addr.Clear();
+ return false;
+}
+
+// We've either (a) just attached to a new kernel, or (b) the kexts-changed breakpoint was hit
+// and we need to figure out what kexts have been added or removed.
+// Read the kext summaries from the inferior kernel memory, compare them against the
+// m_known_kexts vector and update the m_known_kexts vector as needed to keep in sync with the
+// inferior.
+
+bool
+DynamicLoaderDarwinKernel::ParseKextSummaries (const Address &kext_summary_addr, uint32_t count)
+{
+ KextImageInfo::collection kext_summaries;
+ Log *log(GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf ("Kexts-changed breakpoint hit, there are %d kexts currently.\n", count);
+
+ Mutex::Locker locker(m_mutex);
+
+ if (!ReadKextSummaries (kext_summary_addr, count, kext_summaries))
+ return false;
+
+ // read the plugin.dynamic-loader.darwin-kernel.load-kexts setting -- if the user requested no
+ // kext loading, don't print any messages about kexts & don't try to read them.
+ const bool load_kexts = GetGlobalProperties()->GetLoadKexts();
+
+ // By default, all kexts we've loaded in the past are marked as "remove" and all of the kexts
+ // we just found out about from ReadKextSummaries are marked as "add".
+ std::vector<bool> to_be_removed(m_known_kexts.size(), true);
+ std::vector<bool> to_be_added(count, true);
+
+ int number_of_new_kexts_being_added = 0;
+ int number_of_old_kexts_being_removed = m_known_kexts.size();
+
+ const uint32_t new_kexts_size = kext_summaries.size();
+ const uint32_t old_kexts_size = m_known_kexts.size();
+
+ // The m_known_kexts vector may have entries that have been Cleared,
+ // or are a kernel.
+ for (uint32_t old_kext = 0; old_kext < old_kexts_size; old_kext++)
+ {
+ bool ignore = false;
+ KextImageInfo &image_info = m_known_kexts[old_kext];
+ if (image_info.IsKernel())
+ {
+ ignore = true;
+ }
+ else if (image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS && !image_info.GetModule())
+ {
+ ignore = true;
+ }
+
+ if (ignore)
+ {
+ number_of_old_kexts_being_removed--;
+ to_be_removed[old_kext] = false;
+ }
+ }
+
+ // Scan over the list of kexts we just read from the kernel, note those that
+ // need to be added and those already loaded.
+ for (uint32_t new_kext = 0; new_kext < new_kexts_size; new_kext++)
+ {
+ bool add_this_one = true;
+ for (uint32_t old_kext = 0; old_kext < old_kexts_size; old_kext++)
+ {
+ if (m_known_kexts[old_kext] == kext_summaries[new_kext])
+ {
+ // We already have this kext, don't re-load it.
+ to_be_added[new_kext] = false;
+ // This kext is still present, do not remove it.
+ to_be_removed[old_kext] = false;
+
+ number_of_old_kexts_being_removed--;
+ add_this_one = false;
+ break;
+ }
+ }
+ if (add_this_one)
+ {
+ number_of_new_kexts_being_added++;
+ }
+ }
+
+ if (number_of_new_kexts_being_added == 0 && number_of_old_kexts_being_removed == 0)
+ return true;
+
+ Stream *s = m_process->GetTarget().GetDebugger().GetOutputFile().get();
+ if (s && load_kexts)
+ {
+ if (number_of_new_kexts_being_added > 0 && number_of_old_kexts_being_removed > 0)
+ {
+ s->Printf ("Loading %d kext modules and unloading %d kext modules ", number_of_new_kexts_being_added, number_of_old_kexts_being_removed);
+ }
+ else if (number_of_new_kexts_being_added > 0)
+ {
+ s->Printf ("Loading %d kext modules ", number_of_new_kexts_being_added);
+ }
+ else if (number_of_old_kexts_being_removed > 0)
+ {
+ s->Printf ("Unloading %d kext modules ", number_of_old_kexts_being_removed);
+ }
+ }
+
+ if (log)
+ {
+ if (load_kexts)
+ {
+ log->Printf ("DynamicLoaderDarwinKernel::ParseKextSummaries: %d kexts added, %d kexts removed", number_of_new_kexts_being_added, number_of_old_kexts_being_removed);
+ }
+ else
+ {
+ log->Printf ("DynamicLoaderDarwinKernel::ParseKextSummaries kext loading is disabled, else would have %d kexts added, %d kexts removed", number_of_new_kexts_being_added, number_of_old_kexts_being_removed);
+ }
+ }
+
+
+ if (number_of_new_kexts_being_added > 0)
+ {
+ ModuleList loaded_module_list;
+
+ const uint32_t num_of_new_kexts = kext_summaries.size();
+ for (uint32_t new_kext = 0; new_kext < num_of_new_kexts; new_kext++)
+ {
+ if (to_be_added[new_kext] == true)
+ {
+ KextImageInfo &image_info = kext_summaries[new_kext];
+ if (load_kexts)
+ {
+ if (!image_info.LoadImageUsingMemoryModule (m_process))
+ {
+ image_info.LoadImageAtFileAddress (m_process);
+ }
+ }
+
+ m_known_kexts.push_back(image_info);
+
+ if (image_info.GetModule() && m_process->GetStopID() == image_info.GetProcessStopId())
+ loaded_module_list.AppendIfNeeded (image_info.GetModule());
+
+ if (s && load_kexts)
+ s->Printf (".");
+
+ if (log)
+ kext_summaries[new_kext].PutToLog (log);
+ }
+ }
+ m_process->GetTarget().ModulesDidLoad (loaded_module_list);
+ }
+
+ if (number_of_old_kexts_being_removed > 0)
+ {
+ ModuleList loaded_module_list;
+ const uint32_t num_of_old_kexts = m_known_kexts.size();
+ for (uint32_t old_kext = 0; old_kext < num_of_old_kexts; old_kext++)
+ {
+ ModuleList unloaded_module_list;
+ if (to_be_removed[old_kext])
+ {
+ KextImageInfo &image_info = m_known_kexts[old_kext];
+ // You can't unload the kernel.
+ if (!image_info.IsKernel())
+ {
+ if (image_info.GetModule())
+ {
+ unloaded_module_list.AppendIfNeeded (image_info.GetModule());
+ }
+ if (s)
+ s->Printf (".");
+ image_info.Clear();
+ // should pull it out of the KextImageInfos vector but that would mutate the list and invalidate
+ // the to_be_removed bool vector; leaving it in place once Cleared() is relatively harmless.
+ }
+ }
+ m_process->GetTarget().ModulesDidUnload (unloaded_module_list, false);
+ }
+ }
+
+ if (s && load_kexts)
+ {
+ s->Printf (" done.\n");
+ s->Flush ();
+ }
+
+ return true;
+}
+
+uint32_t
+DynamicLoaderDarwinKernel::ReadKextSummaries (const Address &kext_summary_addr,
+ uint32_t image_infos_count,
+ KextImageInfo::collection &image_infos)
+{
+ const ByteOrder endian = m_kernel.GetByteOrder();
+ const uint32_t addr_size = m_kernel.GetAddressByteSize();
+
+ image_infos.resize(image_infos_count);
+ const size_t count = image_infos.size() * m_kext_summary_header.entry_size;
+ DataBufferHeap data(count, 0);
+ Error error;
+
+ const bool prefer_file_cache = false;
+ const size_t bytes_read = m_process->GetTarget().ReadMemory (kext_summary_addr,
+ prefer_file_cache,
+ data.GetBytes(),
+ data.GetByteSize(),
+ error);
+ if (bytes_read == count)
+ {
+
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), endian, addr_size);
+ uint32_t i=0;
+ for (uint32_t kext_summary_offset = 0;
+ i < image_infos.size() && extractor.ValidOffsetForDataOfSize(kext_summary_offset, m_kext_summary_header.entry_size);
+ ++i, kext_summary_offset += m_kext_summary_header.entry_size)
+ {
+ lldb::offset_t offset = kext_summary_offset;
+ const void *name_data = extractor.GetData(&offset, KERNEL_MODULE_MAX_NAME);
+ if (name_data == NULL)
+ break;
+ image_infos[i].SetName ((const char *) name_data);
+ UUID uuid (extractor.GetData (&offset, 16), 16);
+ image_infos[i].SetUUID (uuid);
+ image_infos[i].SetLoadAddress (extractor.GetU64(&offset));
+ image_infos[i].SetSize (extractor.GetU64(&offset));
+ }
+ if (i < image_infos.size())
+ image_infos.resize(i);
+ }
+ else
+ {
+ image_infos.clear();
+ }
+ return image_infos.size();
+}
+
+bool
+DynamicLoaderDarwinKernel::ReadAllKextSummaries ()
+{
+ Mutex::Locker locker(m_mutex);
+
+ if (ReadKextSummaryHeader ())
+ {
+ if (m_kext_summary_header.entry_count > 0 && m_kext_summary_header_addr.IsValid())
+ {
+ Address summary_addr (m_kext_summary_header_addr);
+ summary_addr.Slide(m_kext_summary_header.GetSize());
+ if (!ParseKextSummaries (summary_addr, m_kext_summary_header.entry_count))
+ {
+ m_known_kexts.clear();
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Dump an image info structure to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderDarwinKernel::KextImageInfo::PutToLog (Log *log) const
+{
+ if (log == NULL)
+ return;
+ const uint8_t *u = (uint8_t *) m_uuid.GetBytes();
+
+ if (m_load_address == LLDB_INVALID_ADDRESS)
+ {
+ if (u)
+ {
+ log->Printf("\tuuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X name=\"%s\" (UNLOADED)",
+ u[ 0], u[ 1], u[ 2], u[ 3],
+ u[ 4], u[ 5], u[ 6], u[ 7],
+ u[ 8], u[ 9], u[10], u[11],
+ u[12], u[13], u[14], u[15],
+ m_name.c_str());
+ }
+ else
+ log->Printf("\tname=\"%s\" (UNLOADED)", m_name.c_str());
+ }
+ else
+ {
+ if (u)
+ {
+ log->Printf("\taddr=0x%16.16" PRIx64 " size=0x%16.16" PRIx64 " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X name=\"%s\"",
+ m_load_address, m_size,
+ u[ 0], u[ 1], u[ 2], u[ 3], u[ 4], u[ 5], u[ 6], u[ 7],
+ u[ 8], u[ 9], u[10], u[11], u[12], u[13], u[14], u[15],
+ m_name.c_str());
+ }
+ else
+ {
+ log->Printf("\t[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") name=\"%s\"",
+ m_load_address, m_load_address+m_size, m_name.c_str());
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Dump the _dyld_all_image_infos members and all current image infos
+// that we have parsed to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderDarwinKernel::PutToLog(Log *log) const
+{
+ if (log == NULL)
+ return;
+
+ Mutex::Locker locker(m_mutex);
+ log->Printf("gLoadedKextSummaries = 0x%16.16" PRIx64 " { version=%u, entry_size=%u, entry_count=%u }",
+ m_kext_summary_header_addr.GetFileAddress(),
+ m_kext_summary_header.version,
+ m_kext_summary_header.entry_size,
+ m_kext_summary_header.entry_count);
+
+ size_t i;
+ const size_t count = m_known_kexts.size();
+ if (count > 0)
+ {
+ log->PutCString("Loaded:");
+ for (i = 0; i<count; i++)
+ m_known_kexts[i].PutToLog(log);
+ }
+}
+
+void
+DynamicLoaderDarwinKernel::PrivateInitialize(Process *process)
+{
+ DEBUG_PRINTF("DynamicLoaderDarwinKernel::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
+ Clear(true);
+ m_process = process;
+}
+
+void
+DynamicLoaderDarwinKernel::SetNotificationBreakpointIfNeeded ()
+{
+ if (m_break_id == LLDB_INVALID_BREAK_ID && m_kernel.GetModule())
+ {
+ DEBUG_PRINTF("DynamicLoaderDarwinKernel::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
+
+
+ const bool internal_bp = true;
+ const bool hardware = false;
+ const LazyBool skip_prologue = eLazyBoolNo;
+ FileSpecList module_spec_list;
+ module_spec_list.Append (m_kernel.GetModule()->GetFileSpec());
+ Breakpoint *bp = m_process->GetTarget().CreateBreakpoint (&module_spec_list,
+ NULL,
+ "OSKextLoadedKextSummariesUpdated",
+ eFunctionNameTypeFull,
+ eLanguageTypeUnknown,
+ skip_prologue,
+ internal_bp,
+ hardware).get();
+
+ bp->SetCallback (DynamicLoaderDarwinKernel::BreakpointHitCallback, this, true);
+ m_break_id = bp->GetID();
+ }
+}
+
+//----------------------------------------------------------------------
+// Member function that gets called when the process state changes.
+//----------------------------------------------------------------------
+void
+DynamicLoaderDarwinKernel::PrivateProcessStateChanged (Process *process, StateType state)
+{
+ DEBUG_PRINTF("DynamicLoaderDarwinKernel::%s(%s)\n", __FUNCTION__, StateAsCString(state));
+ switch (state)
+ {
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ case eStateDetached:
+ Clear(false);
+ break;
+
+ case eStateStopped:
+ UpdateIfNeeded();
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ break;
+ }
+}
+
+ThreadPlanSP
+DynamicLoaderDarwinKernel::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others)
+{
+ ThreadPlanSP thread_plan_sp;
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf ("Could not find symbol for step through.");
+ return thread_plan_sp;
+}
+
+Error
+DynamicLoaderDarwinKernel::CanLoadImage ()
+{
+ Error error;
+ error.SetErrorString("always unsafe to load or unload shared libraries in the darwin kernel");
+ return error;
+}
+
+void
+DynamicLoaderDarwinKernel::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ DebuggerInitialize);
+}
+
+void
+DynamicLoaderDarwinKernel::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+void
+DynamicLoaderDarwinKernel::DebuggerInitialize (lldb_private::Debugger &debugger)
+{
+ if (!PluginManager::GetSettingForDynamicLoaderPlugin (debugger, DynamicLoaderDarwinKernelProperties::GetSettingName()))
+ {
+ const bool is_global_setting = true;
+ PluginManager::CreateSettingForDynamicLoaderPlugin (debugger,
+ GetGlobalProperties()->GetValueProperties(),
+ ConstString ("Properties for the DynamicLoaderDarwinKernel plug-in."),
+ is_global_setting);
+ }
+}
+
+lldb_private::ConstString
+DynamicLoaderDarwinKernel::GetPluginNameStatic()
+{
+ static ConstString g_name("darwin-kernel");
+ return g_name;
+}
+
+const char *
+DynamicLoaderDarwinKernel::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that watches for shared library loads/unloads in the MacOSX kernel.";
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+DynamicLoaderDarwinKernel::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DynamicLoaderDarwinKernel::GetPluginVersion()
+{
+ return 1;
+}
+
+lldb::ByteOrder
+DynamicLoaderDarwinKernel::GetByteOrderFromMagic (uint32_t magic)
+{
+ switch (magic)
+ {
+ case llvm::MachO::MH_MAGIC:
+ case llvm::MachO::MH_MAGIC_64:
+ return endian::InlHostByteOrder();
+
+ case llvm::MachO::MH_CIGAM:
+ case llvm::MachO::MH_CIGAM_64:
+ if (endian::InlHostByteOrder() == lldb::eByteOrderBig)
+ return lldb::eByteOrderLittle;
+ else
+ return lldb::eByteOrderBig;
+
+ default:
+ break;
+ }
+ return lldb::eByteOrderInvalid;
+}
+
diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h
new file mode 100644
index 000000000000..7ebda48cec93
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h
@@ -0,0 +1,371 @@
+//===-- DynamicLoaderDarwinKernel.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_DynamicLoaderDarwinKernel_h_
+#define liblldb_DynamicLoaderDarwinKernel_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+
+class DynamicLoaderDarwinKernel : public lldb_private::DynamicLoader
+{
+public:
+ DynamicLoaderDarwinKernel(lldb_private::Process *process, lldb::addr_t kernel_addr);
+
+ ~DynamicLoaderDarwinKernel() override;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance (lldb_private::Process *process, bool force);
+
+ static void
+ DebuggerInitialize (lldb_private::Debugger &debugger);
+
+ //------------------------------------------------------------------
+ /// Called after attaching a process.
+ ///
+ /// Allow DynamicLoader plug-ins to execute some code after
+ /// attaching to a process.
+ //------------------------------------------------------------------
+ void
+ DidAttach() override;
+
+ void
+ DidLaunch() override;
+
+ lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+ bool stop_others) override;
+
+ lldb_private::Error
+ CanLoadImage() override;
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+protected:
+ void
+ PrivateInitialize (lldb_private::Process *process);
+
+ void
+ PrivateProcessStateChanged (lldb_private::Process *process,
+ lldb::StateType state);
+
+ void
+ UpdateIfNeeded();
+
+ void
+ LoadKernelModuleIfNeeded ();
+
+ void
+ Clear (bool clear_process);
+
+ void
+ PutToLog (lldb_private::Log *log) const;
+
+ static bool
+ BreakpointHitCallback (void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ bool
+ BreakpointHit (lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+ uint32_t
+ GetAddrByteSize()
+ {
+ return m_kernel.GetAddressByteSize();
+ }
+
+ static lldb::ByteOrder
+ GetByteOrderFromMagic (uint32_t magic);
+
+ enum
+ {
+ KERNEL_MODULE_MAX_NAME = 64u,
+ // Versions less than 2 didn't have an entry size,
+ // they had a 64 bit name, 16 byte UUID, 8 byte addr,
+ // 8 byte size, 8 byte version, 4 byte load tag, and
+ // 4 byte flags
+ KERNEL_MODULE_ENTRY_SIZE_VERSION_1 = 64u + 16u + 8u + 8u + 8u + 4u + 4u
+ };
+
+ // class KextImageInfo represents a single kext or kernel binary image.
+ // The class was designed to hold the information from the OSKextLoadedKextSummary
+ // structure (in libkern/libkern/OSKextLibPrivate.h from xnu). The kernel maintains
+ // a list of loded kexts in memory (the OSKextLoadedKextSummaryHeader structure,
+ // which points to an array of OSKextLoadedKextSummary's).
+ //
+ // A KextImageInfos may have -
+ //
+ // 1. The load address, name, UUID, and size of a kext/kernel binary in memory
+ // (read straight out of the kernel's list-of-kexts loaded)
+ // 2. A ModuleSP based on a MemoryModule read out of the kernel's memory
+ // (very unlikely to have any symbolic information)
+ // 3. A ModuleSP for an on-disk copy of the kext binary, possibly with debug info
+ // or a dSYM
+ //
+ // For performance reasons, the developer may prefer that lldb not load the kexts out
+ // of memory at the start of a kernel session. But we should build up / maintain a
+ // list of kexts that the kernel has told us about so we can relocate a kext module
+ // later if the user explicitly adds it to the target.
+
+ class KextImageInfo
+ {
+ public:
+ KextImageInfo () :
+ m_name (),
+ m_module_sp (),
+ m_memory_module_sp (),
+ m_load_process_stop_id (UINT32_MAX),
+ m_uuid (),
+ m_load_address (LLDB_INVALID_ADDRESS),
+ m_size (0),
+ m_kernel_image (false)
+ { }
+
+ void
+ Clear ()
+ {
+ m_load_address = LLDB_INVALID_ADDRESS;
+ m_size = 0;
+ m_name.clear ();
+ m_uuid.Clear();
+ m_module_sp.reset();
+ m_memory_module_sp.reset();
+ m_load_process_stop_id = UINT32_MAX;
+ }
+
+ bool
+ LoadImageAtFileAddress (lldb_private::Process *process);
+
+ bool
+ LoadImageUsingMemoryModule (lldb_private::Process *process);
+
+ bool
+ IsLoaded ()
+ {
+ return m_load_process_stop_id != UINT32_MAX;
+ }
+
+ void
+ SetLoadAddress (lldb::addr_t load_addr); // Address of the Mach-O header for this binary
+
+ lldb::addr_t
+ GetLoadAddress () const; // Address of the Mach-O header for this binary
+
+ lldb_private::UUID
+ GetUUID () const;
+
+ void
+ SetUUID (const lldb_private::UUID &uuid);
+
+ void
+ SetName (const char *);
+
+ std::string
+ GetName () const;
+
+ void
+ SetModule (lldb::ModuleSP module);
+
+ lldb::ModuleSP
+ GetModule ();
+
+ // try to fill in m_memory_module_sp from memory based on the m_load_address
+ bool
+ ReadMemoryModule (lldb_private::Process *process);
+
+ bool
+ IsKernel () const; // true if this is the mach_kernel; false if this is a kext
+
+ void
+ SetIsKernel (bool is_kernel);
+
+ uint64_t
+ GetSize () const;
+
+ void
+ SetSize (uint64_t size);
+
+ uint32_t
+ GetProcessStopId () const; // the stop-id when this binary was first noticed
+
+ void
+ SetProcessStopId (uint32_t stop_id);
+
+ bool
+ operator== (const KextImageInfo &rhs);
+
+ uint32_t
+ GetAddressByteSize (); // as determined by Mach-O header
+
+ lldb::ByteOrder
+ GetByteOrder(); // as determined by Mach-O header
+
+ lldb_private::ArchSpec
+ GetArchitecture () const; // as determined by Mach-O header
+
+ void
+ PutToLog (lldb_private::Log *log) const;
+
+ typedef std::vector<KextImageInfo> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ private:
+ std::string m_name;
+ lldb::ModuleSP m_module_sp;
+ lldb::ModuleSP m_memory_module_sp;
+ uint32_t m_load_process_stop_id; // the stop-id when this module was added to the Target
+ lldb_private::UUID m_uuid; // UUID for this dylib if it has one, else all zeros
+ lldb::addr_t m_load_address;
+ uint64_t m_size;
+ bool m_kernel_image; // true if this is the kernel, false if this is a kext
+ };
+
+ struct OSKextLoadedKextSummaryHeader
+ {
+ uint32_t version;
+ uint32_t entry_size;
+ uint32_t entry_count;
+ lldb::addr_t image_infos_addr;
+
+ OSKextLoadedKextSummaryHeader() :
+ version (0),
+ entry_size (0),
+ entry_count (0),
+ image_infos_addr (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ uint32_t
+ GetSize()
+ {
+ switch (version)
+ {
+ case 0: return 0; // Can't know the size without a valid version
+ case 1: return 8; // Version 1 only had a version + entry_count
+ default: break;
+ }
+ // Version 2 and above has version, entry_size, entry_count, and reserved
+ return 16;
+ }
+
+ void
+ Clear()
+ {
+ version = 0;
+ entry_size = 0;
+ entry_count = 0;
+ image_infos_addr = LLDB_INVALID_ADDRESS;
+ }
+
+ bool
+ IsValid() const
+ {
+ return version >= 1 || version <= 2;
+ }
+ };
+
+ void
+ RegisterNotificationCallbacks();
+
+ void
+ UnregisterNotificationCallbacks();
+
+ void
+ SetNotificationBreakpointIfNeeded ();
+
+ bool
+ ReadAllKextSummaries ();
+
+ bool
+ ReadKextSummaryHeader ();
+
+ bool
+ ParseKextSummaries (const lldb_private::Address &kext_summary_addr,
+ uint32_t count);
+
+ void
+ UpdateImageInfosHeaderAndLoadCommands(KextImageInfo::collection &image_infos,
+ uint32_t infos_count,
+ bool update_executable);
+
+ uint32_t
+ ReadKextSummaries (const lldb_private::Address &kext_summary_addr,
+ uint32_t image_infos_count,
+ KextImageInfo::collection &image_infos);
+
+ static lldb::addr_t
+ SearchForDarwinKernel (lldb_private::Process *process);
+
+ static lldb::addr_t
+ SearchForKernelAtSameLoadAddr (lldb_private::Process *process);
+
+ static lldb::addr_t
+ SearchForKernelWithDebugHints (lldb_private::Process *process);
+
+ static lldb::addr_t
+ SearchForKernelNearPC (lldb_private::Process *process);
+
+ static lldb::addr_t
+ SearchForKernelViaExhaustiveSearch (lldb_private::Process *process);
+
+ static lldb_private::UUID
+ CheckForKernelImageAtAddress (lldb::addr_t addr, lldb_private::Process *process);
+
+ lldb::addr_t m_kernel_load_address;
+ KextImageInfo m_kernel; // Info about the current kernel image being used
+
+ lldb_private::Address m_kext_summary_header_ptr_addr;
+ lldb_private::Address m_kext_summary_header_addr;
+ OSKextLoadedKextSummaryHeader m_kext_summary_header;
+ KextImageInfo::collection m_known_kexts;
+ mutable lldb_private::Mutex m_mutex;
+ lldb::user_id_t m_break_id;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (DynamicLoaderDarwinKernel);
+};
+
+#endif // liblldb_DynamicLoaderDarwinKernel_h_
diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/Makefile b/source/Plugins/DynamicLoader/Darwin-Kernel/Makefile
new file mode 100644
index 000000000000..d2342fd06772
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Darwin-Kernel/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Disassembler/llvm/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginDynamicLoaderDarwinKernel
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/CMakeLists.txt b/source/Plugins/DynamicLoader/Hexagon-DYLD/CMakeLists.txt
new file mode 100644
index 000000000000..af15f284118f
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_lldb_library(lldbPluginDynamicLoaderHexagonDYLD
+ HexagonDYLDRendezvous.cpp
+ DynamicLoaderHexagonDYLD.cpp
+ )
diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/Makefile b/source/Plugins/DynamicLoader/Hexagon-DYLD/Makefile
new file mode 100644
index 000000000000..43334562ebb1
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/DynamicLoader/Hexagon-DYLD/Makefile ----*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginDynamicLoaderHexagon
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt b/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt
new file mode 100644
index 000000000000..2c44877662f5
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD
+ DynamicLoaderMacOSXDYLD.cpp
+ )
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
new file mode 100644
index 000000000000..fba11f6aea85
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
@@ -0,0 +1,2075 @@
+//===-- DynamicLoaderMacOSXDYLD.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/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Target/StackFrame.h"
+
+#include "DynamicLoaderMacOSXDYLD.h"
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
+#ifdef ENABLE_DEBUG_PRINTF
+#include <stdio.h>
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+#ifndef __APPLE__
+#include "Utility/UuidCompatibility.h"
+#else
+#include <uuid/uuid.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+/// FIXME - The ObjC Runtime trampoline handler doesn't really belong here.
+/// I am putting it here so I can invoke it in the Trampoline code here, but
+/// it should be moved to the ObjC Runtime support when it is set up.
+
+
+DynamicLoaderMacOSXDYLD::DYLDImageInfo *
+DynamicLoaderMacOSXDYLD::GetImageInfo (Module *module)
+{
+ const UUID &module_uuid = module->GetUUID();
+ DYLDImageInfo::collection::iterator pos, end = m_dyld_image_infos.end();
+
+ // First try just by UUID as it is the safest.
+ if (module_uuid.IsValid())
+ {
+ for (pos = m_dyld_image_infos.begin(); pos != end; ++pos)
+ {
+ if (pos->uuid == module_uuid)
+ return &(*pos);
+ }
+
+ if (m_dyld.uuid == module_uuid)
+ return &m_dyld;
+ }
+
+ // Next try by platform path only for things that don't have a valid UUID
+ // since if a file has a valid UUID in real life it should also in the
+ // dyld info. This is the next safest because the paths in the dyld info
+ // are platform paths, not local paths. For local debugging platform == local
+ // paths.
+ const FileSpec &platform_file_spec = module->GetPlatformFileSpec();
+ for (pos = m_dyld_image_infos.begin(); pos != end; ++pos)
+ {
+ if (pos->file_spec == platform_file_spec && pos->uuid.IsValid() == false)
+ return &(*pos);
+ }
+
+ if (m_dyld.file_spec == platform_file_spec && m_dyld.uuid.IsValid() == false)
+ return &m_dyld;
+
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Create an instance of this class. This function is filled into
+// the plugin info class that gets handed out by the plugin factory and
+// allows the lldb to instantiate an instance of this class.
+//----------------------------------------------------------------------
+DynamicLoader *
+DynamicLoaderMacOSXDYLD::CreateInstance (Process* process, bool force)
+{
+ bool create = force;
+ if (!create)
+ {
+ create = true;
+ Module* exe_module = process->GetTarget().GetExecutableModulePointer();
+ if (exe_module)
+ {
+ ObjectFile *object_file = exe_module->GetObjectFile();
+ if (object_file)
+ {
+ create = (object_file->GetStrata() == ObjectFile::eStrataUser);
+ }
+ }
+
+ if (create)
+ {
+ const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
+ switch (triple_ref.getOS())
+ {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
+ case llvm::Triple::TvOS:
+ case llvm::Triple::WatchOS:
+ create = triple_ref.getVendor() == llvm::Triple::Apple;
+ break;
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+
+ if (create)
+ return new DynamicLoaderMacOSXDYLD (process);
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DynamicLoaderMacOSXDYLD::DynamicLoaderMacOSXDYLD (Process* process) :
+ DynamicLoader(process),
+ m_dyld(),
+ m_dyld_module_wp(),
+ m_dyld_all_image_infos_addr(LLDB_INVALID_ADDRESS),
+ m_dyld_all_image_infos(),
+ m_dyld_all_image_infos_stop_id (UINT32_MAX),
+ m_break_id(LLDB_INVALID_BREAK_ID),
+ m_dyld_image_infos(),
+ m_dyld_image_infos_stop_id (UINT32_MAX),
+ m_mutex(Mutex::eMutexTypeRecursive),
+ m_process_image_addr_is_all_images_infos (false)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoaderMacOSXDYLD::~DynamicLoaderMacOSXDYLD()
+{
+ Clear(true);
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::DidAttach ()
+{
+ PrivateInitialize(m_process);
+ LocateDYLD ();
+ SetNotificationBreakpoint ();
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::DidLaunch ()
+{
+ PrivateInitialize(m_process);
+ LocateDYLD ();
+ SetNotificationBreakpoint ();
+}
+
+bool
+DynamicLoaderMacOSXDYLD::ProcessDidExec ()
+{
+ if (m_process)
+ {
+ // If we are stopped after an exec, we will have only one thread...
+ if (m_process->GetThreadList().GetSize() == 1)
+ {
+ // We know if a process has exec'ed if our "m_dyld_all_image_infos_addr"
+ // value differs from the Process' image info address. When a process
+ // execs itself it might cause a change if ASLR is enabled.
+ const addr_t shlib_addr = m_process->GetImageInfoAddress ();
+ if (m_process_image_addr_is_all_images_infos == true && shlib_addr != m_dyld_all_image_infos_addr)
+ {
+ // The image info address from the process is the 'dyld_all_image_infos'
+ // address and it has changed.
+ return true;
+ }
+
+ if (m_process_image_addr_is_all_images_infos == false && shlib_addr == m_dyld.address)
+ {
+ // The image info address from the process is the mach_header
+ // address for dyld and it has changed.
+ return true;
+ }
+
+ // ASLR might be disabled and dyld could have ended up in the same
+ // location. We should try and detect if we are stopped at '_dyld_start'
+ ThreadSP thread_sp (m_process->GetThreadList().GetThreadAtIndex(0));
+ if (thread_sp)
+ {
+ lldb::StackFrameSP frame_sp (thread_sp->GetStackFrameAtIndex(0));
+ if (frame_sp)
+ {
+ const Symbol *symbol = frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol;
+ if (symbol)
+ {
+ if (symbol->GetName() == ConstString("_dyld_start"))
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+
+//----------------------------------------------------------------------
+// Clear out the state of this class.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::Clear (bool clear_process)
+{
+ Mutex::Locker locker(m_mutex);
+
+ if (LLDB_BREAK_ID_IS_VALID(m_break_id))
+ m_process->GetTarget().RemoveBreakpointByID (m_break_id);
+
+ if (clear_process)
+ m_process = NULL;
+ m_dyld.Clear(false);
+ m_dyld_all_image_infos_addr = LLDB_INVALID_ADDRESS;
+ m_dyld_all_image_infos.Clear();
+ m_break_id = LLDB_INVALID_BREAK_ID;
+ m_dyld_image_infos.clear();
+}
+
+//----------------------------------------------------------------------
+// Check if we have found DYLD yet
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::DidSetNotificationBreakpoint() const
+{
+ return LLDB_BREAK_ID_IS_VALID (m_break_id);
+}
+
+//----------------------------------------------------------------------
+// Try and figure out where dyld is by first asking the Process
+// if it knows (which currently calls down in the lldb::Process
+// to get the DYLD info (available on SnowLeopard only). If that fails,
+// then check in the default addresses.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::LocateDYLD()
+{
+ if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS)
+ {
+ // Check the image info addr as it might point to the
+ // mach header for dyld, or it might point to the
+ // dyld_all_image_infos struct
+ const addr_t shlib_addr = m_process->GetImageInfoAddress ();
+ if (shlib_addr != LLDB_INVALID_ADDRESS)
+ {
+ ByteOrder byte_order = m_process->GetTarget().GetArchitecture().GetByteOrder();
+ uint8_t buf[4];
+ DataExtractor data (buf, sizeof(buf), byte_order, 4);
+ Error error;
+ if (m_process->ReadMemory (shlib_addr, buf, 4, error) == 4)
+ {
+ lldb::offset_t offset = 0;
+ uint32_t magic = data.GetU32 (&offset);
+ switch (magic)
+ {
+ case llvm::MachO::MH_MAGIC:
+ case llvm::MachO::MH_MAGIC_64:
+ case llvm::MachO::MH_CIGAM:
+ case llvm::MachO::MH_CIGAM_64:
+ m_process_image_addr_is_all_images_infos = false;
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback(shlib_addr);
+
+ default:
+ break;
+ }
+ }
+ // Maybe it points to the all image infos?
+ m_dyld_all_image_infos_addr = shlib_addr;
+ m_process_image_addr_is_all_images_infos = true;
+ }
+ }
+
+ if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (ReadAllImageInfosStructure ())
+ {
+ if (m_dyld_all_image_infos.dyldImageLoadAddress != LLDB_INVALID_ADDRESS)
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback (m_dyld_all_image_infos.dyldImageLoadAddress);
+ else
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback (m_dyld_all_image_infos_addr & 0xfffffffffff00000ull);
+ }
+ }
+
+ // Check some default values
+ Module *executable = m_process->GetTarget().GetExecutableModulePointer();
+
+ if (executable)
+ {
+ const ArchSpec &exe_arch = executable->GetArchitecture();
+ if (exe_arch.GetAddressByteSize() == 8)
+ {
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x7fff5fc00000ull);
+ }
+ else if (exe_arch.GetMachine() == llvm::Triple::arm || exe_arch.GetMachine() == llvm::Triple::thumb || exe_arch.GetMachine() == llvm::Triple::aarch64)
+ {
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x2fe00000);
+ }
+ else
+ {
+ return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x8fe00000);
+ }
+ }
+ return false;
+}
+
+ModuleSP
+DynamicLoaderMacOSXDYLD::FindTargetModuleForDYLDImageInfo (DYLDImageInfo &image_info, bool can_create, bool *did_create_ptr)
+{
+ if (did_create_ptr)
+ *did_create_ptr = false;
+
+ Target &target = m_process->GetTarget();
+ const ModuleList &target_images = target.GetImages();
+ ModuleSpec module_spec (image_info.file_spec);
+ module_spec.GetUUID() = image_info.uuid;
+ ModuleSP module_sp (target_images.FindFirstModule (module_spec));
+
+ if (module_sp && !module_spec.GetUUID().IsValid() && !module_sp->GetUUID().IsValid())
+ {
+ // No UUID, we must rely upon the cached module modification
+ // time and the modification time of the file on disk
+ if (module_sp->GetModificationTime() != module_sp->GetFileSpec().GetModificationTime())
+ module_sp.reset();
+ }
+
+ if (!module_sp)
+ {
+ if (can_create)
+ {
+ module_sp = target.GetSharedModule (module_spec);
+ if (!module_sp || module_sp->GetObjectFile() == NULL)
+ module_sp = m_process->ReadModuleFromMemory (image_info.file_spec, image_info.address);
+
+ if (did_create_ptr)
+ *did_create_ptr = (bool) module_sp;
+ }
+ }
+ return module_sp;
+}
+
+//----------------------------------------------------------------------
+// Assume that dyld is in memory at ADDR and try to parse it's load
+// commands
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb::addr_t addr)
+{
+ DataExtractor data; // Load command data
+ if (ReadMachHeader (addr, &m_dyld.header, &data))
+ {
+ if (m_dyld.header.filetype == llvm::MachO::MH_DYLINKER)
+ {
+ m_dyld.address = addr;
+ ModuleSP dyld_module_sp;
+ if (ParseLoadCommands (data, m_dyld, &m_dyld.file_spec))
+ {
+ if (m_dyld.file_spec)
+ {
+ dyld_module_sp = FindTargetModuleForDYLDImageInfo (m_dyld, true, NULL);
+
+ if (dyld_module_sp)
+ UpdateImageLoadAddress (dyld_module_sp.get(), m_dyld);
+ }
+ }
+
+ Target &target = m_process->GetTarget();
+
+ if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS && dyld_module_sp.get())
+ {
+ static ConstString g_dyld_all_image_infos ("dyld_all_image_infos");
+ const Symbol *symbol = dyld_module_sp->FindFirstSymbolWithNameAndType (g_dyld_all_image_infos, eSymbolTypeData);
+ if (symbol)
+ m_dyld_all_image_infos_addr = symbol->GetLoadAddress(&target);
+ }
+
+ // Update all image infos
+ InitializeFromAllImageInfos ();
+
+ // If we didn't have an executable before, but now we do, then the
+ // dyld module shared pointer might be unique and we may need to add
+ // it again (since Target::SetExecutableModule() will clear the
+ // images). So append the dyld module back to the list if it is
+ /// unique!
+ if (dyld_module_sp)
+ {
+ target.GetImages().AppendIfNeeded (dyld_module_sp);
+
+ // At this point we should have read in dyld's module, and so we should set breakpoints in it:
+ ModuleList modules;
+ modules.Append(dyld_module_sp);
+ target.ModulesDidLoad(modules);
+ m_dyld_module_wp = dyld_module_sp;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+DynamicLoaderMacOSXDYLD::NeedToLocateDYLD () const
+{
+ return m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS;
+}
+
+//----------------------------------------------------------------------
+// Update the load addresses for all segments in MODULE using the
+// updated INFO that is passed in.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::UpdateImageLoadAddress (Module *module, DYLDImageInfo& info)
+{
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ std::vector<uint32_t> inaccessible_segment_indexes;
+ // We now know the slide amount, so go through all sections
+ // and update the load addresses with the correct values.
+ const size_t num_segments = info.segments.size();
+ for (size_t i=0; i<num_segments; ++i)
+ {
+ // Only load a segment if it has protections. Things like
+ // __PAGEZERO don't have any protections, and they shouldn't
+ // be slid
+ SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name));
+
+ if (info.segments[i].maxprot == 0)
+ {
+ inaccessible_segment_indexes.push_back(i);
+ }
+ else
+ {
+ const addr_t new_section_load_addr = info.segments[i].vmaddr + info.slide;
+ static ConstString g_section_name_LINKEDIT ("__LINKEDIT");
+
+ if (section_sp)
+ {
+ // __LINKEDIT sections from files in the shared cache
+ // can overlap so check to see what the segment name is
+ // and pass "false" so we don't warn of overlapping
+ // "Section" objects, and "true" for all other sections.
+ const bool warn_multiple = section_sp->GetName() != g_section_name_LINKEDIT;
+
+ changed = m_process->GetTarget().SetSectionLoadAddress (section_sp, new_section_load_addr, warn_multiple);
+ }
+ else
+ {
+ Host::SystemLog (Host::eSystemLogWarning,
+ "warning: unable to find and load segment named '%s' at 0x%" PRIx64 " in '%s' in macosx dynamic loader plug-in.\n",
+ info.segments[i].name.AsCString("<invalid>"),
+ (uint64_t)new_section_load_addr,
+ image_object_file->GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+
+ // If the loaded the file (it changed) and we have segments that
+ // are not readable or writeable, add them to the invalid memory
+ // region cache for the process. This will typically only be
+ // the __PAGEZERO segment in the main executable. We might be able
+ // to apply this more generally to more sections that have no
+ // protections in the future, but for now we are going to just
+ // do __PAGEZERO.
+ if (changed && !inaccessible_segment_indexes.empty())
+ {
+ for (uint32_t i=0; i<inaccessible_segment_indexes.size(); ++i)
+ {
+ const uint32_t seg_idx = inaccessible_segment_indexes[i];
+ SectionSP section_sp(section_list->FindSectionByName(info.segments[seg_idx].name));
+
+ if (section_sp)
+ {
+ static ConstString g_pagezero_section_name("__PAGEZERO");
+ if (g_pagezero_section_name == section_sp->GetName())
+ {
+ // __PAGEZERO never slides...
+ const lldb::addr_t vmaddr = info.segments[seg_idx].vmaddr;
+ const lldb::addr_t vmsize = info.segments[seg_idx].vmsize;
+ Process::LoadRange pagezero_range (vmaddr, vmsize);
+ m_process->AddInvalidMemoryRegion(pagezero_range);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // We might have an in memory image that was loaded as soon as it was created
+ if (info.load_stop_id == m_process->GetStopID())
+ changed = true;
+ else if (changed)
+ {
+ // Update the stop ID when this library was updated
+ info.load_stop_id = m_process->GetStopID();
+ }
+ return changed;
+}
+
+//----------------------------------------------------------------------
+// Update the load addresses for all segments in MODULE using the
+// updated INFO that is passed in.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::UnloadImageLoadAddress (Module *module, DYLDImageInfo& info)
+{
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ const size_t num_segments = info.segments.size();
+ for (size_t i=0; i<num_segments; ++i)
+ {
+ SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name));
+ if (section_sp)
+ {
+ const addr_t old_section_load_addr = info.segments[i].vmaddr + info.slide;
+ if (m_process->GetTarget().SetSectionUnloaded (section_sp, old_section_load_addr))
+ changed = true;
+ }
+ else
+ {
+ Host::SystemLog (Host::eSystemLogWarning,
+ "warning: unable to find and unload segment named '%s' in '%s' in macosx dynamic loader plug-in.\n",
+ info.segments[i].name.AsCString("<invalid>"),
+ image_object_file->GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+
+//----------------------------------------------------------------------
+// Static callback function that gets called when our DYLD notification
+// breakpoint gets hit. We update all of our image infos and then
+// let our super class DynamicLoader class decide if we should stop
+// or not (based on global preference).
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::NotifyBreakpointHit (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id)
+{
+ // Let the event know that the images have changed
+ // DYLD passes three arguments to the notification breakpoint.
+ // Arg1: enum dyld_image_mode mode - 0 = adding, 1 = removing
+ // Arg2: uint32_t infoCount - Number of shared libraries added
+ // Arg3: dyld_image_info info[] - Array of structs of the form:
+ // const struct mach_header *imageLoadAddress
+ // const char *imageFilePath
+ // uintptr_t imageFileModDate (a time_t)
+
+ DynamicLoaderMacOSXDYLD* dyld_instance = (DynamicLoaderMacOSXDYLD*) baton;
+
+ // First step is to see if we've already initialized the all image infos. If we haven't then this function
+ // will do so and return true. In the course of initializing the all_image_infos it will read the complete
+ // current state, so we don't need to figure out what has changed from the data passed in to us.
+
+ ExecutionContext exe_ctx (context->exe_ctx_ref);
+ Process *process = exe_ctx.GetProcessPtr();
+
+ // This is a sanity check just in case this dyld_instance is an old dyld plugin's breakpoint still lying around.
+ if (process != dyld_instance->m_process)
+ return false;
+
+ if (dyld_instance->InitializeFromAllImageInfos())
+ return dyld_instance->GetStopWhenImagesChange();
+
+ const lldb::ABISP &abi = process->GetABI();
+ if (abi)
+ {
+ // Build up the value array to store the three arguments given above, then get the values from the ABI:
+
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+ ValueList argument_values;
+ Value input_value;
+
+ CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ CompilerType clang_uint32_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint, 32);
+ input_value.SetValueType (Value::eValueTypeScalar);
+ input_value.SetCompilerType (clang_uint32_type);
+// input_value.SetContext (Value::eContextTypeClangType, clang_uint32_type);
+ argument_values.PushValue (input_value);
+ argument_values.PushValue (input_value);
+ input_value.SetCompilerType (clang_void_ptr_type);
+ // input_value.SetContext (Value::eContextTypeClangType, clang_void_ptr_type);
+ argument_values.PushValue (input_value);
+
+ if (abi->GetArgumentValues (exe_ctx.GetThreadRef(), argument_values))
+ {
+ uint32_t dyld_mode = argument_values.GetValueAtIndex(0)->GetScalar().UInt (-1);
+ if (dyld_mode != static_cast<uint32_t>(-1))
+ {
+ // Okay the mode was right, now get the number of elements, and the array of new elements...
+ uint32_t image_infos_count = argument_values.GetValueAtIndex(1)->GetScalar().UInt (-1);
+ if (image_infos_count != static_cast<uint32_t>(-1))
+ {
+ // Got the number added, now go through the array of added elements, putting out the mach header
+ // address, and adding the image.
+ // Note, I'm not putting in logging here, since the AddModules & RemoveModules functions do
+ // all the logging internally.
+
+ lldb::addr_t image_infos_addr = argument_values.GetValueAtIndex(2)->GetScalar().ULongLong();
+ if (dyld_mode == 0)
+ {
+ // This is add:
+ dyld_instance->AddModulesUsingImageInfosAddress (image_infos_addr, image_infos_count);
+ }
+ else
+ {
+ // This is remove:
+ dyld_instance->RemoveModulesUsingImageInfosAddress (image_infos_addr, image_infos_count);
+ }
+
+ }
+ }
+ }
+ }
+ else
+ {
+ process->GetTarget().GetDebugger().GetAsyncErrorStream()->Printf("No ABI plugin located for triple %s -- shared libraries will not be registered!\n", process->GetTarget().GetArchitecture().GetTriple().getTriple().c_str());
+ }
+
+ // Return true to stop the target, false to just let the target run
+ return dyld_instance->GetStopWhenImagesChange();
+}
+
+bool
+DynamicLoaderMacOSXDYLD::ReadAllImageInfosStructure ()
+{
+ Mutex::Locker locker(m_mutex);
+
+ // the all image infos is already valid for this process stop ID
+ if (m_process->GetStopID() == m_dyld_all_image_infos_stop_id)
+ return true;
+
+ m_dyld_all_image_infos.Clear();
+ if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS)
+ {
+ ByteOrder byte_order = m_process->GetTarget().GetArchitecture().GetByteOrder();
+ uint32_t addr_size = 4;
+ if (m_dyld_all_image_infos_addr > UINT32_MAX)
+ addr_size = 8;
+
+ uint8_t buf[256];
+ DataExtractor data (buf, sizeof(buf), byte_order, addr_size);
+ lldb::offset_t offset = 0;
+
+ const size_t count_v2 = sizeof (uint32_t) + // version
+ sizeof (uint32_t) + // infoArrayCount
+ addr_size + // infoArray
+ addr_size + // notification
+ addr_size + // processDetachedFromSharedRegion + libSystemInitialized + pad
+ addr_size; // dyldImageLoadAddress
+ const size_t count_v11 = count_v2 +
+ addr_size + // jitInfo
+ addr_size + // dyldVersion
+ addr_size + // errorMessage
+ addr_size + // terminationFlags
+ addr_size + // coreSymbolicationShmPage
+ addr_size + // systemOrderFlag
+ addr_size + // uuidArrayCount
+ addr_size + // uuidArray
+ addr_size + // dyldAllImageInfosAddress
+ addr_size + // initialImageCount
+ addr_size + // errorKind
+ addr_size + // errorClientOfDylibPath
+ addr_size + // errorTargetDylibPath
+ addr_size; // errorSymbol
+ const size_t count_v13 = count_v11 +
+ addr_size + // sharedCacheSlide
+ sizeof (uuid_t); // sharedCacheUUID
+ UNUSED_IF_ASSERT_DISABLED(count_v13);
+ assert (sizeof (buf) >= count_v13);
+
+ Error error;
+ if (m_process->ReadMemory (m_dyld_all_image_infos_addr, buf, 4, error) == 4)
+ {
+ m_dyld_all_image_infos.version = data.GetU32(&offset);
+ // If anything in the high byte is set, we probably got the byte
+ // order incorrect (the process might not have it set correctly
+ // yet due to attaching to a program without a specified file).
+ if (m_dyld_all_image_infos.version & 0xff000000)
+ {
+ // We have guessed the wrong byte order. Swap it and try
+ // reading the version again.
+ if (byte_order == eByteOrderLittle)
+ byte_order = eByteOrderBig;
+ else
+ byte_order = eByteOrderLittle;
+
+ data.SetByteOrder (byte_order);
+ offset = 0;
+ m_dyld_all_image_infos.version = data.GetU32(&offset);
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ const size_t count = (m_dyld_all_image_infos.version >= 11) ? count_v11 : count_v2;
+
+ const size_t bytes_read = m_process->ReadMemory (m_dyld_all_image_infos_addr, buf, count, error);
+ if (bytes_read == count)
+ {
+ offset = 0;
+ m_dyld_all_image_infos.version = data.GetU32(&offset);
+ m_dyld_all_image_infos.dylib_info_count = data.GetU32(&offset);
+ m_dyld_all_image_infos.dylib_info_addr = data.GetPointer(&offset);
+ m_dyld_all_image_infos.notification = data.GetPointer(&offset);
+ m_dyld_all_image_infos.processDetachedFromSharedRegion = data.GetU8(&offset);
+ m_dyld_all_image_infos.libSystemInitialized = data.GetU8(&offset);
+ // Adjust for padding.
+ offset += addr_size - 2;
+ m_dyld_all_image_infos.dyldImageLoadAddress = data.GetPointer(&offset);
+ if (m_dyld_all_image_infos.version >= 11)
+ {
+ offset += addr_size * 8;
+ uint64_t dyld_all_image_infos_addr = data.GetPointer(&offset);
+
+ // When we started, we were given the actual address of the all_image_infos
+ // struct (probably via TASK_DYLD_INFO) in memory - this address is stored in
+ // m_dyld_all_image_infos_addr and is the most accurate address we have.
+
+ // We read the dyld_all_image_infos struct from memory; it contains its own address.
+ // If the address in the struct does not match the actual address,
+ // the dyld we're looking at has been loaded at a different location (slid) from
+ // where it intended to load. The addresses in the dyld_all_image_infos struct
+ // are the original, non-slid addresses, and need to be adjusted. Most importantly
+ // the address of dyld and the notification address need to be adjusted.
+
+ if (dyld_all_image_infos_addr != m_dyld_all_image_infos_addr)
+ {
+ uint64_t image_infos_offset = dyld_all_image_infos_addr - m_dyld_all_image_infos.dyldImageLoadAddress;
+ uint64_t notification_offset = m_dyld_all_image_infos.notification - m_dyld_all_image_infos.dyldImageLoadAddress;
+ m_dyld_all_image_infos.dyldImageLoadAddress = m_dyld_all_image_infos_addr - image_infos_offset;
+ m_dyld_all_image_infos.notification = m_dyld_all_image_infos.dyldImageLoadAddress + notification_offset;
+ }
+ }
+ m_dyld_all_image_infos_stop_id = m_process->GetStopID();
+ return true;
+ }
+ }
+ return false;
+}
+
+
+// This method is an amalgamation of code from
+// ReadMachHeader()
+// ParseLoadCommands()
+// UpdateImageInfosHeaderAndLoadCommands()
+// but written to extract everything from the JSON packet from debugserver, instead of using memory reads.
+
+bool
+DynamicLoaderMacOSXDYLD::AddModulesUsingInfosFromDebugserver (StructuredData::ObjectSP image_details, DYLDImageInfo::collection &image_infos)
+{
+ StructuredData::ObjectSP images_sp = image_details->GetAsDictionary()->GetValueForKey("images");
+ if (images_sp.get() == nullptr)
+ return false;
+
+ image_infos.resize (images_sp->GetAsArray()->GetSize());
+
+ uint32_t exe_idx = UINT32_MAX;
+
+ for (size_t i = 0; i < image_infos.size(); i++)
+ {
+ StructuredData::ObjectSP image_sp = images_sp->GetAsArray()->GetItemAtIndex(i);
+ if (image_sp.get() == nullptr || image_sp->GetAsDictionary() == nullptr)
+ return false;
+ StructuredData::Dictionary *image = image_sp->GetAsDictionary();
+ if (image->HasKey("load_address") == false
+ || image->HasKey("pathname") == false
+ || image->HasKey("mod_date") == false
+ || image->HasKey("mach_header") == false
+ || image->GetValueForKey("mach_header")->GetAsDictionary() == nullptr
+ || image->HasKey("segments") == false
+ || image->GetValueForKey("segments")->GetAsArray() == nullptr
+ || image->HasKey("uuid") == false )
+ {
+ return false;
+ }
+ image_infos[i].address = image->GetValueForKey("load_address")->GetAsInteger()->GetValue();
+ image_infos[i].mod_date = image->GetValueForKey("mod_date")->GetAsInteger()->GetValue();
+ image_infos[i].file_spec.SetFile(image->GetValueForKey("pathname")->GetAsString()->GetValue().c_str(), false);
+
+ StructuredData::Dictionary *mh = image->GetValueForKey("mach_header")->GetAsDictionary();
+ image_infos[i].header.magic = mh->GetValueForKey("magic")->GetAsInteger()->GetValue();
+ image_infos[i].header.cputype = mh->GetValueForKey("cputype")->GetAsInteger()->GetValue();
+ image_infos[i].header.cpusubtype = mh->GetValueForKey("cpusubtype")->GetAsInteger()->GetValue();
+ image_infos[i].header.filetype = mh->GetValueForKey("filetype")->GetAsInteger()->GetValue();
+
+ // Fields that aren't used by DynamicLoaderMacOSXDYLD so debugserver doesn't currently send them
+ // in the reply.
+
+ if (mh->HasKey("flags"))
+ image_infos[i].header.flags = mh->GetValueForKey("flags")->GetAsInteger()->GetValue();
+ else
+ image_infos[i].header.flags = 0;
+
+ if (mh->HasKey("ncmds"))
+ image_infos[i].header.ncmds = mh->GetValueForKey("ncmds")->GetAsInteger()->GetValue();
+ else
+ image_infos[i].header.ncmds = 0;
+
+ if (mh->HasKey("sizeofcmds"))
+ image_infos[i].header.sizeofcmds = mh->GetValueForKey("sizeofcmds")->GetAsInteger()->GetValue();
+ else
+ image_infos[i].header.sizeofcmds = 0;
+
+ if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE)
+ exe_idx = i;
+
+ StructuredData::Array *segments = image->GetValueForKey("segments")->GetAsArray();
+ uint32_t segcount = segments->GetSize();
+ for (size_t j = 0; j < segcount; j++)
+ {
+ Segment segment;
+ StructuredData::Dictionary *seg = segments->GetItemAtIndex(j)->GetAsDictionary();
+ segment.name = ConstString(seg->GetValueForKey("name")->GetAsString()->GetValue().c_str());
+ segment.vmaddr = seg->GetValueForKey("vmaddr")->GetAsInteger()->GetValue();
+ segment.vmsize = seg->GetValueForKey("vmsize")->GetAsInteger()->GetValue();
+ segment.fileoff = seg->GetValueForKey("fileoff")->GetAsInteger()->GetValue();
+ segment.filesize = seg->GetValueForKey("filesize")->GetAsInteger()->GetValue();
+ segment.maxprot = seg->GetValueForKey("maxprot")->GetAsInteger()->GetValue();
+
+ // Fields that aren't used by DynamicLoaderMacOSXDYLD so debugserver doesn't currently send them
+ // in the reply.
+
+ if (seg->HasKey("initprot"))
+ segment.initprot = seg->GetValueForKey("initprot")->GetAsInteger()->GetValue();
+ else
+ segment.initprot = 0;
+
+ if (seg->HasKey("flags"))
+ segment.flags = seg->GetValueForKey("flags")->GetAsInteger()->GetValue();
+ else
+ segment.flags = 0;
+
+ if (seg->HasKey("nsects"))
+ segment.nsects = seg->GetValueForKey("nsects")->GetAsInteger()->GetValue();
+ else
+ segment.nsects = 0;
+
+ image_infos[i].segments.push_back (segment);
+ }
+
+ image_infos[i].uuid.SetFromCString (image->GetValueForKey("uuid")->GetAsString()->GetValue().c_str());
+
+ // All sections listed in the dyld image info structure will all
+ // either be fixed up already, or they will all be off by a single
+ // slide amount that is determined by finding the first segment
+ // that is at file offset zero which also has bytes (a file size
+ // that is greater than zero) in the object file.
+
+ // Determine the slide amount (if any)
+ const size_t num_sections = image_infos[i].segments.size();
+ for (size_t k = 0; k < num_sections; ++k)
+ {
+ // Iterate through the object file sections to find the
+ // first section that starts of file offset zero and that
+ // has bytes in the file...
+ if ((image_infos[i].segments[k].fileoff == 0 && image_infos[i].segments[k].filesize > 0)
+ || (image_infos[i].segments[k].name == ConstString("__TEXT")))
+ {
+ image_infos[i].slide = image_infos[i].address - image_infos[i].segments[k].vmaddr;
+ // We have found the slide amount, so we can exit
+ // this for loop.
+ break;
+ }
+ }
+ }
+
+ Target &target = m_process->GetTarget();
+
+ if (exe_idx < image_infos.size())
+ {
+ const bool can_create = true;
+ ModuleSP exe_module_sp (FindTargetModuleForDYLDImageInfo (image_infos[exe_idx], can_create, NULL));
+
+ if (exe_module_sp)
+ {
+ UpdateImageLoadAddress (exe_module_sp.get(), image_infos[exe_idx]);
+
+ if (exe_module_sp.get() != target.GetExecutableModulePointer())
+ {
+ // Don't load dependent images since we are in dyld where we will know
+ // and find out about all images that are loaded. Also when setting the
+ // executable module, it will clear the targets module list, and if we
+ // have an in memory dyld module, it will get removed from the list
+ // so we will need to add it back after setting the executable module,
+ // so we first try and see if we already have a weak pointer to the
+ // dyld module, make it into a shared pointer, then add the executable,
+ // then re-add it back to make sure it is always in the list.
+ ModuleSP dyld_module_sp(m_dyld_module_wp.lock());
+
+ const bool get_dependent_images = false;
+ m_process->GetTarget().SetExecutableModule (exe_module_sp,
+ get_dependent_images);
+
+ if (dyld_module_sp)
+ {
+ if(target.GetImages().AppendIfNeeded (dyld_module_sp))
+ {
+ // Also add it to the section list.
+ UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld);
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool
+DynamicLoaderMacOSXDYLD::AddModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count)
+{
+ DYLDImageInfo::collection image_infos;
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf ("Adding %d modules.\n", image_infos_count);
+
+ Mutex::Locker locker(m_mutex);
+ if (m_process->GetStopID() == m_dyld_image_infos_stop_id)
+ return true;
+
+ StructuredData::ObjectSP image_infos_json_sp = m_process->GetLoadedDynamicLibrariesInfos (image_infos_addr, image_infos_count);
+ if (image_infos_json_sp.get()
+ && image_infos_json_sp->GetAsDictionary()
+ && image_infos_json_sp->GetAsDictionary()->HasKey("images")
+ && image_infos_json_sp->GetAsDictionary()->GetValueForKey("images")->GetAsArray()
+ && image_infos_json_sp->GetAsDictionary()->GetValueForKey("images")->GetAsArray()->GetSize() == image_infos_count)
+ {
+ bool return_value = false;
+ if (AddModulesUsingInfosFromDebugserver (image_infos_json_sp, image_infos))
+ {
+ return_value = AddModulesUsingImageInfos (image_infos);
+ }
+ m_dyld_image_infos_stop_id = m_process->GetStopID();
+ return return_value;
+ }
+
+ if (!ReadImageInfos (image_infos_addr, image_infos_count, image_infos))
+ return false;
+
+ UpdateImageInfosHeaderAndLoadCommands (image_infos, image_infos_count, false);
+ bool return_value = AddModulesUsingImageInfos (image_infos);
+ m_dyld_image_infos_stop_id = m_process->GetStopID();
+ return return_value;
+}
+
+// Adds the modules in image_infos to m_dyld_image_infos.
+// NB don't call this passing in m_dyld_image_infos.
+
+bool
+DynamicLoaderMacOSXDYLD::AddModulesUsingImageInfos (DYLDImageInfo::collection &image_infos)
+{
+ // Now add these images to the main list.
+ ModuleList loaded_module_list;
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER));
+ Target &target = m_process->GetTarget();
+ ModuleList& target_images = target.GetImages();
+
+ for (uint32_t idx = 0; idx < image_infos.size(); ++idx)
+ {
+ if (log)
+ {
+ log->Printf ("Adding new image at address=0x%16.16" PRIx64 ".", image_infos[idx].address);
+ image_infos[idx].PutToLog (log);
+ }
+
+ m_dyld_image_infos.push_back(image_infos[idx]);
+
+ ModuleSP image_module_sp (FindTargetModuleForDYLDImageInfo (image_infos[idx], true, NULL));
+
+ if (image_module_sp)
+ {
+ ObjectFile *objfile = image_module_sp->GetObjectFile ();
+ if (objfile)
+ {
+ SectionList *sections = objfile->GetSectionList();
+ if (sections)
+ {
+ ConstString commpage_dbstr("__commpage");
+ Section *commpage_section = sections->FindSectionByName(commpage_dbstr).get();
+ if (commpage_section)
+ {
+ ModuleSpec module_spec (objfile->GetFileSpec(), image_infos[idx].GetArchitecture ());
+ module_spec.GetObjectName() = commpage_dbstr;
+ ModuleSP commpage_image_module_sp(target_images.FindFirstModule (module_spec));
+ if (!commpage_image_module_sp)
+ {
+ module_spec.SetObjectOffset (objfile->GetFileOffset() + commpage_section->GetFileOffset());
+ module_spec.SetObjectSize (objfile->GetByteSize());
+ commpage_image_module_sp = target.GetSharedModule (module_spec);
+ if (!commpage_image_module_sp || commpage_image_module_sp->GetObjectFile() == NULL)
+ {
+ commpage_image_module_sp = m_process->ReadModuleFromMemory (image_infos[idx].file_spec,
+ image_infos[idx].address);
+ // Always load a memory image right away in the target in case
+ // we end up trying to read the symbol table from memory... The
+ // __LINKEDIT will need to be mapped so we can figure out where
+ // the symbol table bits are...
+ bool changed = false;
+ UpdateImageLoadAddress (commpage_image_module_sp.get(), image_infos[idx]);
+ target.GetImages().Append(commpage_image_module_sp);
+ if (changed)
+ {
+ image_infos[idx].load_stop_id = m_process->GetStopID();
+ loaded_module_list.AppendIfNeeded (commpage_image_module_sp);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // UpdateImageLoadAddress will return true if any segments
+ // change load address. We need to check this so we don't
+ // mention that all loaded shared libraries are newly loaded
+ // each time we hit out dyld breakpoint since dyld will list all
+ // shared libraries each time.
+ if (UpdateImageLoadAddress (image_module_sp.get(), image_infos[idx]))
+ {
+ target_images.AppendIfNeeded(image_module_sp);
+ loaded_module_list.AppendIfNeeded (image_module_sp);
+ }
+ }
+ }
+
+ if (loaded_module_list.GetSize() > 0)
+ {
+ if (log)
+ loaded_module_list.LogUUIDAndPaths (log, "DynamicLoaderMacOSXDYLD::ModulesDidLoad");
+ m_process->GetTarget().ModulesDidLoad (loaded_module_list);
+ }
+ return true;
+}
+
+bool
+DynamicLoaderMacOSXDYLD::RemoveModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count)
+{
+ DYLDImageInfo::collection image_infos;
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ Mutex::Locker locker(m_mutex);
+ if (m_process->GetStopID() == m_dyld_image_infos_stop_id)
+ return true;
+
+ // First read in the image_infos for the removed modules, and their headers & load commands.
+ if (!ReadImageInfos (image_infos_addr, image_infos_count, image_infos))
+ {
+ if (log)
+ log->PutCString ("Failed reading image infos array.");
+ return false;
+ }
+
+ if (log)
+ log->Printf ("Removing %d modules.", image_infos_count);
+
+ ModuleList unloaded_module_list;
+ for (uint32_t idx = 0; idx < image_infos.size(); ++idx)
+ {
+ if (log)
+ {
+ log->Printf ("Removing module at address=0x%16.16" PRIx64 ".", image_infos[idx].address);
+ image_infos[idx].PutToLog (log);
+ }
+
+ // Remove this image_infos from the m_all_image_infos. We do the comparison by address
+ // rather than by file spec because we can have many modules with the same "file spec" in the
+ // case that they are modules loaded from memory.
+ //
+ // Also copy over the uuid from the old entry to the removed entry so we can
+ // use it to lookup the module in the module list.
+
+ DYLDImageInfo::collection::iterator pos, end = m_dyld_image_infos.end();
+ for (pos = m_dyld_image_infos.begin(); pos != end; pos++)
+ {
+ if (image_infos[idx].address == (*pos).address)
+ {
+ image_infos[idx].uuid = (*pos).uuid;
+
+ // Add the module from this image_info to the "unloaded_module_list". We'll remove them all at
+ // one go later on.
+
+ ModuleSP unload_image_module_sp (FindTargetModuleForDYLDImageInfo (image_infos[idx], false, NULL));
+ if (unload_image_module_sp.get())
+ {
+ // When we unload, be sure to use the image info from the old list,
+ // since that has sections correctly filled in.
+ UnloadImageLoadAddress (unload_image_module_sp.get(), *pos);
+ unloaded_module_list.AppendIfNeeded (unload_image_module_sp);
+ }
+ else
+ {
+ if (log)
+ {
+ log->Printf ("Could not find module for unloading info entry:");
+ image_infos[idx].PutToLog(log);
+ }
+ }
+
+ // Then remove it from the m_dyld_image_infos:
+
+ m_dyld_image_infos.erase(pos);
+ break;
+ }
+ }
+
+ if (pos == end)
+ {
+ if (log)
+ {
+ log->Printf ("Could not find image_info entry for unloading image:");
+ image_infos[idx].PutToLog(log);
+ }
+ }
+ }
+ if (unloaded_module_list.GetSize() > 0)
+ {
+ if (log)
+ {
+ log->PutCString("Unloaded:");
+ unloaded_module_list.LogUUIDAndPaths (log, "DynamicLoaderMacOSXDYLD::ModulesDidUnload");
+ }
+ m_process->GetTarget().GetImages().Remove (unloaded_module_list);
+ }
+ m_dyld_image_infos_stop_id = m_process->GetStopID();
+ return true;
+}
+
+bool
+DynamicLoaderMacOSXDYLD::ReadImageInfos (lldb::addr_t image_infos_addr,
+ uint32_t image_infos_count,
+ DYLDImageInfo::collection &image_infos)
+{
+ const ByteOrder endian = m_dyld.GetByteOrder();
+ const uint32_t addr_size = m_dyld.GetAddressByteSize();
+
+ image_infos.resize(image_infos_count);
+ const size_t count = image_infos.size() * 3 * addr_size;
+ DataBufferHeap info_data(count, 0);
+ Error error;
+ const size_t bytes_read = m_process->ReadMemory (image_infos_addr,
+ info_data.GetBytes(),
+ info_data.GetByteSize(),
+ error);
+ if (bytes_read == count)
+ {
+ lldb::offset_t info_data_offset = 0;
+ DataExtractor info_data_ref(info_data.GetBytes(), info_data.GetByteSize(), endian, addr_size);
+ for (size_t i = 0; i < image_infos.size() && info_data_ref.ValidOffset(info_data_offset); i++)
+ {
+ image_infos[i].address = info_data_ref.GetPointer(&info_data_offset);
+ lldb::addr_t path_addr = info_data_ref.GetPointer(&info_data_offset);
+ image_infos[i].mod_date = info_data_ref.GetPointer(&info_data_offset);
+
+ char raw_path[PATH_MAX];
+ m_process->ReadCStringFromMemory (path_addr, raw_path, sizeof(raw_path), error);
+ // don't resolve the path
+ if (error.Success())
+ {
+ const bool resolve_path = false;
+ image_infos[i].file_spec.SetFile(raw_path, resolve_path);
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//----------------------------------------------------------------------
+// If we have found where the "_dyld_all_image_infos" lives in memory,
+// read the current info from it, and then update all image load
+// addresses (or lack thereof). Only do this if this is the first time
+// we're reading the dyld infos. Return true if we actually read anything,
+// and false otherwise.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::InitializeFromAllImageInfos ()
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ Mutex::Locker locker(m_mutex);
+ if (m_process->GetStopID() == m_dyld_image_infos_stop_id
+ || m_dyld_image_infos.size() != 0)
+ return false;
+
+ if (ReadAllImageInfosStructure ())
+ {
+ // Nothing to load or unload?
+ if (m_dyld_all_image_infos.dylib_info_count == 0)
+ return true;
+
+ if (m_dyld_all_image_infos.dylib_info_addr == 0)
+ {
+ // DYLD is updating the images now. So we should say we have no images, and then we'll
+ // figure it out when we hit the added breakpoint.
+ return false;
+ }
+ else
+ {
+ if (!AddModulesUsingImageInfosAddress (m_dyld_all_image_infos.dylib_info_addr,
+ m_dyld_all_image_infos.dylib_info_count))
+ {
+ DEBUG_PRINTF("%s", "unable to read all data for all_dylib_infos.");
+ m_dyld_image_infos.clear();
+ }
+ }
+
+ // Now we have one more bit of business. If there is a library left in the images for our target that
+ // doesn't have a load address, then it must be something that we were expecting to load (for instance we
+ // read a load command for it) but it didn't in fact load - probably because DYLD_*_PATH pointed
+ // to an equivalent version. We don't want it to stay in the target's module list or it will confuse
+ // us, so unload it here.
+ Target &target = m_process->GetTarget();
+ const ModuleList &target_modules = target.GetImages();
+ ModuleList not_loaded_modules;
+ Mutex::Locker modules_locker(target_modules.GetMutex());
+
+ size_t num_modules = target_modules.GetSize();
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked (i);
+ if (!module_sp->IsLoadedInTarget (&target))
+ {
+ if (log)
+ {
+ StreamString s;
+ module_sp->GetDescription (&s);
+ log->Printf ("Unloading pre-run module: %s.", s.GetData ());
+ }
+ not_loaded_modules.Append (module_sp);
+ }
+ }
+
+ if (not_loaded_modules.GetSize() != 0)
+ {
+ target.GetImages().Remove(not_loaded_modules);
+ }
+
+ return true;
+ }
+ else
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Read a mach_header at ADDR into HEADER, and also fill in the load
+// command data into LOAD_COMMAND_DATA if it is non-NULL.
+//
+// Returns true if we succeed, false if we fail for any reason.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXDYLD::ReadMachHeader (lldb::addr_t addr, llvm::MachO::mach_header *header, DataExtractor *load_command_data)
+{
+ DataBufferHeap header_bytes(sizeof(llvm::MachO::mach_header), 0);
+ Error error;
+ size_t bytes_read = m_process->ReadMemory (addr,
+ header_bytes.GetBytes(),
+ header_bytes.GetByteSize(),
+ error);
+ if (bytes_read == sizeof(llvm::MachO::mach_header))
+ {
+ lldb::offset_t offset = 0;
+ ::memset (header, 0, sizeof(llvm::MachO::mach_header));
+
+ // Get the magic byte unswapped so we can figure out what we are dealing with
+ DataExtractor data(header_bytes.GetBytes(), header_bytes.GetByteSize(), endian::InlHostByteOrder(), 4);
+ header->magic = data.GetU32(&offset);
+ lldb::addr_t load_cmd_addr = addr;
+ data.SetByteOrder(DynamicLoaderMacOSXDYLD::GetByteOrderFromMagic(header->magic));
+ switch (header->magic)
+ {
+ case llvm::MachO::MH_MAGIC:
+ case llvm::MachO::MH_CIGAM:
+ data.SetAddressByteSize(4);
+ load_cmd_addr += sizeof(llvm::MachO::mach_header);
+ break;
+
+ case llvm::MachO::MH_MAGIC_64:
+ case llvm::MachO::MH_CIGAM_64:
+ data.SetAddressByteSize(8);
+ load_cmd_addr += sizeof(llvm::MachO::mach_header_64);
+ break;
+
+ default:
+ return false;
+ }
+
+ // Read the rest of dyld's mach header
+ if (data.GetU32(&offset, &header->cputype, (sizeof(llvm::MachO::mach_header)/sizeof(uint32_t)) - 1))
+ {
+ if (load_command_data == NULL)
+ return true; // We were able to read the mach_header and weren't asked to read the load command bytes
+
+ DataBufferSP load_cmd_data_sp(new DataBufferHeap(header->sizeofcmds, 0));
+
+ size_t load_cmd_bytes_read = m_process->ReadMemory (load_cmd_addr,
+ load_cmd_data_sp->GetBytes(),
+ load_cmd_data_sp->GetByteSize(),
+ error);
+
+ if (load_cmd_bytes_read == header->sizeofcmds)
+ {
+ // Set the load command data and also set the correct endian
+ // swap settings and the correct address size
+ load_command_data->SetData(load_cmd_data_sp, 0, header->sizeofcmds);
+ load_command_data->SetByteOrder(data.GetByteOrder());
+ load_command_data->SetAddressByteSize(data.GetAddressByteSize());
+ return true; // We successfully read the mach_header and the load command data
+ }
+
+ return false; // We weren't able to read the load command data
+ }
+ }
+ return false; // We failed the read the mach_header
+}
+
+
+//----------------------------------------------------------------------
+// Parse the load commands for an image
+//----------------------------------------------------------------------
+uint32_t
+DynamicLoaderMacOSXDYLD::ParseLoadCommands (const DataExtractor& data, DYLDImageInfo& dylib_info, FileSpec *lc_id_dylinker)
+{
+ lldb::offset_t offset = 0;
+ uint32_t cmd_idx;
+ Segment segment;
+ dylib_info.Clear (true);
+
+ for (cmd_idx = 0; cmd_idx < dylib_info.header.ncmds; cmd_idx++)
+ {
+ // Clear out any load command specific data from DYLIB_INFO since
+ // we are about to read it.
+
+ if (data.ValidOffsetForDataOfSize (offset, sizeof(llvm::MachO::load_command)))
+ {
+ llvm::MachO::load_command load_cmd;
+ lldb::offset_t load_cmd_offset = offset;
+ load_cmd.cmd = data.GetU32 (&offset);
+ load_cmd.cmdsize = data.GetU32 (&offset);
+ switch (load_cmd.cmd)
+ {
+ case llvm::MachO::LC_SEGMENT:
+ {
+ segment.name.SetTrimmedCStringWithLength ((const char *)data.GetData(&offset, 16), 16);
+ // We are putting 4 uint32_t values 4 uint64_t values so
+ // we have to use multiple 32 bit gets below.
+ segment.vmaddr = data.GetU32 (&offset);
+ segment.vmsize = data.GetU32 (&offset);
+ segment.fileoff = data.GetU32 (&offset);
+ segment.filesize = data.GetU32 (&offset);
+ // Extract maxprot, initprot, nsects and flags all at once
+ data.GetU32(&offset, &segment.maxprot, 4);
+ dylib_info.segments.push_back (segment);
+ }
+ break;
+
+ case llvm::MachO::LC_SEGMENT_64:
+ {
+ segment.name.SetTrimmedCStringWithLength ((const char *)data.GetData(&offset, 16), 16);
+ // Extract vmaddr, vmsize, fileoff, and filesize all at once
+ data.GetU64(&offset, &segment.vmaddr, 4);
+ // Extract maxprot, initprot, nsects and flags all at once
+ data.GetU32(&offset, &segment.maxprot, 4);
+ dylib_info.segments.push_back (segment);
+ }
+ break;
+
+ case llvm::MachO::LC_ID_DYLINKER:
+ if (lc_id_dylinker)
+ {
+ const lldb::offset_t name_offset = load_cmd_offset + data.GetU32 (&offset);
+ const char *path = data.PeekCStr (name_offset);
+ lc_id_dylinker->SetFile (path, true);
+ }
+ break;
+
+ case llvm::MachO::LC_UUID:
+ dylib_info.uuid.SetBytes(data.GetData (&offset, 16));
+ break;
+
+ default:
+ break;
+ }
+ // Set offset to be the beginning of the next load command.
+ offset = load_cmd_offset + load_cmd.cmdsize;
+ }
+ }
+
+ // All sections listed in the dyld image info structure will all
+ // either be fixed up already, or they will all be off by a single
+ // slide amount that is determined by finding the first segment
+ // that is at file offset zero which also has bytes (a file size
+ // that is greater than zero) in the object file.
+
+ // Determine the slide amount (if any)
+ const size_t num_sections = dylib_info.segments.size();
+ for (size_t i = 0; i < num_sections; ++i)
+ {
+ // Iterate through the object file sections to find the
+ // first section that starts of file offset zero and that
+ // has bytes in the file...
+ if ((dylib_info.segments[i].fileoff == 0 && dylib_info.segments[i].filesize > 0) || (dylib_info.segments[i].name == ConstString("__TEXT")))
+ {
+ dylib_info.slide = dylib_info.address - dylib_info.segments[i].vmaddr;
+ // We have found the slide amount, so we can exit
+ // this for loop.
+ break;
+ }
+ }
+ return cmd_idx;
+}
+
+//----------------------------------------------------------------------
+// Read the mach_header and load commands for each image that the
+// _dyld_all_image_infos structure points to and cache the results.
+//----------------------------------------------------------------------
+
+void
+DynamicLoaderMacOSXDYLD::UpdateImageInfosHeaderAndLoadCommands(DYLDImageInfo::collection &image_infos,
+ uint32_t infos_count,
+ bool update_executable)
+{
+ uint32_t exe_idx = UINT32_MAX;
+ // Read any UUID values that we can get
+ for (uint32_t i = 0; i < infos_count; i++)
+ {
+ if (!image_infos[i].UUIDValid())
+ {
+ DataExtractor data; // Load command data
+ if (!ReadMachHeader (image_infos[i].address, &image_infos[i].header, &data))
+ continue;
+
+ ParseLoadCommands (data, image_infos[i], NULL);
+
+ if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE)
+ exe_idx = i;
+
+ }
+ }
+
+ Target &target = m_process->GetTarget();
+
+ if (exe_idx < image_infos.size())
+ {
+ const bool can_create = true;
+ ModuleSP exe_module_sp (FindTargetModuleForDYLDImageInfo (image_infos[exe_idx], can_create, NULL));
+
+ if (exe_module_sp)
+ {
+ UpdateImageLoadAddress (exe_module_sp.get(), image_infos[exe_idx]);
+
+ if (exe_module_sp.get() != target.GetExecutableModulePointer())
+ {
+ // Don't load dependent images since we are in dyld where we will know
+ // and find out about all images that are loaded. Also when setting the
+ // executable module, it will clear the targets module list, and if we
+ // have an in memory dyld module, it will get removed from the list
+ // so we will need to add it back after setting the executable module,
+ // so we first try and see if we already have a weak pointer to the
+ // dyld module, make it into a shared pointer, then add the executable,
+ // then re-add it back to make sure it is always in the list.
+ ModuleSP dyld_module_sp(m_dyld_module_wp.lock());
+
+ const bool get_dependent_images = false;
+ m_process->GetTarget().SetExecutableModule (exe_module_sp,
+ get_dependent_images);
+
+ if (dyld_module_sp)
+ {
+ if(target.GetImages().AppendIfNeeded (dyld_module_sp))
+ {
+ // Also add it to the section list.
+ UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld);
+ }
+ }
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// On Mac OS X libobjc (the Objective-C runtime) has several critical dispatch
+// functions written in hand-written assembly, and also have hand-written unwind
+// information in the eh_frame section. Normally we prefer analyzing the
+// assembly instructions of a currently executing frame to unwind from that frame --
+// but on hand-written functions this profiling can fail. We should use the
+// eh_frame instructions for these functions all the time.
+//
+// As an aside, it would be better if the eh_frame entries had a flag (or were
+// extensible so they could have an Apple-specific flag) which indicates that
+// the instructions are asynchronous -- accurate at every instruction, instead
+// of our normal default assumption that they are not.
+//----------------------------------------------------------------------
+
+bool
+DynamicLoaderMacOSXDYLD::AlwaysRelyOnEHUnwindInfo (SymbolContext &sym_ctx)
+{
+ ModuleSP module_sp;
+ if (sym_ctx.symbol)
+ {
+ module_sp = sym_ctx.symbol->GetAddressRef().GetModule();
+ }
+ if (module_sp.get() == NULL && sym_ctx.function)
+ {
+ module_sp = sym_ctx.function->GetAddressRange().GetBaseAddress().GetModule();
+ }
+ if (module_sp.get() == NULL)
+ return false;
+
+ ObjCLanguageRuntime *objc_runtime = m_process->GetObjCLanguageRuntime();
+ if (objc_runtime != NULL && objc_runtime->IsModuleObjCLibrary (module_sp))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+
+//----------------------------------------------------------------------
+// Dump a Segment to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::Segment::PutToLog (Log *log, lldb::addr_t slide) const
+{
+ if (log)
+ {
+ if (slide == 0)
+ log->Printf ("\t\t%16s [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")",
+ name.AsCString(""),
+ vmaddr + slide,
+ vmaddr + slide + vmsize);
+ else
+ log->Printf ("\t\t%16s [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") slide = 0x%" PRIx64,
+ name.AsCString(""),
+ vmaddr + slide,
+ vmaddr + slide + vmsize,
+ slide);
+ }
+}
+
+const DynamicLoaderMacOSXDYLD::Segment *
+DynamicLoaderMacOSXDYLD::DYLDImageInfo::FindSegment (const ConstString &name) const
+{
+ const size_t num_segments = segments.size();
+ for (size_t i=0; i<num_segments; ++i)
+ {
+ if (segments[i].name == name)
+ return &segments[i];
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Dump an image info structure to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::DYLDImageInfo::PutToLog (Log *log) const
+{
+ if (log == NULL)
+ return;
+ const uint8_t *u = (const uint8_t *)uuid.GetBytes();
+
+ if (address == LLDB_INVALID_ADDRESS)
+ {
+ if (u)
+ {
+ log->Printf("\t modtime=0x%8.8" PRIx64 " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X path='%s' (UNLOADED)",
+ mod_date,
+ u[ 0], u[ 1], u[ 2], u[ 3],
+ u[ 4], u[ 5], u[ 6], u[ 7],
+ u[ 8], u[ 9], u[10], u[11],
+ u[12], u[13], u[14], u[15],
+ file_spec.GetPath().c_str());
+ }
+ else
+ log->Printf("\t modtime=0x%8.8" PRIx64 " path='%s' (UNLOADED)",
+ mod_date,
+ file_spec.GetPath().c_str());
+ }
+ else
+ {
+ if (u)
+ {
+ log->Printf("\taddress=0x%16.16" PRIx64 " modtime=0x%8.8" PRIx64 " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X path='%s'",
+ address,
+ mod_date,
+ u[ 0], u[ 1], u[ 2], u[ 3],
+ u[ 4], u[ 5], u[ 6], u[ 7],
+ u[ 8], u[ 9], u[10], u[11],
+ u[12], u[13], u[14], u[15],
+ file_spec.GetPath().c_str());
+ }
+ else
+ {
+ log->Printf("\taddress=0x%16.16" PRIx64 " modtime=0x%8.8" PRIx64 " path='%s'",
+ address,
+ mod_date,
+ file_spec.GetPath().c_str());
+
+ }
+ for (uint32_t i=0; i<segments.size(); ++i)
+ segments[i].PutToLog(log, slide);
+ }
+}
+
+//----------------------------------------------------------------------
+// Dump the _dyld_all_image_infos members and all current image infos
+// that we have parsed to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::PutToLog(Log *log) const
+{
+ if (log == NULL)
+ return;
+
+ Mutex::Locker locker(m_mutex);
+ log->Printf("dyld_all_image_infos = { version=%d, count=%d, addr=0x%8.8" PRIx64 ", notify=0x%8.8" PRIx64 " }",
+ m_dyld_all_image_infos.version,
+ m_dyld_all_image_infos.dylib_info_count,
+ (uint64_t)m_dyld_all_image_infos.dylib_info_addr,
+ (uint64_t)m_dyld_all_image_infos.notification);
+ size_t i;
+ const size_t count = m_dyld_image_infos.size();
+ if (count > 0)
+ {
+ log->PutCString("Loaded:");
+ for (i = 0; i<count; i++)
+ m_dyld_image_infos[i].PutToLog(log);
+ }
+}
+
+void
+DynamicLoaderMacOSXDYLD::PrivateInitialize(Process *process)
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
+ Clear(true);
+ m_process = process;
+ m_process->GetTarget().ClearAllLoadedSections();
+}
+
+bool
+DynamicLoaderMacOSXDYLD::SetNotificationBreakpoint ()
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
+ if (m_break_id == LLDB_INVALID_BREAK_ID)
+ {
+ if (m_dyld_all_image_infos.notification != LLDB_INVALID_ADDRESS)
+ {
+ Address so_addr;
+ // Set the notification breakpoint and install a breakpoint
+ // callback function that will get called each time the
+ // breakpoint gets hit. We will use this to track when shared
+ // libraries get loaded/unloaded.
+ bool resolved = m_process->GetTarget().ResolveLoadAddress(m_dyld_all_image_infos.notification, so_addr);
+ if (!resolved)
+ {
+ ModuleSP dyld_module_sp = m_dyld_module_wp.lock();
+ if (dyld_module_sp)
+ {
+ UpdateImageLoadAddress (dyld_module_sp.get(), m_dyld);
+ resolved = m_process->GetTarget().ResolveLoadAddress(m_dyld_all_image_infos.notification, so_addr);
+ }
+ }
+
+ if (resolved)
+ {
+ Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint (so_addr, true, false).get();
+ dyld_break->SetCallback (DynamicLoaderMacOSXDYLD::NotifyBreakpointHit, this, true);
+ dyld_break->SetBreakpointKind ("shared-library-event");
+ m_break_id = dyld_break->GetID();
+ }
+ }
+ }
+ return m_break_id != LLDB_INVALID_BREAK_ID;
+}
+
+//----------------------------------------------------------------------
+// Member function that gets called when the process state changes.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXDYLD::PrivateProcessStateChanged (Process *process, StateType state)
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s(%s)\n", __FUNCTION__, StateAsCString(state));
+ switch (state)
+ {
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ case eStateDetached:
+ Clear(false);
+ break;
+
+ case eStateStopped:
+ // Keep trying find dyld and set our notification breakpoint each time
+ // we stop until we succeed
+ if (!DidSetNotificationBreakpoint () && m_process->IsAlive())
+ {
+ if (NeedToLocateDYLD ())
+ LocateDYLD ();
+
+ SetNotificationBreakpoint ();
+ }
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ break;
+ }
+}
+
+ThreadPlanSP
+DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others)
+{
+ ThreadPlanSP thread_plan_sp;
+ StackFrame *current_frame = thread.GetStackFrameAtIndex(0).get();
+ const SymbolContext &current_context = current_frame->GetSymbolContext(eSymbolContextSymbol);
+ Symbol *current_symbol = current_context.symbol;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ TargetSP target_sp (thread.CalculateTarget());
+
+ if (current_symbol != NULL)
+ {
+ std::vector<Address> addresses;
+
+ if (current_symbol->IsTrampoline())
+ {
+ const ConstString &trampoline_name = current_symbol->GetMangled().GetName(current_symbol->GetLanguage(), Mangled::ePreferMangled);
+
+ if (trampoline_name)
+ {
+ const ModuleList &images = target_sp->GetImages();
+
+ SymbolContextList code_symbols;
+ images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, code_symbols);
+ size_t num_code_symbols = code_symbols.GetSize();
+
+ if (num_code_symbols > 0)
+ {
+ for (uint32_t i = 0; i < num_code_symbols; i++)
+ {
+ SymbolContext context;
+ AddressRange addr_range;
+ if (code_symbols.GetContextAtIndex(i, context))
+ {
+ context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range);
+ addresses.push_back(addr_range.GetBaseAddress());
+ if (log)
+ {
+ addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(target_sp.get());
+
+ log->Printf ("Found a trampoline target symbol at 0x%" PRIx64 ".", load_addr);
+ }
+ }
+ }
+ }
+
+ SymbolContextList reexported_symbols;
+ images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeReExported, reexported_symbols);
+ size_t num_reexported_symbols = reexported_symbols.GetSize();
+ if (num_reexported_symbols > 0)
+ {
+ for (uint32_t i = 0; i < num_reexported_symbols; i++)
+ {
+ SymbolContext context;
+ if (reexported_symbols.GetContextAtIndex(i, context))
+ {
+ if (context.symbol)
+ {
+ Symbol *actual_symbol = context.symbol->ResolveReExportedSymbol(*target_sp.get());
+ if (actual_symbol)
+ {
+ const Address actual_symbol_addr = actual_symbol->GetAddress();
+ if (actual_symbol_addr.IsValid())
+ {
+ addresses.push_back(actual_symbol_addr);
+ if (log)
+ {
+ lldb::addr_t load_addr = actual_symbol_addr.GetLoadAddress(target_sp.get());
+ log->Printf ("Found a re-exported symbol: %s at 0x%" PRIx64 ".",
+ actual_symbol->GetName().GetCString(), load_addr);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ SymbolContextList indirect_symbols;
+ images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeResolver, indirect_symbols);
+ size_t num_indirect_symbols = indirect_symbols.GetSize();
+ if (num_indirect_symbols > 0)
+ {
+ for (uint32_t i = 0; i < num_indirect_symbols; i++)
+ {
+ SymbolContext context;
+ AddressRange addr_range;
+ if (indirect_symbols.GetContextAtIndex(i, context))
+ {
+ context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range);
+ addresses.push_back(addr_range.GetBaseAddress());
+ if (log)
+ {
+ addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(target_sp.get());
+
+ log->Printf ("Found an indirect target symbol at 0x%" PRIx64 ".", load_addr);
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (current_symbol->GetType() == eSymbolTypeReExported)
+ {
+ // I am not sure we could ever end up stopped AT a re-exported symbol. But just in case:
+
+ const Symbol *actual_symbol = current_symbol->ResolveReExportedSymbol(*(target_sp.get()));
+ if (actual_symbol)
+ {
+ Address target_addr(actual_symbol->GetAddress());
+ if (target_addr.IsValid())
+ {
+ if (log)
+ log->Printf ("Found a re-exported symbol: %s pointing to: %s at 0x%" PRIx64 ".",
+ current_symbol->GetName().GetCString(),
+ actual_symbol->GetName().GetCString(),
+ target_addr.GetLoadAddress(target_sp.get()));
+ addresses.push_back (target_addr.GetLoadAddress(target_sp.get()));
+
+ }
+ }
+ }
+
+ if (addresses.size() > 0)
+ {
+ // First check whether any of the addresses point to Indirect symbols, and if they do, resolve them:
+ std::vector<lldb::addr_t> load_addrs;
+ for (Address address : addresses)
+ {
+ Symbol *symbol = address.CalculateSymbolContextSymbol();
+ if (symbol && symbol->IsIndirect())
+ {
+ Error error;
+ Address symbol_address = symbol->GetAddress();
+ addr_t resolved_addr = thread.GetProcess()->ResolveIndirectFunction(&symbol_address, error);
+ if (error.Success())
+ {
+ load_addrs.push_back(resolved_addr);
+ if (log)
+ log->Printf("ResolveIndirectFunction found resolved target for %s at 0x%" PRIx64 ".",
+ symbol->GetName().GetCString(), resolved_addr);
+ }
+ }
+ else
+ {
+ load_addrs.push_back(address.GetLoadAddress(target_sp.get()));
+ }
+
+ }
+ thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, load_addrs, stop_others));
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Could not find symbol for step through.");
+ }
+
+ return thread_plan_sp;
+}
+
+size_t
+DynamicLoaderMacOSXDYLD::FindEquivalentSymbols (lldb_private::Symbol *original_symbol,
+ lldb_private::ModuleList &images,
+ lldb_private::SymbolContextList &equivalent_symbols)
+{
+ const ConstString &trampoline_name = original_symbol->GetMangled().GetName(original_symbol->GetLanguage(), Mangled::ePreferMangled);
+ if (!trampoline_name)
+ return 0;
+
+ size_t initial_size = equivalent_symbols.GetSize();
+
+ static const char *resolver_name_regex = "(_gc|_non_gc|\\$[A-Za-z0-9\\$]+)$";
+ std::string equivalent_regex_buf("^");
+ equivalent_regex_buf.append (trampoline_name.GetCString());
+ equivalent_regex_buf.append (resolver_name_regex);
+
+ RegularExpression equivalent_name_regex (equivalent_regex_buf.c_str());
+ const bool append = true;
+ images.FindSymbolsMatchingRegExAndType (equivalent_name_regex, eSymbolTypeCode, equivalent_symbols, append);
+
+ return equivalent_symbols.GetSize() - initial_size;
+}
+
+Error
+DynamicLoaderMacOSXDYLD::CanLoadImage ()
+{
+ Error error;
+ // In order for us to tell if we can load a shared library we verify that
+ // the dylib_info_addr isn't zero (which means no shared libraries have
+ // been set yet, or dyld is currently mucking with the shared library list).
+ if (ReadAllImageInfosStructure ())
+ {
+ // TODO: also check the _dyld_global_lock_held variable in libSystem.B.dylib?
+ // TODO: check the malloc lock?
+ // TODO: check the objective C lock?
+ if (m_dyld_all_image_infos.dylib_info_addr != 0)
+ return error; // Success
+ }
+
+ error.SetErrorString("unsafe to load or unload shared libraries");
+ return error;
+}
+
+void
+DynamicLoaderMacOSXDYLD::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DynamicLoaderMacOSXDYLD::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+DynamicLoaderMacOSXDYLD::GetPluginNameStatic()
+{
+ static ConstString g_name("macosx-dyld");
+ return g_name;
+}
+
+const char *
+DynamicLoaderMacOSXDYLD::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that watches for shared library loads/unloads in MacOSX user processes.";
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+DynamicLoaderMacOSXDYLD::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DynamicLoaderMacOSXDYLD::GetPluginVersion()
+{
+ return 1;
+}
+
+uint32_t
+DynamicLoaderMacOSXDYLD::AddrByteSize()
+{
+ switch (m_dyld.header.magic)
+ {
+ case llvm::MachO::MH_MAGIC:
+ case llvm::MachO::MH_CIGAM:
+ return 4;
+
+ case llvm::MachO::MH_MAGIC_64:
+ case llvm::MachO::MH_CIGAM_64:
+ return 8;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+lldb::ByteOrder
+DynamicLoaderMacOSXDYLD::GetByteOrderFromMagic (uint32_t magic)
+{
+ switch (magic)
+ {
+ case llvm::MachO::MH_MAGIC:
+ case llvm::MachO::MH_MAGIC_64:
+ return endian::InlHostByteOrder();
+
+ case llvm::MachO::MH_CIGAM:
+ case llvm::MachO::MH_CIGAM_64:
+ if (endian::InlHostByteOrder() == lldb::eByteOrderBig)
+ return lldb::eByteOrderLittle;
+ else
+ return lldb::eByteOrderBig;
+
+ default:
+ break;
+ }
+ return lldb::eByteOrderInvalid;
+}
+
+lldb::ByteOrder
+DynamicLoaderMacOSXDYLD::DYLDImageInfo::GetByteOrder()
+{
+ return DynamicLoaderMacOSXDYLD::GetByteOrderFromMagic(header.magic);
+}
+
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
new file mode 100644
index 000000000000..8fd60d0b6ac7
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
@@ -0,0 +1,385 @@
+//===-- DynamicLoaderMacOSXDYLD.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_DynamicLoaderMacOSXDYLD_h_
+#define liblldb_DynamicLoaderMacOSXDYLD_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/SafeMachO.h"
+
+class DynamicLoaderMacOSXDYLD : public lldb_private::DynamicLoader
+{
+public:
+ DynamicLoaderMacOSXDYLD(lldb_private::Process *process);
+
+ ~DynamicLoaderMacOSXDYLD() override;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance (lldb_private::Process *process, bool force);
+
+ //------------------------------------------------------------------
+ /// Called after attaching a process.
+ ///
+ /// Allow DynamicLoader plug-ins to execute some code after
+ /// attaching to a process.
+ //------------------------------------------------------------------
+ void
+ DidAttach() override;
+
+ void
+ DidLaunch() override;
+
+ bool
+ ProcessDidExec() override;
+
+ lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+ bool stop_others) override;
+
+ size_t
+ FindEquivalentSymbols(lldb_private::Symbol *original_symbol,
+ lldb_private::ModuleList &module_list,
+ lldb_private::SymbolContextList &equivalent_symbols) override;
+
+ lldb_private::Error
+ CanLoadImage() override;
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+ bool
+ AlwaysRelyOnEHUnwindInfo(lldb_private::SymbolContext &sym_ctx) override;
+
+protected:
+ void
+ PrivateInitialize (lldb_private::Process *process);
+
+ void
+ PrivateProcessStateChanged (lldb_private::Process *process,
+ lldb::StateType state);
+
+ bool
+ LocateDYLD ();
+
+ bool
+ DidSetNotificationBreakpoint () const;
+
+ void
+ Clear (bool clear_process);
+
+ void
+ PutToLog (lldb_private::Log *log) const;
+
+ bool
+ ReadDYLDInfoFromMemoryAndSetNotificationCallback (lldb::addr_t addr);
+
+ static bool
+ NotifyBreakpointHit (void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ uint32_t
+ AddrByteSize();
+
+ static lldb::ByteOrder
+ GetByteOrderFromMagic (uint32_t magic);
+
+ bool
+ ReadMachHeader (lldb::addr_t addr,
+ llvm::MachO::mach_header *header,
+ lldb_private::DataExtractor *load_command_data);
+
+ class Segment
+ {
+ public:
+ Segment() :
+ name(),
+ vmaddr(LLDB_INVALID_ADDRESS),
+ vmsize(0),
+ fileoff(0),
+ filesize(0),
+ maxprot(0),
+ initprot(0),
+ nsects(0),
+ flags(0)
+ {
+ }
+
+ lldb_private::ConstString name;
+ lldb::addr_t vmaddr;
+ lldb::addr_t vmsize;
+ lldb::addr_t fileoff;
+ lldb::addr_t filesize;
+ uint32_t maxprot;
+ uint32_t initprot;
+ uint32_t nsects;
+ uint32_t flags;
+
+ bool
+ operator==(const Segment& rhs) const
+ {
+ return name == rhs.name && vmaddr == rhs.vmaddr && vmsize == rhs.vmsize;
+ }
+
+ void
+ PutToLog (lldb_private::Log *log,
+ lldb::addr_t slide) const;
+
+ };
+
+ struct DYLDImageInfo
+ {
+ lldb::addr_t address; // Address of mach header for this dylib
+ lldb::addr_t slide; // The amount to slide all segments by if there is a global slide.
+ lldb::addr_t mod_date; // Modification date for this dylib
+ lldb_private::FileSpec file_spec; // Resolved path for this dylib
+ lldb_private::UUID uuid; // UUID for this dylib if it has one, else all zeros
+ llvm::MachO::mach_header header; // The mach header for this image
+ std::vector<Segment> segments; // All segment vmaddr and vmsize pairs for this executable (from memory of inferior)
+ uint32_t load_stop_id; // The process stop ID that the sections for this image were loaded
+
+ DYLDImageInfo() :
+ address(LLDB_INVALID_ADDRESS),
+ slide(0),
+ mod_date(0),
+ file_spec(),
+ uuid(),
+ header(),
+ segments(),
+ load_stop_id(0)
+ {
+ }
+
+ void
+ Clear(bool load_cmd_data_only)
+ {
+ if (!load_cmd_data_only)
+ {
+ address = LLDB_INVALID_ADDRESS;
+ slide = 0;
+ mod_date = 0;
+ file_spec.Clear();
+ ::memset (&header, 0, sizeof(header));
+ }
+ uuid.Clear();
+ segments.clear();
+ load_stop_id = 0;
+ }
+
+ bool
+ operator == (const DYLDImageInfo& rhs) const
+ {
+ return address == rhs.address
+ && slide == rhs.slide
+ && mod_date == rhs.mod_date
+ && file_spec == rhs.file_spec
+ && uuid == rhs.uuid
+ && memcmp(&header, &rhs.header, sizeof(header)) == 0
+ && segments == rhs.segments;
+ }
+
+ bool
+ UUIDValid() const
+ {
+ return uuid.IsValid();
+ }
+
+ uint32_t
+ GetAddressByteSize ()
+ {
+ if (header.cputype)
+ {
+ if (header.cputype & llvm::MachO::CPU_ARCH_ABI64)
+ return 8;
+ else
+ return 4;
+ }
+ return 0;
+ }
+
+ lldb::ByteOrder
+ GetByteOrder();
+
+ lldb_private::ArchSpec
+ GetArchitecture () const
+ {
+ return lldb_private::ArchSpec (lldb_private::eArchTypeMachO, header.cputype, header.cpusubtype);
+ }
+
+ const Segment *
+ FindSegment (const lldb_private::ConstString &name) const;
+
+ void
+ PutToLog (lldb_private::Log *log) const;
+
+ typedef std::vector<DYLDImageInfo> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+
+ struct DYLDAllImageInfos
+ {
+ uint32_t version;
+ uint32_t dylib_info_count; // Version >= 1
+ lldb::addr_t dylib_info_addr; // Version >= 1
+ lldb::addr_t notification; // Version >= 1
+ bool processDetachedFromSharedRegion; // Version >= 1
+ bool libSystemInitialized; // Version >= 2
+ lldb::addr_t dyldImageLoadAddress; // Version >= 2
+
+ DYLDAllImageInfos() :
+ version (0),
+ dylib_info_count (0),
+ dylib_info_addr (LLDB_INVALID_ADDRESS),
+ notification (LLDB_INVALID_ADDRESS),
+ processDetachedFromSharedRegion (false),
+ libSystemInitialized (false),
+ dyldImageLoadAddress (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ void
+ Clear()
+ {
+ version = 0;
+ dylib_info_count = 0;
+ dylib_info_addr = LLDB_INVALID_ADDRESS;
+ notification = LLDB_INVALID_ADDRESS;
+ processDetachedFromSharedRegion = false;
+ libSystemInitialized = false;
+ dyldImageLoadAddress = LLDB_INVALID_ADDRESS;
+ }
+
+ bool
+ IsValid() const
+ {
+ return version >= 1 || version <= 6;
+ }
+ };
+
+ void
+ RegisterNotificationCallbacks();
+
+ void
+ UnregisterNotificationCallbacks();
+
+ uint32_t
+ ParseLoadCommands (const lldb_private::DataExtractor& data,
+ DYLDImageInfo& dylib_info,
+ lldb_private::FileSpec *lc_id_dylinker);
+
+ bool
+ UpdateImageLoadAddress(lldb_private::Module *module,
+ DYLDImageInfo& info);
+
+ bool
+ UnloadImageLoadAddress (lldb_private::Module *module,
+ DYLDImageInfo& info);
+
+ lldb::ModuleSP
+ FindTargetModuleForDYLDImageInfo (DYLDImageInfo &image_info,
+ bool can_create,
+ bool *did_create_ptr);
+
+ DYLDImageInfo *
+ GetImageInfo (lldb_private::Module *module);
+
+ bool
+ NeedToLocateDYLD () const;
+
+ bool
+ SetNotificationBreakpoint ();
+
+ // There is a little tricky bit where you might initially attach while dyld is updating
+ // the all_image_infos, and you can't read the infos, so you have to continue and pick it
+ // up when you hit the update breakpoint. At that point, you need to run this initialize
+ // function, but when you do it that way you DON'T need to do the extra work you would at
+ // the breakpoint.
+ // So this function will only do actual work if the image infos haven't been read yet.
+ // If it does do any work, then it will return true, and false otherwise. That way you can
+ // call it in the breakpoint action, and if it returns true you're done.
+ bool
+ InitializeFromAllImageInfos ();
+
+ bool
+ ReadAllImageInfosStructure ();
+
+ bool
+ AddModulesUsingInfosFromDebugserver (lldb_private::StructuredData::ObjectSP image_details, DYLDImageInfo::collection &image_infos);
+
+ bool
+ AddModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count);
+
+ bool
+ AddModulesUsingImageInfos (DYLDImageInfo::collection &image_infos);
+
+ bool
+ RemoveModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count);
+
+ void
+ UpdateImageInfosHeaderAndLoadCommands(DYLDImageInfo::collection &image_infos,
+ uint32_t infos_count,
+ bool update_executable);
+
+ bool
+ ReadImageInfos (lldb::addr_t image_infos_addr,
+ uint32_t image_infos_count,
+ DYLDImageInfo::collection &image_infos);
+
+
+ DYLDImageInfo m_dyld; // Info about the current dyld being used
+ lldb::ModuleWP m_dyld_module_wp;
+ lldb::addr_t m_dyld_all_image_infos_addr;
+ DYLDAllImageInfos m_dyld_all_image_infos;
+ uint32_t m_dyld_all_image_infos_stop_id;
+ lldb::user_id_t m_break_id;
+ DYLDImageInfo::collection m_dyld_image_infos; // Current shared libraries information
+ uint32_t m_dyld_image_infos_stop_id; // The process stop ID that "m_dyld_image_infos" is valid for
+ mutable lldb_private::Mutex m_mutex;
+ lldb_private::Process::Notifications m_notification_callbacks;
+ bool m_process_image_addr_is_all_images_infos;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (DynamicLoaderMacOSXDYLD);
+};
+
+#endif // liblldb_DynamicLoaderMacOSXDYLD_h_
diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/Makefile b/source/Plugins/DynamicLoader/MacOSX-DYLD/Makefile
new file mode 100644
index 000000000000..ffac3b457179
--- /dev/null
+++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Disassembler/llvm/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginDynamicLoaderMacOSXDYLD
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/CMakeLists.txt b/source/Plugins/DynamicLoader/POSIX-DYLD/CMakeLists.txt
new file mode 100644
index 000000000000..b302997794a0
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_lldb_library(lldbPluginDynamicLoaderPosixDYLD
+ AuxVector.cpp
+ DYLDRendezvous.cpp
+ DynamicLoaderPOSIXDYLD.cpp
+ )
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/Makefile b/source/Plugins/DynamicLoader/POSIX-DYLD/Makefile
new file mode 100644
index 000000000000..1c56366015d6
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/DynamicLoader/POSIX-DYLD/Makefile ----*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginDynamicLoaderPosixDYLD
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/DynamicLoader/Static/CMakeLists.txt b/source/Plugins/DynamicLoader/Static/CMakeLists.txt
new file mode 100644
index 000000000000..274f6bac3697
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Static/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginDynamicLoaderStatic
+ DynamicLoaderStatic.cpp
+ )
diff --git a/source/Plugins/DynamicLoader/Static/Makefile b/source/Plugins/DynamicLoader/Static/Makefile
new file mode 100644
index 000000000000..63972dfc5512
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Static/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/DynamicLoader/Static/Makefile --------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginDynamicLoaderStatic
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/DynamicLoader/Windows-DYLD/CMakeLists.txt b/source/Plugins/DynamicLoader/Windows-DYLD/CMakeLists.txt
new file mode 100644
index 000000000000..ee768057bcd5
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Windows-DYLD/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginDynamicLoaderWindowsDYLD
+ DynamicLoaderWindowsDYLD.cpp
+ )
diff --git a/source/Plugins/DynamicLoader/Windows-DYLD/Makefile b/source/Plugins/DynamicLoader/Windows-DYLD/Makefile
new file mode 100644
index 000000000000..bf62aee30b2b
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Windows-DYLD/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/DynamicLoader/Windows-DYLD/Makefile --*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginDynamicLoaderWindowsDYLD
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ExpressionParser/CMakeLists.txt b/source/Plugins/ExpressionParser/CMakeLists.txt
new file mode 100644
index 000000000000..dc0540ad30a1
--- /dev/null
+++ b/source/Plugins/ExpressionParser/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(Clang)
+add_subdirectory(Go)
diff --git a/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
new file mode 100644
index 000000000000..e18dde6b700e
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_lldb_library(lldbPluginExpressionParserClang
+ ASTDumper.cpp
+ ASTResultSynthesizer.cpp
+ ASTStructExtractor.cpp
+ ClangASTSource.cpp
+ ClangExpressionDeclMap.cpp
+ ClangExpressionParser.cpp
+ ClangExpressionVariable.cpp
+ ClangFunctionCaller.cpp
+ ClangModulesDeclVendor.cpp
+ ClangPersistentVariables.cpp
+ ClangUserExpression.cpp
+ ClangUtilityFunction.cpp
+ IRForTarget.cpp
+ )
diff --git a/source/Plugins/ExpressionParser/Clang/Makefile b/source/Plugins/ExpressionParser/Clang/Makefile
new file mode 100644
index 000000000000..eb592daabb48
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ExpressionParser/Clang ---------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginExpressionParserClang
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ExpressionParser/Go/CMakeLists.txt b/source/Plugins/ExpressionParser/Go/CMakeLists.txt
new file mode 100644
index 000000000000..f59f51e76489
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Go/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_lldb_library(lldbPluginExpressionParserGo
+ GoLexer.cpp
+ GoParser.cpp
+ GoUserExpression.cpp
+ )
diff --git a/source/Plugins/ExpressionParser/Go/Makefile b/source/Plugins/ExpressionParser/Go/Makefile
new file mode 100644
index 000000000000..c5bd7fb2857e
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Go/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ExpressionParser/Clang ---------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginExpressionParserGo
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Instruction/ARM/CMakeLists.txt b/source/Plugins/Instruction/ARM/CMakeLists.txt
new file mode 100644
index 000000000000..dc547a57306b
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_lldb_library(lldbPluginInstructionARM
+ EmulateInstructionARM.cpp
+ EmulationStateARM.cpp
+ )
diff --git a/source/Plugins/Instruction/ARM/Makefile b/source/Plugins/Instruction/ARM/Makefile
new file mode 100644
index 000000000000..31a233b0b374
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Instruction/ARM/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginInstructionARM
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Instruction/ARM64/CMakeLists.txt b/source/Plugins/Instruction/ARM64/CMakeLists.txt
new file mode 100644
index 000000000000..9f8ee0848984
--- /dev/null
+++ b/source/Plugins/Instruction/ARM64/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginInstructionARM64
+ EmulateInstructionARM64.cpp
+ )
diff --git a/source/Plugins/Instruction/ARM64/Makefile b/source/Plugins/Instruction/ARM64/Makefile
new file mode 100644
index 000000000000..8f60ce6dcd47
--- /dev/null
+++ b/source/Plugins/Instruction/ARM64/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Instruction/ARM/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginInstructionARM64
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Instruction/CMakeLists.txt b/source/Plugins/Instruction/CMakeLists.txt
new file mode 100644
index 000000000000..78f2f64cf1ab
--- /dev/null
+++ b/source/Plugins/Instruction/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_subdirectory(ARM)
+add_subdirectory(ARM64)
+add_subdirectory(MIPS)
+add_subdirectory(MIPS64)
diff --git a/source/Plugins/Instruction/MIPS/CMakeLists.txt b/source/Plugins/Instruction/MIPS/CMakeLists.txt
new file mode 100644
index 000000000000..dc6707336939
--- /dev/null
+++ b/source/Plugins/Instruction/MIPS/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginInstructionMIPS
+ EmulateInstructionMIPS.cpp
+ )
diff --git a/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
index d6485f686e2c..a71fca7c5c3a 100644
--- a/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
+++ b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
@@ -591,45 +591,45 @@ EmulateInstructionMIPS::GetOpcodeForInstruction (const char *op_name)
//----------------------------------------------------------------------
// Branch instructions
//----------------------------------------------------------------------
- { "BEQ", &EmulateInstructionMIPS::Emulate_BEQ, "BEQ rs,rt,offset" },
- { "BNE", &EmulateInstructionMIPS::Emulate_BNE, "BNE rs,rt,offset" },
- { "BEQL", &EmulateInstructionMIPS::Emulate_BEQL, "BEQL rs,rt,offset" },
- { "BNEL", &EmulateInstructionMIPS::Emulate_BNEL, "BNEL rs,rt,offset" },
- { "BGEZALL", &EmulateInstructionMIPS::Emulate_BGEZALL, "BGEZALL rt,offset" },
+ { "BEQ", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BEQ rs,rt,offset" },
+ { "BNE", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BNE rs,rt,offset" },
+ { "BEQL", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BEQL rs,rt,offset" },
+ { "BNEL", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BNEL rs,rt,offset" },
+ { "BGEZALL", &EmulateInstructionMIPS::Emulate_Bcond_Link, "BGEZALL rt,offset" },
{ "BAL", &EmulateInstructionMIPS::Emulate_BAL, "BAL offset" },
- { "BGEZAL", &EmulateInstructionMIPS::Emulate_BGEZAL, "BGEZAL rs,offset" },
+ { "BGEZAL", &EmulateInstructionMIPS::Emulate_Bcond_Link, "BGEZAL rs,offset" },
{ "BALC", &EmulateInstructionMIPS::Emulate_BALC, "BALC offset" },
{ "BC", &EmulateInstructionMIPS::Emulate_BC, "BC offset" },
- { "BGEZ", &EmulateInstructionMIPS::Emulate_BGEZ, "BGEZ rs,offset" },
- { "BLEZALC", &EmulateInstructionMIPS::Emulate_BLEZALC, "BLEZALC rs,offset" },
- { "BGEZALC", &EmulateInstructionMIPS::Emulate_BGEZALC, "BGEZALC rs,offset" },
- { "BLTZALC", &EmulateInstructionMIPS::Emulate_BLTZALC, "BLTZALC rs,offset" },
- { "BGTZALC", &EmulateInstructionMIPS::Emulate_BGTZALC, "BGTZALC rs,offset" },
- { "BEQZALC", &EmulateInstructionMIPS::Emulate_BEQZALC, "BEQZALC rs,offset" },
- { "BNEZALC", &EmulateInstructionMIPS::Emulate_BNEZALC, "BNEZALC rs,offset" },
- { "BEQC", &EmulateInstructionMIPS::Emulate_BEQC, "BEQC rs,rt,offset" },
- { "BNEC", &EmulateInstructionMIPS::Emulate_BNEC, "BNEC rs,rt,offset" },
- { "BLTC", &EmulateInstructionMIPS::Emulate_BLTC, "BLTC rs,rt,offset" },
- { "BGEC", &EmulateInstructionMIPS::Emulate_BGEC, "BGEC rs,rt,offset" },
- { "BLTUC", &EmulateInstructionMIPS::Emulate_BLTUC, "BLTUC rs,rt,offset" },
- { "BGEUC", &EmulateInstructionMIPS::Emulate_BGEUC, "BGEUC rs,rt,offset" },
- { "BLTZC", &EmulateInstructionMIPS::Emulate_BLTZC, "BLTZC rt,offset" },
- { "BLEZC", &EmulateInstructionMIPS::Emulate_BLEZC, "BLEZC rt,offset" },
- { "BGEZC", &EmulateInstructionMIPS::Emulate_BGEZC, "BGEZC rt,offset" },
- { "BGTZC", &EmulateInstructionMIPS::Emulate_BGTZC, "BGTZC rt,offset" },
- { "BEQZC", &EmulateInstructionMIPS::Emulate_BEQZC, "BEQZC rt,offset" },
- { "BNEZC", &EmulateInstructionMIPS::Emulate_BNEZC, "BNEZC rt,offset" },
- { "BGEZL", &EmulateInstructionMIPS::Emulate_BGEZL, "BGEZL rt,offset" },
- { "BGTZ", &EmulateInstructionMIPS::Emulate_BGTZ, "BGTZ rt,offset" },
- { "BGTZL", &EmulateInstructionMIPS::Emulate_BGTZL, "BGTZL rt,offset" },
- { "BLEZ", &EmulateInstructionMIPS::Emulate_BLEZ, "BLEZ rt,offset" },
- { "BLEZL", &EmulateInstructionMIPS::Emulate_BLEZL, "BLEZL rt,offset" },
- { "BLTZ", &EmulateInstructionMIPS::Emulate_BLTZ, "BLTZ rt,offset" },
- { "BLTZAL", &EmulateInstructionMIPS::Emulate_BLTZAL, "BLTZAL rt,offset" },
- { "BLTZALL", &EmulateInstructionMIPS::Emulate_BLTZALL, "BLTZALL rt,offset" },
- { "BLTZL", &EmulateInstructionMIPS::Emulate_BLTZL, "BLTZL rt,offset" },
- { "BOVC", &EmulateInstructionMIPS::Emulate_BOVC, "BOVC rs,rt,offset" },
- { "BNVC", &EmulateInstructionMIPS::Emulate_BNVC, "BNVC rs,rt,offset" },
+ { "BGEZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGEZ rs,offset" },
+ { "BLEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BLEZALC rs,offset" },
+ { "BGEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BGEZALC rs,offset" },
+ { "BLTZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BLTZALC rs,offset" },
+ { "BGTZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BGTZALC rs,offset" },
+ { "BEQZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BEQZALC rs,offset" },
+ { "BNEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BNEZALC rs,offset" },
+ { "BEQC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BEQC rs,rt,offset" },
+ { "BNEC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BNEC rs,rt,offset" },
+ { "BLTC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BLTC rs,rt,offset" },
+ { "BGEC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BGEC rs,rt,offset" },
+ { "BLTUC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BLTUC rs,rt,offset" },
+ { "BGEUC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BGEUC rs,rt,offset" },
+ { "BLTZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BLTZC rt,offset" },
+ { "BLEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BLEZC rt,offset" },
+ { "BGEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BGEZC rt,offset" },
+ { "BGTZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BGTZC rt,offset" },
+ { "BEQZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BEQZC rt,offset" },
+ { "BNEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BNEZC rt,offset" },
+ { "BGEZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGEZL rt,offset" },
+ { "BGTZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGTZ rt,offset" },
+ { "BGTZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGTZL rt,offset" },
+ { "BLEZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLEZ rt,offset" },
+ { "BLEZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLEZL rt,offset" },
+ { "BLTZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLTZ rt,offset" },
+ { "BLTZAL", &EmulateInstructionMIPS::Emulate_Bcond_Link, "BLTZAL rt,offset" },
+ { "BLTZALL", &EmulateInstructionMIPS::Emulate_Bcond_Link, "BLTZALL rt,offset" },
+ { "BLTZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLTZL rt,offset" },
+ { "BOVC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BOVC rs,rt,offset" },
+ { "BNVC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BNVC rs,rt,offset" },
{ "J", &EmulateInstructionMIPS::Emulate_J, "J target" },
{ "JAL", &EmulateInstructionMIPS::Emulate_JAL, "JAL target" },
{ "JALX", &EmulateInstructionMIPS::Emulate_JAL, "JALX target" },
@@ -639,16 +639,16 @@ EmulateInstructionMIPS::GetOpcodeForInstruction (const char *op_name)
{ "JIC", &EmulateInstructionMIPS::Emulate_JIC, "JIC rt,offset" },
{ "JR", &EmulateInstructionMIPS::Emulate_JR, "JR target" },
{ "JR_HB", &EmulateInstructionMIPS::Emulate_JR, "JR.HB target" },
- { "BC1F", &EmulateInstructionMIPS::Emulate_BC1F, "BC1F cc, offset" },
- { "BC1T", &EmulateInstructionMIPS::Emulate_BC1T, "BC1T cc, offset" },
- { "BC1FL", &EmulateInstructionMIPS::Emulate_BC1FL, "BC1FL cc, offset" },
- { "BC1TL", &EmulateInstructionMIPS::Emulate_BC1TL, "BC1TL cc, offset" },
+ { "BC1F", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1F cc, offset" },
+ { "BC1T", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1T cc, offset" },
+ { "BC1FL", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1FL cc, offset" },
+ { "BC1TL", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1TL cc, offset" },
{ "BC1EQZ", &EmulateInstructionMIPS::Emulate_BC1EQZ, "BC1EQZ ft, offset" },
{ "BC1NEZ", &EmulateInstructionMIPS::Emulate_BC1NEZ, "BC1NEZ ft, offset" },
- { "BC1ANY2F", &EmulateInstructionMIPS::Emulate_BC1ANY2F, "BC1ANY2F cc, offset" },
- { "BC1ANY2T", &EmulateInstructionMIPS::Emulate_BC1ANY2T, "BC1ANY2T cc, offset" },
- { "BC1ANY4F", &EmulateInstructionMIPS::Emulate_BC1ANY4F, "BC1ANY4F cc, offset" },
- { "BC1ANY4T", &EmulateInstructionMIPS::Emulate_BC1ANY4T, "BC1ANY4T cc, offset" },
+ { "BC1ANY2F", &EmulateInstructionMIPS::Emulate_3D_branch, "BC1ANY2F cc, offset" },
+ { "BC1ANY2T", &EmulateInstructionMIPS::Emulate_3D_branch, "BC1ANY2T cc, offset" },
+ { "BC1ANY4F", &EmulateInstructionMIPS::Emulate_3D_branch, "BC1ANY4F cc, offset" },
+ { "BC1ANY4T", &EmulateInstructionMIPS::Emulate_3D_branch, "BC1ANY4T cc, offset" },
{ "BNZ_B", &EmulateInstructionMIPS::Emulate_BNZB, "BNZ.b wt,s16" },
{ "BNZ_H", &EmulateInstructionMIPS::Emulate_BNZH, "BNZ.h wt,s16" },
{ "BNZ_W", &EmulateInstructionMIPS::Emulate_BNZW, "BNZ.w wt,s16" },
@@ -1387,19 +1387,26 @@ EmulateInstructionMIPS::Emulate_JRADDIUSP (llvm::MCInst& insn)
return true;
}
+static int
+IsAdd64bitOverflow (int32_t a, int32_t b)
+{
+ int32_t r = (uint32_t) a + (uint32_t) b;
+ return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0);
+}
+
+/*
+ Emulate below MIPS branch instructions.
+ BEQ, BNE : Branch on condition
+ BEQL, BNEL : Branch likely
+*/
bool
-EmulateInstructionMIPS::Emulate_BEQ (llvm::MCInst& insn)
+EmulateInstructionMIPS::Emulate_BXX_3ops (llvm::MCInst& insn)
{
bool success = false;
uint32_t rs, rt;
- int32_t offset, pc, target, rs_val, rt_val;
+ int32_t offset, pc, target = 0, rs_val, rt_val;
+ const char *op_name = m_insn_info->getName (insn.getOpcode ());
- /*
- * BEQ rs, rt, offset
- * condition <- (GPR[rs] = GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
offset = insn.getOperand(2).getImm();
@@ -1416,13 +1423,399 @@ EmulateInstructionMIPS::Emulate_BEQ (llvm::MCInst& insn)
if (!success)
return false;
- if (rs_val == rt_val)
- target = pc + offset;
- else
- target = pc + 8;
+ if (!strcasecmp (op_name, "BEQ") ||
+ !strcasecmp (op_name, "BEQL"))
+ {
+ if (rs_val == rt_val)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+ else if (!strcasecmp (op_name, "BNE") ||
+ !strcasecmp (op_name, "BNEL"))
+ {
+ if (rs_val != rt_val)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
Context context;
context.type = eContextRelativeBranchImmediate;
+ context.SetImmediate (offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+/*
+ Emulate below MIPS branch instructions.
+ BEQC, BNEC, BLTC, BGEC, BLTUC, BGEUC, BOVC, BNVC: Compact branch instructions with no delay slot
+*/
+bool
+EmulateInstructionMIPS::Emulate_BXX_3ops_C (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs, rt;
+ int32_t offset, pc, target = 0, rs_val, rt_val;
+ const char *op_name = m_insn_info->getName (insn.getOpcode ());
+ uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize();
+
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ offset = insn.getOperand(2).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
+ if (!success)
+ return false;
+
+ if (!strcasecmp (op_name, "BEQC"))
+ {
+ if (rs_val == rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BNEC"))
+ {
+ if (rs_val != rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BLTC"))
+ {
+ if (rs_val < rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BGEC"))
+ {
+ if (rs_val >= rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BLTUC"))
+ {
+ if (rs_val < rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BGEUC"))
+ {
+ if ((uint32_t)rs_val >= (uint32_t)rt_val)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BOVC"))
+ {
+ if (IsAdd64bitOverflow (rs_val, rt_val))
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BNVC"))
+ {
+ if (!IsAdd64bitOverflow (rs_val, rt_val))
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+ context.SetImmediate (current_inst_size + offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+/*
+ Emulate below MIPS conditional branch and link instructions.
+ BLEZALC, BGEZALC, BLTZALC, BGTZALC, BEQZALC, BNEZALC : Compact branches
+*/
+bool
+EmulateInstructionMIPS::Emulate_Bcond_Link_C (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target = 0;
+ int32_t rs_val;
+ const char *op_name = m_insn_info->getName (insn.getOpcode ());
+
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (!strcasecmp (op_name, "BLEZALC"))
+ {
+ if (rs_val <= 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BGEZALC"))
+ {
+ if (rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BLTZALC"))
+ {
+ if (rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BGTZALC"))
+ {
+ if (rs_val > 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BEQZALC"))
+ {
+ if (rs_val == 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BNEZALC"))
+ {
+ if (rs_val != 0)
+ target = pc + offset;
+ else
+ target = pc + 4;
+ }
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 4))
+ return false;
+
+ return true;
+}
+
+/*
+ Emulate below MIPS Non-Compact conditional branch and link instructions.
+ BLTZAL, BGEZAL :
+ BLTZALL, BGEZALL : Branch likely
+*/
+bool
+EmulateInstructionMIPS::Emulate_Bcond_Link (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target = 0;
+ int32_t rs_val;
+ const char *op_name = m_insn_info->getName (insn.getOpcode ());
+
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (!strcasecmp (op_name, "BLTZAL") ||
+ !strcasecmp (op_name, "BLTZALL"))
+ {
+ if ((int32_t) rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+ else if (!strcasecmp (op_name, "BGEZAL") ||
+ !strcasecmp (op_name, "BGEZALL"))
+ {
+ if ((int32_t) rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+
+ Context context;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 8))
+ return false;
+
+ return true;
+}
+
+/*
+ Emulate below MIPS branch instructions.
+ BLTZL, BGEZL, BGTZL, BLEZL : Branch likely
+ BLTZ, BGEZ, BGTZ, BLEZ : Non-compact branches
+*/
+bool
+EmulateInstructionMIPS::Emulate_BXX_2ops (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target = 0;
+ int32_t rs_val;
+ const char *op_name = m_insn_info->getName (insn.getOpcode ());
+
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (!strcasecmp (op_name, "BLTZL") ||
+ !strcasecmp (op_name, "BLTZ"))
+ {
+ if (rs_val < 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+ else if (!strcasecmp (op_name, "BGEZL") ||
+ !strcasecmp (op_name, "BGEZ"))
+ {
+ if (rs_val >= 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+ else if (!strcasecmp (op_name, "BGTZL") ||
+ !strcasecmp (op_name, "BGTZ"))
+ {
+ if (rs_val > 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+ else if (!strcasecmp (op_name, "BLEZL") ||
+ !strcasecmp (op_name, "BLEZ"))
+ {
+ if (rs_val <= 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+ context.SetImmediate (offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
+ return false;
+
+ return true;
+}
+
+/*
+ Emulate below MIPS branch instructions.
+ BLTZC, BLEZC, BGEZC, BGTZC, BEQZC, BNEZC : Compact Branches
+*/
+bool
+EmulateInstructionMIPS::Emulate_BXX_2ops_C (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t rs;
+ int32_t offset, pc, target = 0;
+ int32_t rs_val;
+ const char *op_name = m_insn_info->getName (insn.getOpcode ());
+ uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize();
+
+ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
+ offset = insn.getOperand(1).getImm();
+
+ pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
+ if (!success)
+ return false;
+
+ rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
+ if (!success)
+ return false;
+
+ if (!strcasecmp (op_name, "BLTZC"))
+ {
+ if (rs_val < 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BLEZC"))
+ {
+ if (rs_val <= 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BGEZC"))
+ {
+ if (rs_val >= 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BGTZC"))
+ {
+ if (rs_val > 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BEQZC"))
+ {
+ if (rs_val == 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+ else if (!strcasecmp (op_name, "BNEZC"))
+ {
+ if (rs_val != 0)
+ target = pc + 4 + offset;
+ else
+ target = pc + 4;
+ }
+
+ Context context;
+ context.type = eContextRelativeBranchImmediate;
+ context.SetImmediate (current_inst_size + offset);
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
return false;
@@ -1688,450 +2081,6 @@ EmulateInstructionMIPS::Emulate_JALRS (llvm::MCInst& insn)
}
bool
-EmulateInstructionMIPS::Emulate_BNE (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target, rs_val, rt_val;
-
- /*
- * BNE rs, rt, offset
- * condition <- (GPR[rs] != GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (rs_val != rt_val)
- target = pc + offset;
- else
- target = pc + 8;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BEQL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target, rs_val, rt_val;
-
- /*
- * BEQL rs, rt, offset
- * condition <- (GPR[rs] = GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (rs_val == rt_val)
- target = pc + offset;
- else
- target = pc + 8; /* skip delay slot */
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BNEL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target, rs_val, rt_val;
-
- /*
- * BNEL rs, rt, offset
- * condition <- (GPR[rs] != GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (rs_val != rt_val)
- target = pc + offset;
- else
- target = pc + 8; /* skip delay slot */
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGEZL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BGEZL rs, offset
- * condition <- (GPR[rs] >= 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val >= 0)
- target = pc + offset;
- else
- target = pc + 8; /* skip delay slot */
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLTZL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BLTZL rs, offset
- * condition <- (GPR[rs] < 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val < 0)
- target = pc + offset;
- else
- target = pc + 8; /* skip delay slot */
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGTZL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BGTZL rs, offset
- * condition <- (GPR[rs] > 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val > 0)
- target = pc + offset;
- else
- target = pc + 8; /* skip delay slot */
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLEZL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BLEZL rs, offset
- * condition <- (GPR[rs] <= 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val <= 0)
- target = pc + offset;
- else
- target = pc + 8; /* skip delay slot */
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGTZ (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BGTZ rs, offset
- * condition <- (GPR[rs] > 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val > 0)
- target = pc + offset;
- else
- target = pc + 8;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLEZ (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BLEZ rs, offset
- * condition <- (GPR[rs] <= 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val <= 0)
- target = pc + offset;
- else
- target = pc + 8;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLTZ (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BLTZ rs, offset
- * condition <- (GPR[rs] < 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val < 0)
- target = pc + offset;
- else
- target = pc + 8;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGEZALL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BGEZALL rt, offset
- * condition <- (GPR[rs] >= 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val >= 0)
- target = pc + offset;
- else
- target = pc + 8; /* skip delay slot */
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 8))
- return false;
-
- return true;
-}
-
-bool
EmulateInstructionMIPS::Emulate_BAL (llvm::MCInst& insn)
{
bool success = false;
@@ -2194,430 +2143,6 @@ EmulateInstructionMIPS::Emulate_BALC (llvm::MCInst& insn)
}
bool
-EmulateInstructionMIPS::Emulate_BGEZAL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BGEZAL rs,offset
- * offset = sign_ext (offset << 2)
- * condition <- (GPR[rs] >= 0)
- * if condition then
- * RA = PC + 8
- * PC = PC + offset
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- Context context;
-
- if ((int32_t) rs_val >= 0)
- target = pc + offset;
- else
- target = pc + 8;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 8))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLTZAL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BLTZAL rs,offset
- * offset = sign_ext (offset << 2)
- * condition <- (GPR[rs] < 0)
- * if condition then
- * RA = PC + 8
- * PC = PC + offset
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- Context context;
-
- if ((int32_t) rs_val < 0)
- target = pc + offset;
- else
- target = pc + 8;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 8))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLTZALL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BLTZALL rs,offset
- * offset = sign_ext (offset << 2)
- * condition <- (GPR[rs] < 0)
- * if condition then
- * RA = PC + 8
- * PC = PC + offset
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- Context context;
-
- if (rs_val < 0)
- target = pc + offset;
- else
- target = pc + 8; /* skip delay slot */
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 8))
- return false;
-
- return true;
-}
-
-
-bool
-EmulateInstructionMIPS::Emulate_BLEZALC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BLEZALC rs,offset
- * offset = sign_ext (offset << 2)
- * condition <- (GPR[rs] <= 0)
- * if condition then
- * RA = PC + 4
- * PC = PC + offset
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- Context context;
-
- if (rs_val <= 0)
- target = pc + offset;
- else
- target = pc + 4;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 4))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGEZALC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BGEZALC rs,offset
- * offset = sign_ext (offset << 2)
- * condition <- (GPR[rs] >= 0)
- * if condition then
- * RA = PC + 4
- * PC = PC + offset
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- Context context;
-
- if (rs_val >= 0)
- target = pc + offset;
- else
- target = pc + 4;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 4))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLTZALC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BLTZALC rs,offset
- * offset = sign_ext (offset << 2)
- * condition <- (GPR[rs] < 0)
- * if condition then
- * RA = PC + 4
- * PC = PC + offset
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- Context context;
-
- if (rs_val < 0)
- target = pc + offset;
- else
- target = pc + 4;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 4))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGTZALC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BGTZALC rs,offset
- * offset = sign_ext (offset << 2)
- * condition <- (GPR[rs] > 0)
- * if condition then
- * RA = PC + 4
- * PC = PC + offset
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- Context context;
-
- if (rs_val > 0)
- target = pc + offset;
- else
- target = pc + 4;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 4))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BEQZALC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target, rs_val;
-
- /*
- * BEQZALC rs,offset
- * offset = sign_ext (offset << 2)
- * condition <- (GPR[rs] == 0)
- * if condition then
- * RA = PC + 4
- * PC = PC + offset
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- Context context;
-
- if (rs_val == 0)
- target = pc + offset;
- else
- target = pc + 4;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 4))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BNEZALC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target, rs_val;
-
- /*
- * BNEZALC rs,offset
- * offset = sign_ext (offset << 2)
- * condition <- (GPR[rs] != 0)
- * if condition then
- * RA = PC + 4
- * PC = PC + offset
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- Context context;
-
- if (rs_val != 0)
- target = pc + offset;
- else
- target = pc + 4;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 4))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGEZ (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target, rs_val;
-
- /*
- * BGEZ rs,offset
- * offset = sign_ext (offset << 2)
- * condition <- (GPR[rs] >= 0)
- * if condition then
- * PC = PC + offset
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- Context context;
-
- if (rs_val >= 0)
- target = pc + offset;
- else
- target = pc + 8;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
EmulateInstructionMIPS::Emulate_BC (llvm::MCInst& insn)
{
bool success = false;
@@ -2645,597 +2170,6 @@ EmulateInstructionMIPS::Emulate_BC (llvm::MCInst& insn)
}
bool
-EmulateInstructionMIPS::Emulate_BEQC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target, rs_val, rt_val;
-
- /*
- * BEQC rs, rt, offset
- * condition <- (GPR[rs] = GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (rs_val == rt_val)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BNEC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target, rs_val, rt_val;
-
- /*
- * BNEC rs, rt, offset
- * condition <- (GPR[rs] != GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (rs_val != rt_val)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLTC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target;
- int32_t rs_val, rt_val;
-
- /*
- * BLTC rs, rt, offset
- * condition <- (GPR[rs] < GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (rs_val < rt_val)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGEC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target;
- int32_t rs_val, rt_val;
-
- /*
- * BGEC rs, rt, offset
- * condition <- (GPR[rs] > GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (rs_val > rt_val)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLTUC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target;
- uint32_t rs_val, rt_val;
-
- /*
- * BLTUC rs, rt, offset
- * condition <- (GPR[rs] < GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (rs_val < rt_val)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGEUC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target;
- uint32_t rs_val, rt_val;
-
- /*
- * BGEUC rs, rt, offset
- * condition <- (GPR[rs] > GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (rs_val > rt_val)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLTZC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BLTZC rs, offset
- * condition <- (GPR[rs] < 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val < 0)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BLEZC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BLEZC rs, offset
- * condition <- (GPR[rs] <= 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val <= 0)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGEZC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BGEZC rs, offset
- * condition <- (GPR[rs] >= 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val >= 0)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BGTZC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- int32_t rs_val;
-
- /*
- * BGTZC rs, offset
- * condition <- (GPR[rs] > 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val > 0)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BEQZC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- uint32_t rs_val;
-
- /*
- * BEQZC rs, offset
- * condition <- (GPR[rs] = 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val == 0)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BNEZC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs;
- int32_t offset, pc, target;
- uint32_t rs_val;
-
- /*
- * BNEZC rs, offset
- * condition <- (GPR[rs] != 0)
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- if (rs_val != 0)
- target = pc + 4 + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-static int
-IsAdd64bitOverflow (int32_t a, int32_t b)
-{
- int32_t r = (uint32_t) a + (uint32_t) b;
- return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0);
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BOVC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target;
- int32_t rs_val, rt_val;
-
- /*
- * BOVC rs, rt, offset
- * condition <- overflow(GPR[rs] + GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (IsAdd64bitOverflow (rs_val, rt_val))
- target = pc + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BNVC (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t rs, rt;
- int32_t offset, pc, target;
- int32_t rs_val, rt_val;
-
- /*
- * BNVC rs, rt, offset
- * condition <- overflow(GPR[rs] + GPR[rt])
- * if condition then
- * PC = PC + sign_ext (offset << 2)
- */
- rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- offset = insn.getOperand(2).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
- if (!success)
- return false;
-
- rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
- if (!success)
- return false;
-
- if (! IsAdd64bitOverflow (rs_val, rt_val))
- target = pc + offset;
- else
- target = pc + 4;
-
- Context context;
- context.type = eContextRelativeBranchImmediate;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
EmulateInstructionMIPS::Emulate_J (llvm::MCInst& insn)
{
bool success = false;
@@ -3419,102 +2353,19 @@ EmulateInstructionMIPS::Emulate_JR (llvm::MCInst& insn)
return true;
}
+/*
+ Emulate Branch on FP True/False
+ BC1F, BC1FL : Branch on FP False (L stands for branch likely)
+ BC1T, BC1TL : Branch on FP True (L stands for branch likely)
+*/
bool
-EmulateInstructionMIPS::Emulate_BC1F (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t cc, fcsr;
- int32_t target, pc, offset;
-
- /*
- * BC1F cc, offset
- * condition <- (FPConditionCode(cc) == 0)
- * if condition then
- * offset = sign_ext (offset)
- * PC = PC + offset
- */
- cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips, 0, &success);
- if (!success)
- return false;
-
- /* fcsr[23], fcsr[25-31] are vaild condition bits */
- fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
-
- if ((fcsr & (1 << cc)) == 0)
- target = pc + offset;
- else
- target = pc + 8;
-
- Context context;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BC1T (llvm::MCInst& insn)
+EmulateInstructionMIPS::Emulate_FP_branch (llvm::MCInst& insn)
{
bool success = false;
uint32_t cc, fcsr;
- int32_t target, pc, offset;
-
- /*
- * BC1T cc, offset
- * condition <- (FPConditionCode(cc) != 0)
- * if condition then
- * offset = sign_ext (offset)
- * PC = PC + offset
- */
- cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips, 0, &success);
- if (!success)
- return false;
-
- /* fcsr[23], fcsr[25-31] are vaild condition bits */
- fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
-
- if ((fcsr & (1 << cc)) != 0)
- target = pc + offset;
- else
- target = pc + 8;
-
- Context context;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
+ int32_t pc, offset, target = 0;
+ const char *op_name = m_insn_info->getName (insn.getOpcode ());
-bool
-EmulateInstructionMIPS::Emulate_BC1FL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t cc, fcsr;
- int32_t target, pc, offset;
-
- /*
- * BC1F cc, offset
- * condition <- (FPConditionCode(cc) == 0)
- * if condition then
- * offset = sign_ext (offset)
- * PC = PC + offset
- */
cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
offset = insn.getOperand(1).getImm();
@@ -3528,53 +2379,23 @@ EmulateInstructionMIPS::Emulate_BC1FL (llvm::MCInst& insn)
/* fcsr[23], fcsr[25-31] are vaild condition bits */
fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
-
- if ((fcsr & (1 << cc)) == 0)
- target = pc + offset;
- else
- target = pc + 8; /* skip delay slot */
-
- Context context;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-bool
-EmulateInstructionMIPS::Emulate_BC1TL (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t cc, fcsr;
- int32_t target, pc, offset;
-
- /*
- * BC1T cc, offset
- * condition <- (FPConditionCode(cc) != 0)
- * if condition then
- * offset = sign_ext (offset)
- * PC = PC + offset
- */
- cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips, 0, &success);
- if (!success)
- return false;
-
- /* fcsr[23], fcsr[25-31] are vaild condition bits */
- fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
-
- if ((fcsr & (1 << cc)) != 0)
- target = pc + offset;
- else
- target = pc + 8; /* skip delay slot */
-
+ if (!strcasecmp (op_name, "BC1F") ||
+ !strcasecmp (op_name, "BC1FL"))
+ {
+ if ((fcsr & (1 << cc)) == 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+ else if (!strcasecmp (op_name, "BC1T") ||
+ !strcasecmp (op_name, "BC1TL"))
+ {
+ if ((fcsr & (1 << cc)) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
Context context;
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
@@ -3661,154 +2482,19 @@ EmulateInstructionMIPS::Emulate_BC1NEZ (llvm::MCInst& insn)
return true;
}
+/*
+ Emulate MIPS-3D Branch instructions
+ BC1ANY2F, BC1ANY2T : Branch on Any of Two Floating Point Condition Codes False/True
+ BC1ANY4F, BC1ANY4T : Branch on Any of Four Floating Point Condition Codes False/True
+*/
bool
-EmulateInstructionMIPS::Emulate_BC1ANY2F (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t cc, fcsr;
- int32_t target, pc, offset;
-
- /*
- * BC1ANY2F cc, offset
- * condition <- (FPConditionCode(cc) == 0
- * || FPConditionCode(cc+1) == 0)
- * if condition then
- * offset = sign_ext (offset)
- * PC = PC + offset
- */
- cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips, 0, &success);
- if (!success)
- return false;
-
- /* fcsr[23], fcsr[25-31] are vaild condition bits */
- fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
-
- /* if any one bit is 0 */
- if (((fcsr >> cc) & 3) != 3)
- target = pc + offset;
- else
- target = pc + 8;
-
- Context context;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BC1ANY2T (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t cc, fcsr;
- int32_t target, pc, offset;
-
- /*
- * BC1ANY2T cc, offset
- * condition <- (FPConditionCode(cc) == 1
- * || FPConditionCode(cc+1) == 1)
- * if condition then
- * offset = sign_ext (offset)
- * PC = PC + offset
- */
- cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips, 0, &success);
- if (!success)
- return false;
-
- /* fcsr[23], fcsr[25-31] are vaild condition bits */
- fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
-
- /* if any one bit is 1 */
- if (((fcsr >> cc) & 3) != 0)
- target = pc + offset;
- else
- target = pc + 8;
-
- Context context;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
-
-bool
-EmulateInstructionMIPS::Emulate_BC1ANY4F (llvm::MCInst& insn)
+EmulateInstructionMIPS::Emulate_3D_branch (llvm::MCInst& insn)
{
bool success = false;
uint32_t cc, fcsr;
- int32_t target, pc, offset;
-
- /*
- * BC1ANY4F cc, offset
- * condition <- (FPConditionCode(cc) == 0
- * || FPConditionCode(cc+1) == 0)
- * || FPConditionCode(cc+2) == 0)
- * || FPConditionCode(cc+3) == 0)
- * if condition then
- * offset = sign_ext (offset)
- * PC = PC + offset
- */
- cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
- offset = insn.getOperand(1).getImm();
-
- pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
- if (!success)
- return false;
-
- fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips, 0, &success);
- if (!success)
- return false;
-
- /* fcsr[23], fcsr[25-31] are vaild condition bits */
- fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
-
- /* if any one bit is 0 */
- if (((fcsr >> cc) & 0xf) != 0xf)
- target = pc + offset;
- else
- target = pc + 8;
-
- Context context;
-
- if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
- return false;
-
- return true;
-}
+ int32_t pc, offset, target = 0;
+ const char *op_name = m_insn_info->getName (insn.getOpcode ());
-bool
-EmulateInstructionMIPS::Emulate_BC1ANY4T (llvm::MCInst& insn)
-{
- bool success = false;
- uint32_t cc, fcsr;
- int32_t target, pc, offset;
-
- /*
- * BC1ANY4T cc, offset
- * condition <- (FPConditionCode(cc) == 1
- * || FPConditionCode(cc+1) == 1)
- * || FPConditionCode(cc+2) == 1)
- * || FPConditionCode(cc+3) == 1)
- * if condition then
- * offset = sign_ext (offset)
- * PC = PC + offset
- */
cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
offset = insn.getOperand(1).getImm();
@@ -3823,12 +2509,38 @@ EmulateInstructionMIPS::Emulate_BC1ANY4T (llvm::MCInst& insn)
/* fcsr[23], fcsr[25-31] are vaild condition bits */
fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
- /* if any one bit is 1 */
- if (((fcsr >> cc) & 0xf) != 0)
- target = pc + offset;
- else
- target = pc + 8;
-
+ if (!strcasecmp (op_name, "BC1ANY2F"))
+ {
+ /* if any one bit is 0 */
+ if (((fcsr >> cc) & 3) != 3)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+ else if (!strcasecmp (op_name, "BC1ANY2T"))
+ {
+ /* if any one bit is 1 */
+ if (((fcsr >> cc) & 3) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+ else if (!strcasecmp (op_name, "BC1ANY4F"))
+ {
+ /* if any one bit is 0 */
+ if (((fcsr >> cc) & 0xf) != 0xf)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
+ else if (!strcasecmp (op_name, "BC1ANY4T"))
+ {
+ /* if any one bit is 1 */
+ if (((fcsr >> cc) & 0xf) != 0)
+ target = pc + offset;
+ else
+ target = pc + 8;
+ }
Context context;
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target))
diff --git a/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
index e1340f983278..892de054e2ae 100644
--- a/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
+++ b/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
@@ -160,121 +160,37 @@ protected:
Emulate_LDST_Reg (llvm::MCInst& insn);
bool
- Emulate_BEQ (llvm::MCInst& insn);
+ Emulate_BXX_3ops (llvm::MCInst& insn);
bool
- Emulate_BNE (llvm::MCInst& insn);
+ Emulate_BXX_3ops_C (llvm::MCInst& insn);
bool
- Emulate_BEQL (llvm::MCInst& insn);
+ Emulate_BXX_2ops (llvm::MCInst& insn);
bool
- Emulate_BNEL (llvm::MCInst& insn);
+ Emulate_BXX_2ops_C (llvm::MCInst& insn);
bool
- Emulate_BGEZALL (llvm::MCInst& insn);
+ Emulate_Bcond_Link_C (llvm::MCInst& insn);
bool
- Emulate_BAL (llvm::MCInst& insn);
-
- bool
- Emulate_BGEZAL (llvm::MCInst& insn);
-
- bool
- Emulate_BALC (llvm::MCInst& insn);
-
- bool
- Emulate_BC (llvm::MCInst& insn);
-
- bool
- Emulate_BGEZ (llvm::MCInst& insn);
-
- bool
- Emulate_BLEZALC (llvm::MCInst& insn);
-
- bool
- Emulate_BGEZALC (llvm::MCInst& insn);
-
- bool
- Emulate_BLTZALC (llvm::MCInst& insn);
-
- bool
- Emulate_BGTZALC (llvm::MCInst& insn);
-
- bool
- Emulate_BEQZALC (llvm::MCInst& insn);
-
- bool
- Emulate_BNEZALC (llvm::MCInst& insn);
-
- bool
- Emulate_BEQC (llvm::MCInst& insn);
-
- bool
- Emulate_BNEC (llvm::MCInst& insn);
-
- bool
- Emulate_BLTC (llvm::MCInst& insn);
-
- bool
- Emulate_BGEC (llvm::MCInst& insn);
-
- bool
- Emulate_BLTUC (llvm::MCInst& insn);
-
- bool
- Emulate_BGEUC (llvm::MCInst& insn);
-
- bool
- Emulate_BLTZC (llvm::MCInst& insn);
-
- bool
- Emulate_BLEZC (llvm::MCInst& insn);
+ Emulate_Bcond_Link (llvm::MCInst& insn);
bool
- Emulate_BGEZC (llvm::MCInst& insn);
+ Emulate_FP_branch (llvm::MCInst& insn);
bool
- Emulate_BGTZC (llvm::MCInst& insn);
+ Emulate_3D_branch (llvm::MCInst& insn);
bool
- Emulate_BEQZC (llvm::MCInst& insn);
-
- bool
- Emulate_BNEZC (llvm::MCInst& insn);
-
- bool
- Emulate_BGEZL (llvm::MCInst& insn);
-
- bool
- Emulate_BGTZ (llvm::MCInst& insn);
-
- bool
- Emulate_BGTZL (llvm::MCInst& insn);
-
- bool
- Emulate_BLEZ (llvm::MCInst& insn);
-
- bool
- Emulate_BLEZL (llvm::MCInst& insn);
-
- bool
- Emulate_BLTZ (llvm::MCInst& insn);
-
- bool
- Emulate_BLTZAL (llvm::MCInst& insn);
-
- bool
- Emulate_BLTZALL (llvm::MCInst& insn);
-
- bool
- Emulate_BLTZL (llvm::MCInst& insn);
+ Emulate_BAL (llvm::MCInst& insn);
bool
- Emulate_BOVC (llvm::MCInst& insn);
+ Emulate_BALC (llvm::MCInst& insn);
bool
- Emulate_BNVC (llvm::MCInst& insn);
+ Emulate_BC (llvm::MCInst& insn);
bool
Emulate_J (llvm::MCInst& insn);
@@ -295,36 +211,12 @@ protected:
Emulate_JR (llvm::MCInst& insn);
bool
- Emulate_BC1F (llvm::MCInst& insn);
-
- bool
- Emulate_BC1T (llvm::MCInst& insn);
-
- bool
- Emulate_BC1FL (llvm::MCInst& insn);
-
- bool
- Emulate_BC1TL (llvm::MCInst& insn);
-
- bool
Emulate_BC1EQZ (llvm::MCInst& insn);
bool
Emulate_BC1NEZ (llvm::MCInst& insn);
bool
- Emulate_BC1ANY2F (llvm::MCInst& insn);
-
- bool
- Emulate_BC1ANY2T (llvm::MCInst& insn);
-
- bool
- Emulate_BC1ANY4F (llvm::MCInst& insn);
-
- bool
- Emulate_BC1ANY4T (llvm::MCInst& insn);
-
- bool
Emulate_BNZB (llvm::MCInst& insn);
bool
diff --git a/source/Plugins/Instruction/MIPS/Makefile b/source/Plugins/Instruction/MIPS/Makefile
new file mode 100644
index 000000000000..e9cef4ba0cf7
--- /dev/null
+++ b/source/Plugins/Instruction/MIPS/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Instruction/MIPS/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginInstructionMIPS
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Instruction/MIPS64/CMakeLists.txt b/source/Plugins/Instruction/MIPS64/CMakeLists.txt
new file mode 100644
index 000000000000..25c919c4edb6
--- /dev/null
+++ b/source/Plugins/Instruction/MIPS64/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginInstructionMIPS64
+ EmulateInstructionMIPS64.cpp
+ )
diff --git a/source/Plugins/Instruction/MIPS64/Makefile b/source/Plugins/Instruction/MIPS64/Makefile
new file mode 100644
index 000000000000..7e5b339a359d
--- /dev/null
+++ b/source/Plugins/Instruction/MIPS64/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Instruction/MIPS64/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginInstructionMIPS64
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/InstrumentationRuntime/AddressSanitizer/CMakeLists.txt b/source/Plugins/InstrumentationRuntime/AddressSanitizer/CMakeLists.txt
new file mode 100644
index 000000000000..77e7d15caa7c
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/AddressSanitizer/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeAddressSanitizer
+ AddressSanitizerRuntime.cpp
+ )
diff --git a/source/Plugins/InstrumentationRuntime/AddressSanitizer/Makefile b/source/Plugins/InstrumentationRuntime/AddressSanitizer/Makefile
new file mode 100644
index 000000000000..030aec17b026
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/AddressSanitizer/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/InstrumentationRuntime/AddressSanitizer Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginInstrumentationRuntimeAddressSanitizer
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/InstrumentationRuntime/CMakeLists.txt b/source/Plugins/InstrumentationRuntime/CMakeLists.txt
new file mode 100644
index 000000000000..8ee303b25359
--- /dev/null
+++ b/source/Plugins/InstrumentationRuntime/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(AddressSanitizer)
diff --git a/source/Plugins/JITLoader/CMakeLists.txt b/source/Plugins/JITLoader/CMakeLists.txt
new file mode 100644
index 000000000000..e52230199109
--- /dev/null
+++ b/source/Plugins/JITLoader/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(GDB)
diff --git a/source/Plugins/JITLoader/GDB/CMakeLists.txt b/source/Plugins/JITLoader/GDB/CMakeLists.txt
new file mode 100644
index 000000000000..bcf714dca593
--- /dev/null
+++ b/source/Plugins/JITLoader/GDB/CMakeLists.txt
@@ -0,0 +1,6 @@
+include_directories(.)
+
+add_lldb_library(lldbPluginJITLoaderGDB
+ JITLoaderGDB.cpp
+ )
+
diff --git a/source/Plugins/JITLoader/GDB/Makefile b/source/Plugins/JITLoader/GDB/Makefile
new file mode 100644
index 000000000000..cd5404ffca18
--- /dev/null
+++ b/source/Plugins/JITLoader/GDB/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/JITLoader/GDB/Makefile ---------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginJITLoaderGDB
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Language/CMakeLists.txt b/source/Plugins/Language/CMakeLists.txt
new file mode 100644
index 000000000000..60b3da2406b6
--- /dev/null
+++ b/source/Plugins/Language/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_subdirectory(CPlusPlus)
+add_subdirectory(Go)
+add_subdirectory(ObjC)
+add_subdirectory(ObjCPlusPlus)
diff --git a/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/source/Plugins/Language/CPlusPlus/CMakeLists.txt
new file mode 100644
index 000000000000..0b0f0f451a8d
--- /dev/null
+++ b/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_lldb_library(lldbPluginCPlusPlusLanguage
+ CPlusPlusLanguage.cpp
+ CxxStringTypes.cpp
+ LibCxx.cpp
+ LibCxxInitializerList.cpp
+ LibCxxList.cpp
+ LibCxxMap.cpp
+ LibCxxUnorderedMap.cpp
+ LibCxxVector.cpp
+ LibStdcpp.cpp
+)
diff --git a/source/Plugins/Language/CPlusPlus/Makefile b/source/Plugins/Language/CPlusPlus/Makefile
new file mode 100644
index 000000000000..2cb0dcf638b3
--- /dev/null
+++ b/source/Plugins/Language/CPlusPlus/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Language/CPlusPlus -------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginCPlusPlusLanguage
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Language/Go/CMakeLists.txt b/source/Plugins/Language/Go/CMakeLists.txt
new file mode 100644
index 000000000000..f3a9c12b7523
--- /dev/null
+++ b/source/Plugins/Language/Go/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_lldb_library(lldbPluginGoLanguage
+ GoLanguage.cpp
+ GoFormatterFunctions.cpp
+)
diff --git a/source/Plugins/Language/Go/Makefile b/source/Plugins/Language/Go/Makefile
new file mode 100644
index 000000000000..3ea09f6c538f
--- /dev/null
+++ b/source/Plugins/Language/Go/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Language/Go -------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginGoLanguage
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Language/ObjC/CMakeLists.txt b/source/Plugins/Language/ObjC/CMakeLists.txt
new file mode 100644
index 000000000000..5c480a1aed11
--- /dev/null
+++ b/source/Plugins/Language/ObjC/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginObjCLanguage
+ ObjCLanguage.cpp
+ CF.cpp
+ Cocoa.cpp
+ CoreMedia.cpp
+ NSArray.cpp
+ NSDictionary.cpp
+ NSError.cpp
+ NSException.cpp
+ NSIndexPath.cpp
+ NSSet.cpp
+ NSString.cpp
+)
diff --git a/source/Plugins/Language/ObjC/Makefile b/source/Plugins/Language/ObjC/Makefile
new file mode 100644
index 000000000000..58c9e58f2bc6
--- /dev/null
+++ b/source/Plugins/Language/ObjC/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Language/ObjC ------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginObjCLanguage
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt b/source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt
new file mode 100644
index 000000000000..ef80af74107b
--- /dev/null
+++ b/source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginObjCPlusPlusLanguage
+ ObjCPlusPlusLanguage.cpp
+)
diff --git a/source/Plugins/Language/ObjCPlusPlus/Makefile b/source/Plugins/Language/ObjCPlusPlus/Makefile
new file mode 100644
index 000000000000..74e1a14bcf4d
--- /dev/null
+++ b/source/Plugins/Language/ObjCPlusPlus/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Language/ObjCPlusPlus ----------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginObjCPlusPlusLanguage
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/LanguageRuntime/CMakeLists.txt b/source/Plugins/LanguageRuntime/CMakeLists.txt
new file mode 100644
index 000000000000..66b17a4af229
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_subdirectory(CPlusPlus)
+add_subdirectory(ObjC)
+add_subdirectory(Go)
+add_subdirectory(RenderScript)
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt b/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt
new file mode 100644
index 000000000000..26c68c60b019
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(ItaniumABI)
+#add_subdirectory(MicrosoftABI)
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt
new file mode 100644
index 000000000000..d25215d0a613
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginCXXItaniumABI
+ ItaniumABILanguageRuntime.cpp
+ )
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/Makefile b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/Makefile
new file mode 100644
index 000000000000..ac87437f9d2a
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/LangRuntime/C++/ItaniumABI/Makefile --*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../../..
+LIBRARYNAME := lldbPluginCXXItaniumABI
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/LanguageRuntime/Go/CMakeLists.txt b/source/Plugins/LanguageRuntime/Go/CMakeLists.txt
new file mode 100644
index 000000000000..7c9166a94cbe
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/Go/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_NO_RTTI 1)
+
+add_lldb_library(lldbPluginLanguageRuntimeGo
+ GoLanguageRuntime.cpp
+ )
diff --git a/source/Plugins/LanguageRuntime/Go/Makefile b/source/Plugins/LanguageRuntime/Go/Makefile
new file mode 100644
index 000000000000..1c8114e421c1
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/Go/Makefile
@@ -0,0 +1,14 @@
+##===- Source/Plugins/LangRuntime/Go/Makefile ----*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginLanguageRuntimeGo
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt
new file mode 100644
index 000000000000..13fde3d181fa
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_lldb_library(lldbPluginAppleObjCRuntime
+ AppleObjCRuntime.cpp
+ AppleObjCRuntimeV1.cpp
+ AppleObjCRuntimeV2.cpp
+ AppleObjCTrampolineHandler.cpp
+ AppleObjCDeclVendor.cpp
+ AppleThreadPlanStepThroughObjCTrampoline.cpp
+ AppleObjCClassDescriptorV2.cpp
+ AppleObjCTypeEncodingParser.cpp
+ )
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/Makefile b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/Makefile
new file mode 100644
index 000000000000..485fe75b3f88
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/LangRuntime/ObjC/AppleRT/Makefile ----*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../../..
+LIBRARYNAME := lldbPluginAppleObjCRuntime
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt b/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
new file mode 100644
index 000000000000..af13dc6a144d
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(AppleObjCRuntime)
diff --git a/source/Plugins/LanguageRuntime/RenderScript/CMakeLists.txt b/source/Plugins/LanguageRuntime/RenderScript/CMakeLists.txt
new file mode 100644
index 000000000000..d944d76c4957
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/RenderScript/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(RenderScriptRuntime)
diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt
new file mode 100644
index 000000000000..d93e9fa2a291
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginRenderScriptRuntime
+ RenderScriptRuntime.cpp
+ )
diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/Makefile b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/Makefile
new file mode 100644
index 000000000000..eeb50ae3fcae
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/Makefile
@@ -0,0 +1,14 @@
+##===- Source/Plugins/LangRuntime/RenderScript/RenderScriptRuntime/Makefile ----*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../../..
+LIBRARYNAME := lldbPluginRenderScriptRuntime
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
index 149244df30c2..5d82ded50882 100644
--- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
+++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
@@ -452,7 +452,7 @@ RenderScriptRuntime::GetPluginNameStatic()
return g_name;
}
-RenderScriptRuntime::ModuleKind
+RenderScriptRuntime::ModuleKind
RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp)
{
if (module_sp)
@@ -493,7 +493,7 @@ RenderScriptRuntime::IsRenderScriptModule(const lldb::ModuleSP &module_sp)
return GetModuleKind(module_sp) != eModuleKindIgnored;
}
-void
+void
RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list )
{
Mutex::Locker locker (module_list.GetMutex ());
@@ -640,11 +640,11 @@ RenderScriptRuntime::HookCallback(void *baton, StoppointCallbackContext *ctx, ll
RenderScriptRuntime *lang_rt = (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
lang_rt->HookCallback(hook_info, context);
-
+
return false;
}
-void
+void
RenderScriptRuntime::HookCallback(RuntimeHook* hook_info, ExecutionContext& context)
{
Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
@@ -652,7 +652,7 @@ RenderScriptRuntime::HookCallback(RuntimeHook* hook_info, ExecutionContext& cont
if (log)
log->Printf ("RenderScriptRuntime::HookCallback - '%s' .", hook_info->defn->name);
- if (hook_info->defn->grabber)
+ if (hook_info->defn->grabber)
{
(this->*(hook_info->defn->grabber))(hook_info, context);
}
@@ -706,7 +706,6 @@ RenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint6
*data = result;
success = true;
}
-
break;
}
case llvm::Triple::ArchType::x86_64:
@@ -741,6 +740,7 @@ RenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint6
case llvm::Triple::ArchType::arm:
{
// arm 32 bit
+ // first 4 arguments are passed via registers
if (arg < 4)
{
const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg);
@@ -760,18 +760,19 @@ RenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint6
{
uint64_t sp = reg_ctx->GetSP();
uint32_t offset = (arg-4) * sizeof(uint32_t);
- process->ReadMemory(sp + offset, &data, sizeof(uint32_t), error);
- if (error.Fail())
+ uint32_t value = 0;
+ size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error);
+ if (error.Fail() || bytes_read != sizeof(value))
{
if (log)
log->Printf("RenderScriptRuntime::GetArgSimple - error reading ARM stack: %s.", error.AsCString());
}
else
{
+ *data = value;
success = true;
}
}
-
break;
}
case llvm::Triple::ArchType::aarch64:
@@ -803,8 +804,8 @@ RenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint6
}
case llvm::Triple::ArchType::mipsel:
{
-
// read from the registers
+ // first 4 arguments are passed in registers
if (arg < 4){
const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg + 4);
RegisterValue rVal;
@@ -818,26 +819,25 @@ RenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint6
if (log)
log->Printf("RenderScriptRuntime::GetArgSimple() - Mips - Error while reading the argument #%d", arg);
}
-
}
-
- // read from the stack
+ // arguments > 4 are read from the stack
else
{
uint64_t sp = reg_ctx->GetSP();
uint32_t offset = arg * sizeof(uint32_t);
- process->ReadMemory(sp + offset, &data, sizeof(uint32_t), error);
- if (error.Fail())
+ uint32_t value = 0;
+ size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error);
+ if (error.Fail() || bytes_read != sizeof(value))
{
if (log)
log->Printf("RenderScriptRuntime::GetArgSimple - error reading Mips stack: %s.", error.AsCString());
}
else
{
+ *data = value;
success = true;
}
}
-
break;
}
case llvm::Triple::ArchType::mips64el:
@@ -858,24 +858,24 @@ RenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint6
log->Printf("RenderScriptRuntime::GetArgSimple - Mips64 - Error reading the argument #%d", arg);
}
}
-
- // read from the stack
+ // arguments > 8 are read from the stack
else
{
uint64_t sp = reg_ctx->GetSP();
uint32_t offset = (arg - 8) * sizeof(uint64_t);
- process->ReadMemory(sp + offset, &data, sizeof(uint64_t), error);
- if (error.Fail())
+ uint64_t value = 0;
+ size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error);
+ if (error.Fail() || bytes_read != sizeof(value))
{
if (log)
log->Printf("RenderScriptRuntime::GetArgSimple - Mips64 - Error reading Mips64 stack: %s.", error.AsCString());
}
else
{
+ *data = value;
success = true;
}
}
-
break;
}
default:
@@ -883,7 +883,6 @@ RenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint6
// invalid architecture
if (log)
log->Printf("RenderScriptRuntime::GetArgSimple - Architecture not supported");
-
}
}
@@ -895,11 +894,11 @@ RenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint6
return success;
}
-void
+void
RenderScriptRuntime::CaptureSetGlobalVar1(RuntimeHook* hook_info, ExecutionContext& context)
{
Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
-
+
//Context, Script, int, data, length
uint64_t rs_context_u64 = 0U;
@@ -921,7 +920,7 @@ RenderScriptRuntime::CaptureSetGlobalVar1(RuntimeHook* hook_info, ExecutionConte
log->Printf("RenderScriptRuntime::CaptureSetGlobalVar1 - Error while reading the function parameters");
return;
}
-
+
if (log)
{
log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 ":%" PRIu64 "bytes.",
@@ -934,18 +933,18 @@ RenderScriptRuntime::CaptureSetGlobalVar1(RuntimeHook* hook_info, ExecutionConte
if (rs_id_u64 < rsm->m_globals.size())
{
auto rsg = rsm->m_globals[rs_id_u64];
- log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - Setting of '%s' within '%s' inferred", rsg.m_name.AsCString(),
+ log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - Setting of '%s' within '%s' inferred", rsg.m_name.AsCString(),
rsm->m_module->GetFileSpec().GetFilename().AsCString());
}
}
}
}
-void
+void
RenderScriptRuntime::CaptureAllocationInit1(RuntimeHook* hook_info, ExecutionContext& context)
{
Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
-
+
//Context, Alloc, bool
uint64_t rs_context_u64 = 0U;
@@ -1009,7 +1008,7 @@ RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook* hook_info, ExecutionC
log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - Couldn't find destroyed allocation");
}
-void
+void
RenderScriptRuntime::CaptureScriptInit1(RuntimeHook* hook_info, ExecutionContext& context)
{
Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
@@ -1045,16 +1044,16 @@ RenderScriptRuntime::CaptureScriptInit1(RuntimeHook* hook_info, ExecutionContext
{
if (log)
log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading resname: %s.", error.AsCString());
-
+
}
process->ReadCStringFromMemory((lldb::addr_t)rs_cachedirptr_u64, cachedir, error);
if (error.Fail())
{
if (log)
- log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading cachedir: %s.", error.AsCString());
+ log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading cachedir: %s.", error.AsCString());
}
-
+
if (log)
log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .",
rs_context_u64, rs_script_u64, resname.c_str(), cachedir.c_str());
@@ -1077,7 +1076,7 @@ RenderScriptRuntime::CaptureScriptInit1(RuntimeHook* hook_info, ExecutionContext
if (log)
log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - '%s' tagged with context 0x%" PRIx64 " and script 0x%" PRIx64 ".",
strm.GetData(), rs_context_u64, rs_script_u64);
- }
+ }
else if (log)
{
log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - resource name invalid, Script not tagged");
@@ -1134,7 +1133,7 @@ RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind)
if (addr == LLDB_INVALID_ADDRESS)
{
if (log)
- log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Unable to resolve the address of hook function '%s' with symbol '%s'.",
+ log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Unable to resolve the address of hook function '%s' with symbol '%s'.",
hook_defn->name, symbol_name);
continue;
}
@@ -1152,7 +1151,7 @@ RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind)
m_runtimeHooks[addr] = hook;
if (log)
{
- log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Successfully hooked '%s' in '%s' version %" PRIu64 " at 0x%" PRIx64 ".",
+ log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Successfully hooked '%s' in '%s' version %" PRIu64 " at 0x%" PRIx64 ".",
hook_defn->name, module->GetFileSpec().GetFilename().AsCString(), (uint64_t)hook_defn->version, (uint64_t)addr);
}
}
@@ -2231,7 +2230,7 @@ RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const
// Write allocation data to file
num_bytes = static_cast<size_t>(*alloc->size.get());
if (log)
- log->Printf("RenderScriptRuntime::SaveAllocation - Writing 0x%" PRIx64 " bytes from %p", (uint64_t) num_bytes, buffer.get());
+ log->Printf("RenderScriptRuntime::SaveAllocation - Writing 0x%" PRIx64 " bytes from %p", (uint64_t) num_bytes, (void*) buffer.get());
err = file.Write(buffer.get(), num_bytes);
if (!err.Success())
@@ -2299,7 +2298,7 @@ RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp)
}
case eModuleKindLibRS:
{
- if (!m_libRS)
+ if (!m_libRS)
{
m_libRS = module_sp;
static ConstString gDbgPresentStr("gDebuggerPresent");
@@ -2334,7 +2333,7 @@ RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp)
break;
}
if (module_loaded)
- Update();
+ Update();
return module_loaded;
}
return false;
@@ -2408,7 +2407,7 @@ RSModuleDescriptor::ParseRSInfo()
m_kernels.push_back(RSKernelDescriptor(this, name, slot));
}
}
- }
+ }
else if (sscanf(line.c_str(), "pragmaCount: %u", &numDefns) == 1)
{
char name[MAXLINE];
@@ -2417,7 +2416,7 @@ RSModuleDescriptor::ParseRSInfo()
{
name[0] = '\0';
value[0] = '\0';
- if (sscanf(info_lines[++offset].c_str(), "%s - %s", &name[0], &value[0]) != 0
+ if (sscanf(info_lines[++offset].c_str(), "%s - %s", &name[0], &value[0]) != 0
&& (name[0] != '\0'))
{
m_pragmas[std::string(name)] = value;
@@ -2466,7 +2465,7 @@ RenderScriptRuntime::Status(Stream &strm) const
strm.Printf("CPU Reference Implementation discovered.");
strm.EOL();
}
-
+
if (m_runtimeHooks.size())
{
strm.Printf("Runtime functions hooked:");
@@ -2476,7 +2475,7 @@ RenderScriptRuntime::Status(Stream &strm) const
strm.Indent(b.second->defn->name);
strm.EOL();
}
- }
+ }
else
{
strm.Printf("Runtime is not hooked.");
@@ -2484,7 +2483,7 @@ RenderScriptRuntime::Status(Stream &strm) const
}
}
-void
+void
RenderScriptRuntime::DumpContexts(Stream &strm) const
{
strm.Printf("Inferred RenderScript Contexts:");
@@ -2519,7 +2518,7 @@ RenderScriptRuntime::DumpContexts(Stream &strm) const
strm.IndentLess();
}
-void
+void
RenderScriptRuntime::DumpKernels(Stream &strm) const
{
strm.Printf("RenderScript Kernels:");
diff --git a/source/Plugins/Makefile b/source/Plugins/Makefile
new file mode 100644
index 000000000000..931f459a26b7
--- /dev/null
+++ b/source/Plugins/Makefile
@@ -0,0 +1,67 @@
+##===- source/Plugins/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+
+include $(LLDB_LEVEL)/../../Makefile.config
+
+
+PARALLEL_DIRS := ABI/MacOSX-arm ABI/MacOSX-arm64 ABI/MacOSX-i386 ABI/SysV-i386 ABI/SysV-x86_64 \
+ ABI/SysV-arm ABI/SysV-arm64 ABI/SysV-hexagon ABI/SysV-ppc ABI/SysV-ppc64 \
+ ABI/SysV-mips ABI/SysV-mips64 Disassembler/llvm \
+ ObjectContainer/BSD-Archive ObjectFile/ELF ObjectFile/PECOFF \
+ ObjectContainer/Universal-Mach-O ObjectFile/Mach-O \
+ ObjectFile/JIT SymbolFile/DWARF SymbolFile/Symtab Process/Utility \
+ DynamicLoader/Static Platform Process/elf-core Process/gdb-remote \
+ Instruction/ARM Instruction/ARM64 Instruction/MIPS Instruction/MIPS64 \
+ UnwindAssembly/InstEmulation UnwindAssembly/x86 \
+ LanguageRuntime/CPlusPlus/ItaniumABI \
+ LanguageRuntime/ObjC/AppleObjCRuntime \
+ LanguageRuntime/Go/ \
+ LanguageRuntime/RenderScript/RenderScriptRuntime \
+ Language/CPlusPlus \
+ Language/Go \
+ Language/ObjC \
+ Language/ObjCPlusPlus \
+ DynamicLoader/POSIX-DYLD \
+ DynamicLoader/Hexagon-DYLD \
+ DynamicLoader/MacOSX-DYLD \
+ DynamicLoader/Windows-DYLD \
+ JITLoader/GDB \
+ ExpressionParser/Clang \
+ ExpressionParser/Go \
+ OperatingSystem/Go \
+ OperatingSystem/Python \
+ SystemRuntime/MacOSX \
+ SymbolVendor/ELF \
+ MemoryHistory/asan \
+ InstrumentationRuntime/AddressSanitizer \
+ ScriptInterpreter/Python ScriptInterpreter/None
+
+ifeq ($(HOST_OS),Darwin)
+PARALLEL_DIRS += Process/MacOSX-Kernel
+PARALLEL_DIRS += DynamicLoader/Darwin-Kernel
+PARALLEL_DIRS += SymbolVendor/MacOSX
+#PARALLEL_DIRS += Process/MacOSX-User
+PARALLEL_DIRS += Process/mach-core
+endif
+
+ifeq ($(HOST_OS),Linux)
+PARALLEL_DIRS += Process/Linux Process/POSIX
+endif
+
+ifneq (,$(filter $(HOST_OS), FreeBSD GNU/kFreeBSD))
+PARALLEL_DIRS += Process/FreeBSD Process/POSIX
+endif
+
+ifeq ($(HOST_OS),NetBSD)
+PARALLEL_DIRS += Process/POSIX
+endif
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/MemoryHistory/CMakeLists.txt b/source/Plugins/MemoryHistory/CMakeLists.txt
new file mode 100644
index 000000000000..113f06362578
--- /dev/null
+++ b/source/Plugins/MemoryHistory/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(asan)
diff --git a/source/Plugins/MemoryHistory/asan/CMakeLists.txt b/source/Plugins/MemoryHistory/asan/CMakeLists.txt
new file mode 100644
index 000000000000..8bfe95e3680e
--- /dev/null
+++ b/source/Plugins/MemoryHistory/asan/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginMemoryHistoryASan
+ MemoryHistoryASan.cpp
+ )
diff --git a/source/Plugins/MemoryHistory/asan/Makefile b/source/Plugins/MemoryHistory/asan/Makefile
new file mode 100644
index 000000000000..86de6aba3638
--- /dev/null
+++ b/source/Plugins/MemoryHistory/asan/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/MemoryHistory/asan/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginMemoryHistoryASan
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/CMakeLists.txt b/source/Plugins/ObjectContainer/BSD-Archive/CMakeLists.txt
new file mode 100644
index 000000000000..68ebe885e3e9
--- /dev/null
+++ b/source/Plugins/ObjectContainer/BSD-Archive/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginObjectContainerBSDArchive
+ ObjectContainerBSDArchive.cpp
+ )
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/Makefile b/source/Plugins/ObjectContainer/BSD-Archive/Makefile
new file mode 100644
index 000000000000..00c5911ea95f
--- /dev/null
+++ b/source/Plugins/ObjectContainer/BSD-Archive/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ObjectContainer/BSD-Archive/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginObjectContainerBSDArchive
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ObjectContainer/CMakeLists.txt b/source/Plugins/ObjectContainer/CMakeLists.txt
new file mode 100644
index 000000000000..5dcef91f07d2
--- /dev/null
+++ b/source/Plugins/ObjectContainer/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(BSD-Archive)
+add_subdirectory(Universal-Mach-O)
diff --git a/source/Plugins/ObjectContainer/Universal-Mach-O/CMakeLists.txt b/source/Plugins/ObjectContainer/Universal-Mach-O/CMakeLists.txt
new file mode 100644
index 000000000000..b4553868bf94
--- /dev/null
+++ b/source/Plugins/ObjectContainer/Universal-Mach-O/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginObjectContainerMachOArchive
+ ObjectContainerUniversalMachO.cpp
+ )
diff --git a/source/Plugins/ObjectContainer/Universal-Mach-O/Makefile b/source/Plugins/ObjectContainer/Universal-Mach-O/Makefile
new file mode 100644
index 000000000000..957753527d24
--- /dev/null
+++ b/source/Plugins/ObjectContainer/Universal-Mach-O/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ObjectContainer/Universal-Mach-O/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginObjectContainerMachOArchive
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
new file mode 100644
index 000000000000..7497b987eba4
--- /dev/null
+++ b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
@@ -0,0 +1,310 @@
+//===-- ObjectContainerUniversalMachO.cpp -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectContainerUniversalMachO.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm::MachO;
+
+void
+ObjectContainerUniversalMachO::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ GetModuleSpecifications);
+}
+
+void
+ObjectContainerUniversalMachO::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+ObjectContainerUniversalMachO::GetPluginNameStatic()
+{
+ static ConstString g_name("mach-o");
+ return g_name;
+}
+
+const char *
+ObjectContainerUniversalMachO::GetPluginDescriptionStatic()
+{
+ return "Universal mach-o object container reader.";
+}
+
+
+ObjectContainer *
+ObjectContainerUniversalMachO::CreateInstance
+(
+ const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const FileSpec *file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length
+)
+{
+ // We get data when we aren't trying to look for cached container information,
+ // so only try and look for an architecture slice if we get data
+ if (data_sp)
+ {
+ DataExtractor data;
+ data.SetData (data_sp, data_offset, length);
+ if (ObjectContainerUniversalMachO::MagicBytesMatch(data))
+ {
+ std::unique_ptr<ObjectContainerUniversalMachO> container_ap(new ObjectContainerUniversalMachO (module_sp, data_sp, data_offset, file, file_offset, length));
+ if (container_ap->ParseHeader())
+ {
+ return container_ap.release();
+ }
+ }
+ }
+ return NULL;
+}
+
+bool
+ObjectContainerUniversalMachO::MagicBytesMatch (const DataExtractor &data)
+{
+ lldb::offset_t offset = 0;
+ uint32_t magic = data.GetU32(&offset);
+ return magic == FAT_MAGIC || magic == FAT_CIGAM;
+}
+
+ObjectContainerUniversalMachO::ObjectContainerUniversalMachO
+(
+ const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const FileSpec *file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length
+) :
+ ObjectContainer (module_sp, file, file_offset, length, data_sp, data_offset),
+ m_header(),
+ m_fat_archs()
+{
+ memset(&m_header, 0, sizeof(m_header));
+}
+
+
+ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO()
+{
+}
+
+bool
+ObjectContainerUniversalMachO::ParseHeader ()
+{
+ bool success = ParseHeader (m_data, m_header, m_fat_archs);
+ // We no longer need any data, we parsed all we needed to parse
+ // and cached it in m_header and m_fat_archs
+ m_data.Clear();
+ return success;
+}
+
+bool
+ObjectContainerUniversalMachO::ParseHeader (lldb_private::DataExtractor &data,
+ llvm::MachO::fat_header &header,
+ std::vector<llvm::MachO::fat_arch> &fat_archs)
+{
+ bool success = false;
+ // Store the file offset for this universal file as we could have a universal .o file
+ // in a BSD archive, or be contained in another kind of object.
+ // Universal mach-o files always have their headers in big endian.
+ lldb::offset_t offset = 0;
+ data.SetByteOrder (eByteOrderBig);
+ header.magic = data.GetU32(&offset);
+ fat_archs.clear();
+
+ if (header.magic == FAT_MAGIC)
+ {
+
+ data.SetAddressByteSize(4);
+
+ header.nfat_arch = data.GetU32(&offset);
+
+ // Now we should have enough data for all of the fat headers, so lets index
+ // them so we know how many architectures that this universal binary contains.
+ uint32_t arch_idx = 0;
+ for (arch_idx = 0; arch_idx < header.nfat_arch; ++arch_idx)
+ {
+ if (data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch)))
+ {
+ fat_arch arch;
+ if (data.GetU32(&offset, &arch, sizeof(fat_arch)/sizeof(uint32_t)))
+ fat_archs.push_back(arch);
+ }
+ }
+ success = true;
+ }
+ else
+ {
+ memset(&header, 0, sizeof(header));
+ }
+ return success;
+}
+
+void
+ObjectContainerUniversalMachO::Dump (Stream *s) const
+{
+ s->Printf("%p: ", static_cast<const void*>(this));
+ s->Indent();
+ const size_t num_archs = GetNumArchitectures();
+ const size_t num_objects = GetNumObjects();
+ s->Printf("ObjectContainerUniversalMachO, num_archs = %lu, num_objects = %lu", num_archs, num_objects);
+ uint32_t i;
+ ArchSpec arch;
+ s->IndentMore();
+ for (i=0; i<num_archs; i++)
+ {
+ s->Indent();
+ GetArchitectureAtIndex(i, arch);
+ s->Printf("arch[%u] = %s\n", i, arch.GetArchitectureName());
+ }
+ for (i=0; i<num_objects; i++)
+ {
+ s->Indent();
+ s->Printf("object[%u] = %s\n", i, GetObjectNameAtIndex (i));
+ }
+ s->IndentLess();
+ s->EOL();
+}
+
+size_t
+ObjectContainerUniversalMachO::GetNumArchitectures () const
+{
+ return m_header.nfat_arch;
+}
+
+bool
+ObjectContainerUniversalMachO::GetArchitectureAtIndex (uint32_t idx, ArchSpec& arch) const
+{
+ if (idx < m_header.nfat_arch)
+ {
+ arch.SetArchitecture (eArchTypeMachO, m_fat_archs[idx].cputype, m_fat_archs[idx].cpusubtype);
+ return true;
+ }
+ return false;
+}
+
+ObjectFileSP
+ObjectContainerUniversalMachO::GetObjectFile (const FileSpec *file)
+{
+ uint32_t arch_idx = 0;
+ ArchSpec arch;
+ // If the module hasn't specified an architecture yet, set it to the default
+ // architecture:
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ if (!module_sp->GetArchitecture().IsValid())
+ {
+ arch = Target::GetDefaultArchitecture ();
+ if (!arch.IsValid())
+ arch.SetTriple (LLDB_ARCH_DEFAULT);
+ }
+ else
+ arch = module_sp->GetArchitecture();
+
+ ArchSpec curr_arch;
+ // First, try to find an exact match for the Arch of the Target.
+ for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
+ {
+ if (GetArchitectureAtIndex (arch_idx, curr_arch) && arch.IsExactMatch(curr_arch))
+ break;
+ }
+
+ // Failing an exact match, try to find a compatible Arch of the Target.
+ if (arch_idx >= m_header.nfat_arch)
+ {
+ for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
+ {
+ if (GetArchitectureAtIndex (arch_idx, curr_arch) && arch.IsCompatibleMatch(curr_arch))
+ break;
+ }
+ }
+
+ if (arch_idx < m_header.nfat_arch)
+ {
+ DataBufferSP data_sp;
+ lldb::offset_t data_offset = 0;
+ return ObjectFile::FindPlugin (module_sp,
+ file,
+ m_offset + m_fat_archs[arch_idx].offset,
+ m_fat_archs[arch_idx].size,
+ data_sp,
+ data_offset);
+ }
+ }
+ return ObjectFileSP();
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ObjectContainerUniversalMachO::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectContainerUniversalMachO::GetPluginVersion()
+{
+ return 1;
+}
+
+
+size_t
+ObjectContainerUniversalMachO::GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ lldb_private::ModuleSpecList &specs)
+{
+ const size_t initial_count = specs.GetSize();
+
+ DataExtractor data;
+ data.SetData (data_sp, data_offset, data_sp->GetByteSize());
+
+ if (ObjectContainerUniversalMachO::MagicBytesMatch(data))
+ {
+ llvm::MachO::fat_header header;
+ std::vector<llvm::MachO::fat_arch> fat_archs;
+ if (ParseHeader (data, header, fat_archs))
+ {
+ for (const llvm::MachO::fat_arch &fat_arch : fat_archs)
+ {
+ const lldb::offset_t slice_file_offset = fat_arch.offset + file_offset;
+ if (fat_arch.offset < file_size && file_size > slice_file_offset)
+ {
+ ObjectFile::GetModuleSpecifications (file,
+ slice_file_offset,
+ file_size - slice_file_offset,
+ specs);
+ }
+ }
+ }
+ }
+ return specs.GetSize() - initial_count;
+}
+
diff --git a/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
new file mode 100644
index 000000000000..162402e4b2ba
--- /dev/null
+++ b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
@@ -0,0 +1,105 @@
+//===-- ObjectContainerUniversalMachO.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_ObjectContainerUniversalMachO_h_
+#define liblldb_ObjectContainerUniversalMachO_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Symbol/ObjectContainer.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/SafeMachO.h"
+
+class ObjectContainerUniversalMachO :
+ public lldb_private::ObjectContainer
+{
+public:
+ ObjectContainerUniversalMachO(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec *file,
+ lldb::offset_t offset,
+ lldb::offset_t length);
+
+ ~ObjectContainerUniversalMachO() override;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectContainer *
+ CreateInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec *file,
+ lldb::offset_t offset,
+ lldb::offset_t length);
+
+ static size_t
+ GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs);
+
+ static bool
+ MagicBytesMatch (const lldb_private::DataExtractor &data);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ bool
+ ParseHeader() override;
+
+ void
+ Dump(lldb_private::Stream *s) const override;
+
+ size_t
+ GetNumArchitectures() const override;
+
+ bool
+ GetArchitectureAtIndex(uint32_t cpu_idx, lldb_private::ArchSpec& arch) const override;
+
+ lldb::ObjectFileSP
+ GetObjectFile(const lldb_private::FileSpec *file) override;
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+protected:
+ llvm::MachO::fat_header m_header;
+ std::vector<llvm::MachO::fat_arch> m_fat_archs;
+
+ static bool
+ ParseHeader (lldb_private::DataExtractor &data,
+ llvm::MachO::fat_header &header,
+ std::vector<llvm::MachO::fat_arch> &fat_archs);
+};
+
+#endif // liblldb_ObjectContainerUniversalMachO_h_
diff --git a/source/Plugins/ObjectFile/CMakeLists.txt b/source/Plugins/ObjectFile/CMakeLists.txt
new file mode 100644
index 000000000000..06aa01c4f004
--- /dev/null
+++ b/source/Plugins/ObjectFile/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_subdirectory(ELF)
+add_subdirectory(Mach-O)
+add_subdirectory(PECOFF)
+add_subdirectory(JIT) \ No newline at end of file
diff --git a/source/Plugins/ObjectFile/ELF/CMakeLists.txt b/source/Plugins/ObjectFile/ELF/CMakeLists.txt
new file mode 100644
index 000000000000..69ec80c62bf0
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_lldb_library(lldbPluginObjectFileELF
+ ELFHeader.cpp
+ ObjectFileELF.cpp
+ )
diff --git a/source/Plugins/ObjectFile/ELF/Makefile b/source/Plugins/ObjectFile/ELF/Makefile
new file mode 100644
index 000000000000..470660bb7861
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ObjectFile/ELF/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginObjectFileELF
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 44fe6615a361..1d63ced787e0 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -119,7 +119,7 @@ public:
///
/// @param type Either DT_REL or DT_RELA. Any other value is invalid.
ELFRelocation(unsigned type);
-
+
~ELFRelocation();
bool
@@ -156,7 +156,7 @@ private:
};
ELFRelocation::ELFRelocation(unsigned type)
-{
+{
if (type == DT_REL || type == SHT_REL)
reloc = new ELFRel();
else if (type == DT_RELA || type == SHT_RELA)
@@ -172,7 +172,7 @@ ELFRelocation::~ELFRelocation()
if (reloc.is<ELFRel*>())
delete reloc.get<ELFRel*>();
else
- delete reloc.get<ELFRela*>();
+ delete reloc.get<ELFRela*>();
}
bool
@@ -315,7 +315,7 @@ kalimbaVariantFromElfFlags(const elf::elf_word e_flags)
kal_arch_variant = llvm::Triple::KalimbaSubArch_v5;
break;
default:
- break;
+ break;
}
return kal_arch_variant;
}
@@ -470,9 +470,9 @@ ObjectFileELF::CreateInstance (const lldb::ModuleSP &module_sp,
ObjectFile*
-ObjectFileELF::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
- DataBufferSP& data_sp,
- const lldb::ProcessSP &process_sp,
+ObjectFileELF::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
lldb::addr_t header_addr)
{
if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT))
@@ -561,7 +561,7 @@ calc_crc32(uint32_t crc, const void *buf, size_t size)
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
- };
+ };
const uint8_t *p = (const uint8_t *)buf;
crc = crc ^ ~0U;
@@ -826,12 +826,12 @@ ObjectFileELF::GetPluginVersion()
// ObjectFile protocol
//------------------------------------------------------------------
-ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp,
+ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp,
DataBufferSP& data_sp,
lldb::offset_t data_offset,
- const FileSpec* file,
+ const FileSpec* file,
lldb::offset_t file_offset,
- lldb::offset_t length) :
+ lldb::offset_t length) :
ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
m_header(),
m_uuid(),
@@ -901,7 +901,7 @@ ObjectFileELF::SetLoadAddress (Target &target,
if (header->p_type != PT_LOAD || header->p_offset != 0)
continue;
-
+
value = value - header->p_vaddr;
found_offset = true;
break;
@@ -1176,7 +1176,7 @@ ObjectFileELF::GetImageInfoAddress(Target *target)
}
lldb_private::Address
-ObjectFileELF::GetEntryPointAddress ()
+ObjectFileELF::GetEntryPointAddress ()
{
if (m_entry_point_address.IsValid())
return m_entry_point_address;
@@ -1187,7 +1187,7 @@ ObjectFileELF::GetEntryPointAddress ()
SectionList *section_list = GetSectionList();
addr_t offset = m_header.e_entry;
- if (!section_list)
+ if (!section_list)
m_entry_point_address.SetOffset(offset);
else
m_entry_point_address.ResolveAddressUsingFileSections(offset, section_list);
@@ -1545,16 +1545,16 @@ ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
{
switch (header.e_flags & llvm::ELF::EF_MIPS_ARCH_ASE)
{
- case llvm::ELF::EF_MIPS_MICROMIPS:
- arch_spec.SetFlags (ArchSpec::eMIPSAse_micromips);
+ case llvm::ELF::EF_MIPS_MICROMIPS:
+ arch_spec.SetFlags (ArchSpec::eMIPSAse_micromips);
break;
- case llvm::ELF::EF_MIPS_ARCH_ASE_M16:
- arch_spec.SetFlags (ArchSpec::eMIPSAse_mips16);
+ case llvm::ELF::EF_MIPS_ARCH_ASE_M16:
+ arch_spec.SetFlags (ArchSpec::eMIPSAse_mips16);
break;
- case llvm::ELF::EF_MIPS_ARCH_ASE_MDMX:
- arch_spec.SetFlags (ArchSpec::eMIPSAse_mdmx);
+ case llvm::ELF::EF_MIPS_ARCH_ASE_MDMX:
+ arch_spec.SetFlags (ArchSpec::eMIPSAse_mdmx);
break;
- default:
+ default:
break;
}
}
@@ -1612,7 +1612,7 @@ ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
DataExtractor data;
if (sheader.sh_type == SHT_MIPS_ABIFLAGS)
{
-
+
if (section_size && (data.SetData (object_data, sheader.sh_offset, section_size) == section_size))
{
lldb::offset_t ase_offset = 12; // MIPS ABI Flags Version: 0
@@ -1621,12 +1621,12 @@ ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
}
// Settings appropriate ArchSpec ABI Flags
if (header.e_flags & llvm::ELF::EF_MIPS_ABI2)
- {
+ {
arch_flags |= lldb_private::ArchSpec::eMIPSABI_N32;
}
else if (header.e_flags & llvm::ELF::EF_MIPS_ABI_O32)
{
- arch_flags |= lldb_private::ArchSpec::eMIPSABI_O32;
+ arch_flags |= lldb_private::ArchSpec::eMIPSABI_O32;
}
arch_spec.SetFlags (arch_flags);
}
@@ -1700,7 +1700,7 @@ ObjectFileELF::GetProgramHeaderByIndex(lldb::user_id_t id)
return NULL;
}
-DataExtractor
+DataExtractor
ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id)
{
const elf::ELFProgramHeader *segment_header = GetProgramHeaderByIndex(id);
@@ -1805,12 +1805,12 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list)
else if (name == g_sect_name_tdata)
{
sect_type = eSectionTypeData;
- is_thread_specific = true;
+ is_thread_specific = true;
}
else if (name == g_sect_name_tbss)
{
- sect_type = eSectionTypeZeroFill;
- is_thread_specific = true;
+ sect_type = eSectionTypeZeroFill;
+ is_thread_specific = true;
}
// .debug_abbrev – Abbreviations used in the .debug_info section
// .debug_aranges – Lookup table for mapping addresses to compilation units
@@ -1877,12 +1877,12 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list)
{
// the kalimba toolchain assumes that ELF section names are free-form. It does
// support linkscripts which (can) give rise to various arbitrarily named
- // sections being "Code" or "Data".
+ // sections being "Code" or "Data".
sect_type = kalimbaSectionType(m_header, header);
}
const uint32_t target_bytes_size =
- (eSectionTypeData == sect_type || eSectionTypeZeroFill == sect_type) ?
+ (eSectionTypeData == sect_type || eSectionTypeZeroFill == sect_type) ?
m_arch_spec.GetDataByteSize() :
eSectionTypeCode == sect_type ?
m_arch_spec.GetCodeByteSize() : 1;
@@ -2022,7 +2022,7 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
{
if (symbol.Parse(symtab_data, &offset) == false)
break;
-
+
const char *symbol_name = strtab_data.PeekCStr(symbol.st_name);
// No need to add non-section symbols that have no names
@@ -2325,7 +2325,7 @@ ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, user_id_t start_id, lldb_p
user_id_t symtab_id = symtab->GetID();
const ELFSectionHeaderInfo *symtab_hdr = GetSectionHeaderByIndex(symtab_id);
- assert(symtab_hdr->sh_type == SHT_SYMTAB ||
+ assert(symtab_hdr->sh_type == SHT_SYMTAB ||
symtab_hdr->sh_type == SHT_DYNSYM);
// sh_link: section header index of associated string table.
@@ -2601,16 +2601,16 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table,
if (!rel_type)
return 0;
- return ParsePLTRelocations (symbol_table,
- start_id,
+ return ParsePLTRelocations (symbol_table,
+ start_id,
rel_type,
- &m_header,
- rel_hdr,
- plt_hdr,
+ &m_header,
+ rel_hdr,
+ plt_hdr,
sym_hdr,
- plt_section_sp,
- rel_data,
- symtab_data,
+ plt_section_sp,
+ rel_data,
+ symtab_data,
strtab_data);
}
@@ -2797,24 +2797,24 @@ ObjectFileELF::GetSymtab()
// Synthesize trampoline symbols to help navigate the PLT.
addr_t addr = symbol->d_ptr;
Section *reloc_section = section_list->FindSectionContainingFileAddress(addr).get();
- if (reloc_section)
+ if (reloc_section)
{
user_id_t reloc_id = reloc_section->GetID();
const ELFSectionHeaderInfo *reloc_header = GetSectionHeaderByIndex(reloc_id);
assert(reloc_header);
-
+
if (m_symtab_ap == nullptr)
m_symtab_ap.reset(new Symtab(reloc_section->GetObjectFile()));
ParseTrampolineSymbols (m_symtab_ap.get(), symbol_id, reloc_header, reloc_id);
}
}
-
+
// If we still don't have any symtab then create an empty instance to avoid do the section
// lookup next time.
if (m_symtab_ap == nullptr)
m_symtab_ap.reset(new Symtab(this));
-
+
m_symtab_ap->CalculateSymbolSizes();
}
@@ -3274,7 +3274,7 @@ ObjectFileELF::CalculateStrata()
{
switch (m_header.e_type)
{
- case llvm::ELF::ET_NONE:
+ case llvm::ELF::ET_NONE:
// 0 - No file type
return eStrataUnknown;
@@ -3285,21 +3285,21 @@ ObjectFileELF::CalculateStrata()
case llvm::ELF::ET_EXEC:
// 2 - Executable file
// TODO: is there any way to detect that an executable is a kernel
- // related executable by inspecting the program headers, section
+ // related executable by inspecting the program headers, section
// headers, symbols, or any other flag bits???
return eStrataUser;
case llvm::ELF::ET_DYN:
// 3 - Shared object file
// TODO: is there any way to detect that an shared library is a kernel
- // related executable by inspecting the program headers, section
+ // related executable by inspecting the program headers, section
// headers, symbols, or any other flag bits???
return eStrataUnknown;
case ET_CORE:
// 4 - Core file
// TODO: is there any way to detect that an core file is a kernel
- // related executable by inspecting the program headers, section
+ // related executable by inspecting the program headers, section
// headers, symbols, or any other flag bits???
return eStrataUnknown;
diff --git a/source/Plugins/ObjectFile/JIT/CMakeLists.txt b/source/Plugins/ObjectFile/JIT/CMakeLists.txt
new file mode 100644
index 000000000000..979724bac5ad
--- /dev/null
+++ b/source/Plugins/ObjectFile/JIT/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginObjectFileJIT
+ ObjectFileJIT.cpp
+ )
diff --git a/source/Plugins/ObjectFile/JIT/Makefile b/source/Plugins/ObjectFile/JIT/Makefile
new file mode 100644
index 000000000000..2af3521777a1
--- /dev/null
+++ b/source/Plugins/ObjectFile/JIT/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ObjectFile/JIT/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginObjectFileJIT
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ObjectFile/Mach-O/CMakeLists.txt b/source/Plugins/ObjectFile/Mach-O/CMakeLists.txt
new file mode 100644
index 000000000000..45d45860b9e5
--- /dev/null
+++ b/source/Plugins/ObjectFile/Mach-O/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginObjectFileMachO
+ ObjectFileMachO.cpp
+ )
diff --git a/source/Plugins/ObjectFile/Mach-O/Makefile b/source/Plugins/ObjectFile/Mach-O/Makefile
new file mode 100644
index 000000000000..2fab0238e411
--- /dev/null
+++ b/source/Plugins/ObjectFile/Mach-O/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ObjectFile/Mach-O/Makefile -----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginObjectFileMachO
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
new file mode 100644
index 000000000000..9c1e17782508
--- /dev/null
+++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -0,0 +1,6096 @@
+//===-- ObjectFileMachO.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/ADT/StringRef.h"
+
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadList.h"
+#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h"
+#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h"
+#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
+#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
+
+#include "lldb/Utility/SafeMachO.h"
+
+#include "ObjectFileMachO.h"
+
+#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__))
+// GetLLDBSharedCacheUUID() needs to call dlsym()
+#include <dlfcn.h>
+#endif
+
+#ifndef __APPLE__
+#include "Utility/UuidCompatibility.h"
+#endif
+
+#define THUMB_ADDRESS_BIT_MASK 0xfffffffffffffffeull
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm::MachO;
+
+// Some structure definitions needed for parsing the dyld shared cache files
+// found on iOS devices.
+
+struct lldb_copy_dyld_cache_header_v1
+{
+ char magic[16]; // e.g. "dyld_v0 i386", "dyld_v1 armv7", etc.
+ uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info
+ uint32_t mappingCount; // number of dyld_cache_mapping_info entries
+ uint32_t imagesOffset;
+ uint32_t imagesCount;
+ uint64_t dyldBaseAddress;
+ uint64_t codeSignatureOffset;
+ uint64_t codeSignatureSize;
+ uint64_t slideInfoOffset;
+ uint64_t slideInfoSize;
+ uint64_t localSymbolsOffset;
+ uint64_t localSymbolsSize;
+ uint8_t uuid[16]; // v1 and above, also recorded in dyld_all_image_infos v13 and later
+};
+
+struct lldb_copy_dyld_cache_mapping_info
+{
+ uint64_t address;
+ uint64_t size;
+ uint64_t fileOffset;
+ uint32_t maxProt;
+ uint32_t initProt;
+};
+
+struct lldb_copy_dyld_cache_local_symbols_info
+{
+ uint32_t nlistOffset;
+ uint32_t nlistCount;
+ uint32_t stringsOffset;
+ uint32_t stringsSize;
+ uint32_t entriesOffset;
+ uint32_t entriesCount;
+};
+struct lldb_copy_dyld_cache_local_symbols_entry
+{
+ uint32_t dylibOffset;
+ uint32_t nlistStartIndex;
+ uint32_t nlistCount;
+};
+
+
+class RegisterContextDarwin_x86_64_Mach : public RegisterContextDarwin_x86_64
+{
+public:
+ RegisterContextDarwin_x86_64_Mach (lldb_private::Thread &thread, const DataExtractor &data) :
+ RegisterContextDarwin_x86_64 (thread, 0)
+ {
+ SetRegisterDataFrom_LC_THREAD (data);
+ }
+
+ void
+ InvalidateAllRegisters() override
+ {
+ // Do nothing... registers are always valid...
+ }
+
+ void
+ SetRegisterDataFrom_LC_THREAD (const DataExtractor &data)
+ {
+ lldb::offset_t offset = 0;
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ bool done = false;
+
+ while (!done)
+ {
+ int flavor = data.GetU32 (&offset);
+ if (flavor == 0)
+ done = true;
+ else
+ {
+ uint32_t i;
+ uint32_t count = data.GetU32 (&offset);
+ switch (flavor)
+ {
+ case GPRRegSet:
+ for (i=0; i<count; ++i)
+ (&gpr.rax)[i] = data.GetU64(&offset);
+ SetError (GPRRegSet, Read, 0);
+ done = true;
+
+ break;
+ case FPURegSet:
+ // TODO: fill in FPU regs....
+ //SetError (FPURegSet, Read, -1);
+ done = true;
+
+ break;
+ case EXCRegSet:
+ exc.trapno = data.GetU32(&offset);
+ exc.err = data.GetU32(&offset);
+ exc.faultvaddr = data.GetU64(&offset);
+ SetError (EXCRegSet, Read, 0);
+ done = true;
+ break;
+ case 7:
+ case 8:
+ case 9:
+ // fancy flavors that encapsulate of the above
+ // flavors...
+ break;
+
+ default:
+ done = true;
+ break;
+ }
+ }
+ }
+ }
+
+ static size_t
+ WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data)
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
+ if (reg_info == NULL)
+ reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
+ if (reg_info)
+ {
+ lldb_private::RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(reg_info, reg_value))
+ {
+ if (reg_info->byte_size >= reg_byte_size)
+ data.Write(reg_value.GetBytes(), reg_byte_size);
+ else
+ {
+ data.Write(reg_value.GetBytes(), reg_info->byte_size);
+ for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i)
+ data.PutChar(0);
+ }
+ return reg_byte_size;
+ }
+ }
+ // Just write zeros if all else fails
+ for (size_t i=0; i<reg_byte_size; ++ i)
+ data.PutChar(0);
+ return reg_byte_size;
+ }
+
+ static bool
+ Create_LC_THREAD (Thread *thread, Stream &data)
+ {
+ RegisterContextSP reg_ctx_sp (thread->GetRegisterContext());
+ if (reg_ctx_sp)
+ {
+ RegisterContext *reg_ctx = reg_ctx_sp.get();
+
+ data.PutHex32 (GPRRegSet); // Flavor
+ data.PutHex32 (GPRWordCount);
+ WriteRegister (reg_ctx, "rax", NULL, 8, data);
+ WriteRegister (reg_ctx, "rbx", NULL, 8, data);
+ WriteRegister (reg_ctx, "rcx", NULL, 8, data);
+ WriteRegister (reg_ctx, "rdx", NULL, 8, data);
+ WriteRegister (reg_ctx, "rdi", NULL, 8, data);
+ WriteRegister (reg_ctx, "rsi", NULL, 8, data);
+ WriteRegister (reg_ctx, "rbp", NULL, 8, data);
+ WriteRegister (reg_ctx, "rsp", NULL, 8, data);
+ WriteRegister (reg_ctx, "r8", NULL, 8, data);
+ WriteRegister (reg_ctx, "r9", NULL, 8, data);
+ WriteRegister (reg_ctx, "r10", NULL, 8, data);
+ WriteRegister (reg_ctx, "r11", NULL, 8, data);
+ WriteRegister (reg_ctx, "r12", NULL, 8, data);
+ WriteRegister (reg_ctx, "r13", NULL, 8, data);
+ WriteRegister (reg_ctx, "r14", NULL, 8, data);
+ WriteRegister (reg_ctx, "r15", NULL, 8, data);
+ WriteRegister (reg_ctx, "rip", NULL, 8, data);
+ WriteRegister (reg_ctx, "rflags", NULL, 8, data);
+ WriteRegister (reg_ctx, "cs", NULL, 8, data);
+ WriteRegister (reg_ctx, "fs", NULL, 8, data);
+ WriteRegister (reg_ctx, "gs", NULL, 8, data);
+
+// // Write out the FPU registers
+// const size_t fpu_byte_size = sizeof(FPU);
+// size_t bytes_written = 0;
+// data.PutHex32 (FPURegSet);
+// data.PutHex32 (fpu_byte_size/sizeof(uint64_t));
+// bytes_written += data.PutHex32(0); // uint32_t pad[0]
+// bytes_written += data.PutHex32(0); // uint32_t pad[1]
+// bytes_written += WriteRegister (reg_ctx, "fcw", "fctrl", 2, data); // uint16_t fcw; // "fctrl"
+// bytes_written += WriteRegister (reg_ctx, "fsw" , "fstat", 2, data); // uint16_t fsw; // "fstat"
+// bytes_written += WriteRegister (reg_ctx, "ftw" , "ftag", 1, data); // uint8_t ftw; // "ftag"
+// bytes_written += data.PutHex8 (0); // uint8_t pad1;
+// bytes_written += WriteRegister (reg_ctx, "fop" , NULL, 2, data); // uint16_t fop; // "fop"
+// bytes_written += WriteRegister (reg_ctx, "fioff", "ip", 4, data); // uint32_t ip; // "fioff"
+// bytes_written += WriteRegister (reg_ctx, "fiseg", NULL, 2, data); // uint16_t cs; // "fiseg"
+// bytes_written += data.PutHex16 (0); // uint16_t pad2;
+// bytes_written += WriteRegister (reg_ctx, "dp", "fooff" , 4, data); // uint32_t dp; // "fooff"
+// bytes_written += WriteRegister (reg_ctx, "foseg", NULL, 2, data); // uint16_t ds; // "foseg"
+// bytes_written += data.PutHex16 (0); // uint16_t pad3;
+// bytes_written += WriteRegister (reg_ctx, "mxcsr", NULL, 4, data); // uint32_t mxcsr;
+// bytes_written += WriteRegister (reg_ctx, "mxcsrmask", NULL, 4, data);// uint32_t mxcsrmask;
+// bytes_written += WriteRegister (reg_ctx, "stmm0", NULL, sizeof(MMSReg), data);
+// bytes_written += WriteRegister (reg_ctx, "stmm1", NULL, sizeof(MMSReg), data);
+// bytes_written += WriteRegister (reg_ctx, "stmm2", NULL, sizeof(MMSReg), data);
+// bytes_written += WriteRegister (reg_ctx, "stmm3", NULL, sizeof(MMSReg), data);
+// bytes_written += WriteRegister (reg_ctx, "stmm4", NULL, sizeof(MMSReg), data);
+// bytes_written += WriteRegister (reg_ctx, "stmm5", NULL, sizeof(MMSReg), data);
+// bytes_written += WriteRegister (reg_ctx, "stmm6", NULL, sizeof(MMSReg), data);
+// bytes_written += WriteRegister (reg_ctx, "stmm7", NULL, sizeof(MMSReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm0" , NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm1" , NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm2" , NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm3" , NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm4" , NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm5" , NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm6" , NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm7" , NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm8" , NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm9" , NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm10", NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm11", NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm12", NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm13", NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm14", NULL, sizeof(XMMReg), data);
+// bytes_written += WriteRegister (reg_ctx, "xmm15", NULL, sizeof(XMMReg), data);
+//
+// // Fill rest with zeros
+// for (size_t i=0, n = fpu_byte_size - bytes_written; i<n; ++ i)
+// data.PutChar(0);
+
+ // Write out the EXC registers
+ data.PutHex32 (EXCRegSet);
+ data.PutHex32 (EXCWordCount);
+ WriteRegister (reg_ctx, "trapno", NULL, 4, data);
+ WriteRegister (reg_ctx, "err", NULL, 4, data);
+ WriteRegister (reg_ctx, "faultvaddr", NULL, 8, data);
+ return true;
+ }
+ return false;
+ }
+
+protected:
+ int
+ DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override
+ {
+ return 0;
+ }
+
+ int
+ DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override
+ {
+ return 0;
+ }
+
+ int
+ DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override
+ {
+ return 0;
+ }
+};
+
+class RegisterContextDarwin_i386_Mach : public RegisterContextDarwin_i386
+{
+public:
+ RegisterContextDarwin_i386_Mach (lldb_private::Thread &thread, const DataExtractor &data) :
+ RegisterContextDarwin_i386 (thread, 0)
+ {
+ SetRegisterDataFrom_LC_THREAD (data);
+ }
+
+ void
+ InvalidateAllRegisters() override
+ {
+ // Do nothing... registers are always valid...
+ }
+
+ void
+ SetRegisterDataFrom_LC_THREAD (const DataExtractor &data)
+ {
+ lldb::offset_t offset = 0;
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ bool done = false;
+
+ while (!done)
+ {
+ int flavor = data.GetU32 (&offset);
+ if (flavor == 0)
+ done = true;
+ else
+ {
+ uint32_t i;
+ uint32_t count = data.GetU32 (&offset);
+ switch (flavor)
+ {
+ case GPRRegSet:
+ for (i=0; i<count; ++i)
+ (&gpr.eax)[i] = data.GetU32(&offset);
+ SetError (GPRRegSet, Read, 0);
+ done = true;
+
+ break;
+ case FPURegSet:
+ // TODO: fill in FPU regs....
+ //SetError (FPURegSet, Read, -1);
+ done = true;
+
+ break;
+ case EXCRegSet:
+ exc.trapno = data.GetU32(&offset);
+ exc.err = data.GetU32(&offset);
+ exc.faultvaddr = data.GetU32(&offset);
+ SetError (EXCRegSet, Read, 0);
+ done = true;
+ break;
+ case 7:
+ case 8:
+ case 9:
+ // fancy flavors that encapsulate of the above
+ // flavors...
+ break;
+
+ default:
+ done = true;
+ break;
+ }
+ }
+ }
+ }
+
+ static size_t
+ WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data)
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
+ if (reg_info == NULL)
+ reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
+ if (reg_info)
+ {
+ lldb_private::RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(reg_info, reg_value))
+ {
+ if (reg_info->byte_size >= reg_byte_size)
+ data.Write(reg_value.GetBytes(), reg_byte_size);
+ else
+ {
+ data.Write(reg_value.GetBytes(), reg_info->byte_size);
+ for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i)
+ data.PutChar(0);
+ }
+ return reg_byte_size;
+ }
+ }
+ // Just write zeros if all else fails
+ for (size_t i=0; i<reg_byte_size; ++ i)
+ data.PutChar(0);
+ return reg_byte_size;
+ }
+
+ static bool
+ Create_LC_THREAD (Thread *thread, Stream &data)
+ {
+ RegisterContextSP reg_ctx_sp (thread->GetRegisterContext());
+ if (reg_ctx_sp)
+ {
+ RegisterContext *reg_ctx = reg_ctx_sp.get();
+
+ data.PutHex32 (GPRRegSet); // Flavor
+ data.PutHex32 (GPRWordCount);
+ WriteRegister (reg_ctx, "eax", NULL, 4, data);
+ WriteRegister (reg_ctx, "ebx", NULL, 4, data);
+ WriteRegister (reg_ctx, "ecx", NULL, 4, data);
+ WriteRegister (reg_ctx, "edx", NULL, 4, data);
+ WriteRegister (reg_ctx, "edi", NULL, 4, data);
+ WriteRegister (reg_ctx, "esi", NULL, 4, data);
+ WriteRegister (reg_ctx, "ebp", NULL, 4, data);
+ WriteRegister (reg_ctx, "esp", NULL, 4, data);
+ WriteRegister (reg_ctx, "ss", NULL, 4, data);
+ WriteRegister (reg_ctx, "eflags", NULL, 4, data);
+ WriteRegister (reg_ctx, "eip", NULL, 4, data);
+ WriteRegister (reg_ctx, "cs", NULL, 4, data);
+ WriteRegister (reg_ctx, "ds", NULL, 4, data);
+ WriteRegister (reg_ctx, "es", NULL, 4, data);
+ WriteRegister (reg_ctx, "fs", NULL, 4, data);
+ WriteRegister (reg_ctx, "gs", NULL, 4, data);
+
+ // Write out the EXC registers
+ data.PutHex32 (EXCRegSet);
+ data.PutHex32 (EXCWordCount);
+ WriteRegister (reg_ctx, "trapno", NULL, 4, data);
+ WriteRegister (reg_ctx, "err", NULL, 4, data);
+ WriteRegister (reg_ctx, "faultvaddr", NULL, 4, data);
+ return true;
+ }
+ return false;
+ }
+
+protected:
+ int
+ DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override
+ {
+ return 0;
+ }
+
+ int
+ DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override
+ {
+ return 0;
+ }
+
+ int
+ DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override
+ {
+ return 0;
+ }
+};
+
+class RegisterContextDarwin_arm_Mach : public RegisterContextDarwin_arm
+{
+public:
+ RegisterContextDarwin_arm_Mach (lldb_private::Thread &thread, const DataExtractor &data) :
+ RegisterContextDarwin_arm (thread, 0)
+ {
+ SetRegisterDataFrom_LC_THREAD (data);
+ }
+
+ void
+ InvalidateAllRegisters() override
+ {
+ // Do nothing... registers are always valid...
+ }
+
+ void
+ SetRegisterDataFrom_LC_THREAD (const DataExtractor &data)
+ {
+ lldb::offset_t offset = 0;
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ bool done = false;
+
+ while (!done)
+ {
+ int flavor = data.GetU32 (&offset);
+ uint32_t count = data.GetU32 (&offset);
+ lldb::offset_t next_thread_state = offset + (count * 4);
+ switch (flavor)
+ {
+ case GPRRegSet:
+ for (uint32_t i=0; i<count; ++i)
+ {
+ gpr.r[i] = data.GetU32(&offset);
+ }
+
+ // Note that gpr.cpsr is also copied by the above loop; this loop technically extends
+ // one element past the end of the gpr.r[] array.
+
+ SetError (GPRRegSet, Read, 0);
+ offset = next_thread_state;
+ break;
+
+ case FPURegSet:
+ {
+ uint8_t *fpu_reg_buf = (uint8_t*) &fpu.floats.s[0];
+ const int fpu_reg_buf_size = sizeof (fpu.floats);
+ if (data.ExtractBytes (offset, fpu_reg_buf_size, eByteOrderLittle, fpu_reg_buf) == fpu_reg_buf_size)
+ {
+ offset += fpu_reg_buf_size;
+ fpu.fpscr = data.GetU32(&offset);
+ SetError (FPURegSet, Read, 0);
+ }
+ else
+ {
+ done = true;
+ }
+ }
+ offset = next_thread_state;
+ break;
+
+ case EXCRegSet:
+ if (count == 3)
+ {
+ exc.exception = data.GetU32(&offset);
+ exc.fsr = data.GetU32(&offset);
+ exc.far = data.GetU32(&offset);
+ SetError (EXCRegSet, Read, 0);
+ }
+ done = true;
+ offset = next_thread_state;
+ break;
+
+ // Unknown register set flavor, stop trying to parse.
+ default:
+ done = true;
+ }
+ }
+ }
+
+ static size_t
+ WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data)
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
+ if (reg_info == NULL)
+ reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
+ if (reg_info)
+ {
+ lldb_private::RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(reg_info, reg_value))
+ {
+ if (reg_info->byte_size >= reg_byte_size)
+ data.Write(reg_value.GetBytes(), reg_byte_size);
+ else
+ {
+ data.Write(reg_value.GetBytes(), reg_info->byte_size);
+ for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i)
+ data.PutChar(0);
+ }
+ return reg_byte_size;
+ }
+ }
+ // Just write zeros if all else fails
+ for (size_t i=0; i<reg_byte_size; ++ i)
+ data.PutChar(0);
+ return reg_byte_size;
+ }
+
+ static bool
+ Create_LC_THREAD (Thread *thread, Stream &data)
+ {
+ RegisterContextSP reg_ctx_sp (thread->GetRegisterContext());
+ if (reg_ctx_sp)
+ {
+ RegisterContext *reg_ctx = reg_ctx_sp.get();
+
+ data.PutHex32 (GPRRegSet); // Flavor
+ data.PutHex32 (GPRWordCount);
+ WriteRegister (reg_ctx, "r0", NULL, 4, data);
+ WriteRegister (reg_ctx, "r1", NULL, 4, data);
+ WriteRegister (reg_ctx, "r2", NULL, 4, data);
+ WriteRegister (reg_ctx, "r3", NULL, 4, data);
+ WriteRegister (reg_ctx, "r4", NULL, 4, data);
+ WriteRegister (reg_ctx, "r5", NULL, 4, data);
+ WriteRegister (reg_ctx, "r6", NULL, 4, data);
+ WriteRegister (reg_ctx, "r7", NULL, 4, data);
+ WriteRegister (reg_ctx, "r8", NULL, 4, data);
+ WriteRegister (reg_ctx, "r9", NULL, 4, data);
+ WriteRegister (reg_ctx, "r10", NULL, 4, data);
+ WriteRegister (reg_ctx, "r11", NULL, 4, data);
+ WriteRegister (reg_ctx, "r12", NULL, 4, data);
+ WriteRegister (reg_ctx, "sp", NULL, 4, data);
+ WriteRegister (reg_ctx, "lr", NULL, 4, data);
+ WriteRegister (reg_ctx, "pc", NULL, 4, data);
+ WriteRegister (reg_ctx, "cpsr", NULL, 4, data);
+
+ // Write out the EXC registers
+// data.PutHex32 (EXCRegSet);
+// data.PutHex32 (EXCWordCount);
+// WriteRegister (reg_ctx, "exception", NULL, 4, data);
+// WriteRegister (reg_ctx, "fsr", NULL, 4, data);
+// WriteRegister (reg_ctx, "far", NULL, 4, data);
+ return true;
+ }
+ return false;
+ }
+
+protected:
+ int
+ DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override
+ {
+ return -1;
+ }
+
+ int
+ DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override
+ {
+ return -1;
+ }
+
+ int
+ DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override
+ {
+ return -1;
+ }
+
+ int
+ DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override
+ {
+ return -1;
+ }
+
+ int
+ DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override
+ {
+ return -1;
+ }
+};
+
+class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64
+{
+public:
+ RegisterContextDarwin_arm64_Mach (lldb_private::Thread &thread, const DataExtractor &data) :
+ RegisterContextDarwin_arm64 (thread, 0)
+ {
+ SetRegisterDataFrom_LC_THREAD (data);
+ }
+
+ void
+ InvalidateAllRegisters() override
+ {
+ // Do nothing... registers are always valid...
+ }
+
+ void
+ SetRegisterDataFrom_LC_THREAD (const DataExtractor &data)
+ {
+ lldb::offset_t offset = 0;
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ bool done = false;
+ while (!done)
+ {
+ int flavor = data.GetU32 (&offset);
+ uint32_t count = data.GetU32 (&offset);
+ lldb::offset_t next_thread_state = offset + (count * 4);
+ switch (flavor)
+ {
+ case GPRRegSet:
+ // x0-x29 + fp + lr + sp + pc (== 33 64-bit registers) plus cpsr (1 32-bit register)
+ if (count >= (33 * 2) + 1)
+ {
+ for (uint32_t i=0; i<33; ++i)
+ gpr.x[i] = data.GetU64(&offset);
+ gpr.cpsr = data.GetU32(&offset);
+ SetError (GPRRegSet, Read, 0);
+ }
+ offset = next_thread_state;
+ break;
+ case FPURegSet:
+ {
+ uint8_t *fpu_reg_buf = (uint8_t*) &fpu.v[0];
+ const int fpu_reg_buf_size = sizeof (fpu);
+ if (fpu_reg_buf_size == count
+ && data.ExtractBytes (offset, fpu_reg_buf_size, eByteOrderLittle, fpu_reg_buf) == fpu_reg_buf_size)
+ {
+ SetError (FPURegSet, Read, 0);
+ }
+ else
+ {
+ done = true;
+ }
+ }
+ offset = next_thread_state;
+ break;
+ case EXCRegSet:
+ if (count == 4)
+ {
+ exc.far = data.GetU64(&offset);
+ exc.esr = data.GetU32(&offset);
+ exc.exception = data.GetU32(&offset);
+ SetError (EXCRegSet, Read, 0);
+ }
+ offset = next_thread_state;
+ break;
+ default:
+ done = true;
+ break;
+ }
+ }
+ }
+
+ static size_t
+ WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data)
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
+ if (reg_info == NULL)
+ reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
+ if (reg_info)
+ {
+ lldb_private::RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(reg_info, reg_value))
+ {
+ if (reg_info->byte_size >= reg_byte_size)
+ data.Write(reg_value.GetBytes(), reg_byte_size);
+ else
+ {
+ data.Write(reg_value.GetBytes(), reg_info->byte_size);
+ for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i)
+ data.PutChar(0);
+ }
+ return reg_byte_size;
+ }
+ }
+ // Just write zeros if all else fails
+ for (size_t i=0; i<reg_byte_size; ++ i)
+ data.PutChar(0);
+ return reg_byte_size;
+ }
+
+ static bool
+ Create_LC_THREAD (Thread *thread, Stream &data)
+ {
+ RegisterContextSP reg_ctx_sp (thread->GetRegisterContext());
+ if (reg_ctx_sp)
+ {
+ RegisterContext *reg_ctx = reg_ctx_sp.get();
+
+ data.PutHex32 (GPRRegSet); // Flavor
+ data.PutHex32 (GPRWordCount);
+ WriteRegister (reg_ctx, "x0", NULL, 8, data);
+ WriteRegister (reg_ctx, "x1", NULL, 8, data);
+ WriteRegister (reg_ctx, "x2", NULL, 8, data);
+ WriteRegister (reg_ctx, "x3", NULL, 8, data);
+ WriteRegister (reg_ctx, "x4", NULL, 8, data);
+ WriteRegister (reg_ctx, "x5", NULL, 8, data);
+ WriteRegister (reg_ctx, "x6", NULL, 8, data);
+ WriteRegister (reg_ctx, "x7", NULL, 8, data);
+ WriteRegister (reg_ctx, "x8", NULL, 8, data);
+ WriteRegister (reg_ctx, "x9", NULL, 8, data);
+ WriteRegister (reg_ctx, "x10", NULL, 8, data);
+ WriteRegister (reg_ctx, "x11", NULL, 8, data);
+ WriteRegister (reg_ctx, "x12", NULL, 8, data);
+ WriteRegister (reg_ctx, "x13", NULL, 8, data);
+ WriteRegister (reg_ctx, "x14", NULL, 8, data);
+ WriteRegister (reg_ctx, "x15", NULL, 8, data);
+ WriteRegister (reg_ctx, "x16", NULL, 8, data);
+ WriteRegister (reg_ctx, "x17", NULL, 8, data);
+ WriteRegister (reg_ctx, "x18", NULL, 8, data);
+ WriteRegister (reg_ctx, "x19", NULL, 8, data);
+ WriteRegister (reg_ctx, "x20", NULL, 8, data);
+ WriteRegister (reg_ctx, "x21", NULL, 8, data);
+ WriteRegister (reg_ctx, "x22", NULL, 8, data);
+ WriteRegister (reg_ctx, "x23", NULL, 8, data);
+ WriteRegister (reg_ctx, "x24", NULL, 8, data);
+ WriteRegister (reg_ctx, "x25", NULL, 8, data);
+ WriteRegister (reg_ctx, "x26", NULL, 8, data);
+ WriteRegister (reg_ctx, "x27", NULL, 8, data);
+ WriteRegister (reg_ctx, "x28", NULL, 8, data);
+ WriteRegister (reg_ctx, "fp", NULL, 8, data);
+ WriteRegister (reg_ctx, "lr", NULL, 8, data);
+ WriteRegister (reg_ctx, "sp", NULL, 8, data);
+ WriteRegister (reg_ctx, "pc", NULL, 8, data);
+ WriteRegister (reg_ctx, "cpsr", NULL, 4, data);
+
+ // Write out the EXC registers
+// data.PutHex32 (EXCRegSet);
+// data.PutHex32 (EXCWordCount);
+// WriteRegister (reg_ctx, "far", NULL, 8, data);
+// WriteRegister (reg_ctx, "esr", NULL, 4, data);
+// WriteRegister (reg_ctx, "exception", NULL, 4, data);
+ return true;
+ }
+ return false;
+ }
+
+protected:
+ int
+ DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override
+ {
+ return -1;
+ }
+
+ int
+ DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override
+ {
+ return -1;
+ }
+
+ int
+ DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override
+ {
+ return -1;
+ }
+
+ int
+ DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override
+ {
+ return -1;
+ }
+
+ int
+ DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override
+ {
+ return 0;
+ }
+
+ int
+ DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override
+ {
+ return -1;
+ }
+};
+
+static uint32_t
+MachHeaderSizeFromMagic(uint32_t magic)
+{
+ switch (magic)
+ {
+ case MH_MAGIC:
+ case MH_CIGAM:
+ return sizeof(struct mach_header);
+
+ case MH_MAGIC_64:
+ case MH_CIGAM_64:
+ return sizeof(struct mach_header_64);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+#define MACHO_NLIST_ARM_SYMBOL_IS_THUMB 0x0008
+
+void
+ObjectFileMachO::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ CreateMemoryInstance,
+ GetModuleSpecifications,
+ SaveCore);
+}
+
+void
+ObjectFileMachO::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ObjectFileMachO::GetPluginNameStatic()
+{
+ static ConstString g_name("mach-o");
+ return g_name;
+}
+
+const char *
+ObjectFileMachO::GetPluginDescriptionStatic()
+{
+ return "Mach-o object file reader (32 and 64 bit)";
+}
+
+ObjectFile *
+ObjectFileMachO::CreateInstance (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length)
+{
+ if (!data_sp)
+ {
+ data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
+ data_offset = 0;
+ }
+
+ if (ObjectFileMachO::MagicBytesMatch(data_sp, data_offset, length))
+ {
+ // Update the data to contain the entire file if it doesn't already
+ if (data_sp->GetByteSize() < length)
+ {
+ data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
+ data_offset = 0;
+ }
+ std::unique_ptr<ObjectFile> objfile_ap(new ObjectFileMachO (module_sp, data_sp, data_offset, file, file_offset, length));
+ if (objfile_ap.get() && objfile_ap->ParseHeader())
+ return objfile_ap.release();
+ }
+ return NULL;
+}
+
+ObjectFile *
+ObjectFileMachO::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ const ProcessSP &process_sp,
+ lldb::addr_t header_addr)
+{
+ if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
+ {
+ std::unique_ptr<ObjectFile> objfile_ap(new ObjectFileMachO (module_sp, data_sp, process_sp, header_addr));
+ if (objfile_ap.get() && objfile_ap->ParseHeader())
+ return objfile_ap.release();
+ }
+ return NULL;
+}
+
+size_t
+ObjectFileMachO::GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs)
+{
+ const size_t initial_count = specs.GetSize();
+
+ if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
+ {
+ DataExtractor data;
+ data.SetData(data_sp);
+ llvm::MachO::mach_header header;
+ if (ParseHeader (data, &data_offset, header))
+ {
+ size_t header_and_load_cmds = header.sizeofcmds + MachHeaderSizeFromMagic(header.magic);
+ if (header_and_load_cmds >= data_sp->GetByteSize())
+ {
+ data_sp = file.ReadFileContents(file_offset, header_and_load_cmds);
+ data.SetData(data_sp);
+ data_offset = MachHeaderSizeFromMagic(header.magic);
+ }
+ if (data_sp)
+ {
+ ModuleSpec spec;
+ spec.GetFileSpec() = file;
+ spec.SetObjectOffset(file_offset);
+ spec.SetObjectSize(length);
+
+ if (GetArchitecture (header, data, data_offset, spec.GetArchitecture()))
+ {
+ if (spec.GetArchitecture().IsValid())
+ {
+ GetUUID (header, data, data_offset, spec.GetUUID());
+ specs.Append(spec);
+ }
+ }
+ }
+ }
+ }
+ return specs.GetSize() - initial_count;
+}
+
+const ConstString &
+ObjectFileMachO::GetSegmentNameTEXT()
+{
+ static ConstString g_segment_name_TEXT ("__TEXT");
+ return g_segment_name_TEXT;
+}
+
+const ConstString &
+ObjectFileMachO::GetSegmentNameDATA()
+{
+ static ConstString g_segment_name_DATA ("__DATA");
+ return g_segment_name_DATA;
+}
+
+const ConstString &
+ObjectFileMachO::GetSegmentNameDATA_DIRTY()
+{
+ static ConstString g_segment_name ("__DATA_DIRTY");
+ return g_segment_name;
+}
+
+const ConstString &
+ObjectFileMachO::GetSegmentNameDATA_CONST()
+{
+ static ConstString g_segment_name ("__DATA_CONST");
+ return g_segment_name;
+}
+
+const ConstString &
+ObjectFileMachO::GetSegmentNameOBJC()
+{
+ static ConstString g_segment_name_OBJC ("__OBJC");
+ return g_segment_name_OBJC;
+}
+
+const ConstString &
+ObjectFileMachO::GetSegmentNameLINKEDIT()
+{
+ static ConstString g_section_name_LINKEDIT ("__LINKEDIT");
+ return g_section_name_LINKEDIT;
+}
+
+const ConstString &
+ObjectFileMachO::GetSectionNameEHFrame()
+{
+ static ConstString g_section_name_eh_frame ("__eh_frame");
+ return g_section_name_eh_frame;
+}
+
+bool
+ObjectFileMachO::MagicBytesMatch (DataBufferSP& data_sp,
+ lldb::addr_t data_offset,
+ lldb::addr_t data_length)
+{
+ DataExtractor data;
+ data.SetData (data_sp, data_offset, data_length);
+ lldb::offset_t offset = 0;
+ uint32_t magic = data.GetU32(&offset);
+ return MachHeaderSizeFromMagic(magic) != 0;
+}
+
+ObjectFileMachO::ObjectFileMachO(const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length) :
+ ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
+ m_mach_segments(),
+ m_mach_sections(),
+ m_entry_point_address(),
+ m_thread_context_offsets(),
+ m_thread_context_offsets_valid(false)
+{
+ ::memset (&m_header, 0, sizeof(m_header));
+ ::memset (&m_dysymtab, 0, sizeof(m_dysymtab));
+}
+
+ObjectFileMachO::ObjectFileMachO (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& header_data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr) :
+ ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
+ m_mach_segments(),
+ m_mach_sections(),
+ m_entry_point_address(),
+ m_thread_context_offsets(),
+ m_thread_context_offsets_valid(false)
+{
+ ::memset (&m_header, 0, sizeof(m_header));
+ ::memset (&m_dysymtab, 0, sizeof(m_dysymtab));
+}
+
+bool
+ObjectFileMachO::ParseHeader (DataExtractor &data,
+ lldb::offset_t *data_offset_ptr,
+ llvm::MachO::mach_header &header)
+{
+ data.SetByteOrder (endian::InlHostByteOrder());
+ // Leave magic in the original byte order
+ header.magic = data.GetU32(data_offset_ptr);
+ bool can_parse = false;
+ bool is_64_bit = false;
+ switch (header.magic)
+ {
+ case MH_MAGIC:
+ data.SetByteOrder (endian::InlHostByteOrder());
+ data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_MAGIC_64:
+ data.SetByteOrder (endian::InlHostByteOrder());
+ data.SetAddressByteSize(8);
+ can_parse = true;
+ is_64_bit = true;
+ break;
+
+ case MH_CIGAM:
+ data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
+ data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_CIGAM_64:
+ data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
+ data.SetAddressByteSize(8);
+ is_64_bit = true;
+ can_parse = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (can_parse)
+ {
+ data.GetU32(data_offset_ptr, &header.cputype, 6);
+ if (is_64_bit)
+ *data_offset_ptr += 4;
+ return true;
+ }
+ else
+ {
+ memset(&header, 0, sizeof(header));
+ }
+ return false;
+}
+
+bool
+ObjectFileMachO::ParseHeader ()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ bool can_parse = false;
+ lldb::offset_t offset = 0;
+ m_data.SetByteOrder (endian::InlHostByteOrder());
+ // Leave magic in the original byte order
+ m_header.magic = m_data.GetU32(&offset);
+ switch (m_header.magic)
+ {
+ case MH_MAGIC:
+ m_data.SetByteOrder (endian::InlHostByteOrder());
+ m_data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_MAGIC_64:
+ m_data.SetByteOrder (endian::InlHostByteOrder());
+ m_data.SetAddressByteSize(8);
+ can_parse = true;
+ break;
+
+ case MH_CIGAM:
+ m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
+ m_data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_CIGAM_64:
+ m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
+ m_data.SetAddressByteSize(8);
+ can_parse = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (can_parse)
+ {
+ m_data.GetU32(&offset, &m_header.cputype, 6);
+
+
+ ArchSpec mach_arch;
+
+ if (GetArchitecture (mach_arch))
+ {
+ // Check if the module has a required architecture
+ const ArchSpec &module_arch = module_sp->GetArchitecture();
+ if (module_arch.IsValid() && !module_arch.IsCompatibleMatch(mach_arch))
+ return false;
+
+ if (SetModulesArchitecture (mach_arch))
+ {
+ const size_t header_and_lc_size = m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic);
+ if (m_data.GetByteSize() < header_and_lc_size)
+ {
+ DataBufferSP data_sp;
+ ProcessSP process_sp (m_process_wp.lock());
+ if (process_sp)
+ {
+ data_sp = ReadMemory (process_sp, m_memory_addr, header_and_lc_size);
+ }
+ else
+ {
+ // Read in all only the load command data from the file on disk
+ data_sp = m_file.ReadFileContents(m_file_offset, header_and_lc_size);
+ if (data_sp->GetByteSize() != header_and_lc_size)
+ return false;
+ }
+ if (data_sp)
+ m_data.SetData (data_sp);
+ }
+ }
+ return true;
+ }
+ }
+ else
+ {
+ memset(&m_header, 0, sizeof(struct mach_header));
+ }
+ }
+ return false;
+}
+
+ByteOrder
+ObjectFileMachO::GetByteOrder () const
+{
+ return m_data.GetByteOrder ();
+}
+
+bool
+ObjectFileMachO::IsExecutable() const
+{
+ return m_header.filetype == MH_EXECUTE;
+}
+
+uint32_t
+ObjectFileMachO::GetAddressByteSize () const
+{
+ return m_data.GetAddressByteSize ();
+}
+
+AddressClass
+ObjectFileMachO::GetAddressClass (lldb::addr_t file_addr)
+{
+ Symtab *symtab = GetSymtab();
+ if (symtab)
+ {
+ Symbol *symbol = symtab->FindSymbolContainingFileAddress(file_addr);
+ if (symbol)
+ {
+ if (symbol->ValueIsAddress())
+ {
+ SectionSP section_sp (symbol->GetAddressRef().GetSection());
+ if (section_sp)
+ {
+ const lldb::SectionType section_type = section_sp->GetType();
+ switch (section_type)
+ {
+ case eSectionTypeInvalid:
+ return eAddressClassUnknown;
+
+ case eSectionTypeCode:
+ if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM)
+ {
+ // For ARM we have a bit in the n_desc field of the symbol
+ // that tells us ARM/Thumb which is bit 0x0008.
+ if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB)
+ return eAddressClassCodeAlternateISA;
+ }
+ return eAddressClassCode;
+
+ case eSectionTypeContainer:
+ return eAddressClassUnknown;
+
+ case eSectionTypeData:
+ case eSectionTypeDataCString:
+ case eSectionTypeDataCStringPointers:
+ case eSectionTypeDataSymbolAddress:
+ case eSectionTypeData4:
+ case eSectionTypeData8:
+ case eSectionTypeData16:
+ case eSectionTypeDataPointers:
+ case eSectionTypeZeroFill:
+ case eSectionTypeDataObjCMessageRefs:
+ case eSectionTypeDataObjCCFStrings:
+ case eSectionTypeGoSymtab:
+ return eAddressClassData;
+
+ case eSectionTypeDebug:
+ case eSectionTypeDWARFDebugAbbrev:
+ case eSectionTypeDWARFDebugAddr:
+ case eSectionTypeDWARFDebugAranges:
+ case eSectionTypeDWARFDebugFrame:
+ case eSectionTypeDWARFDebugInfo:
+ case eSectionTypeDWARFDebugLine:
+ case eSectionTypeDWARFDebugLoc:
+ case eSectionTypeDWARFDebugMacInfo:
+ case eSectionTypeDWARFDebugMacro:
+ case eSectionTypeDWARFDebugPubNames:
+ case eSectionTypeDWARFDebugPubTypes:
+ case eSectionTypeDWARFDebugRanges:
+ case eSectionTypeDWARFDebugStr:
+ case eSectionTypeDWARFDebugStrOffsets:
+ case eSectionTypeDWARFAppleNames:
+ case eSectionTypeDWARFAppleTypes:
+ case eSectionTypeDWARFAppleNamespaces:
+ case eSectionTypeDWARFAppleObjC:
+ return eAddressClassDebug;
+
+ case eSectionTypeEHFrame:
+ case eSectionTypeARMexidx:
+ case eSectionTypeARMextab:
+ case eSectionTypeCompactUnwind:
+ return eAddressClassRuntime;
+
+ case eSectionTypeELFSymbolTable:
+ case eSectionTypeELFDynamicSymbols:
+ case eSectionTypeELFRelocationEntries:
+ case eSectionTypeELFDynamicLinkInfo:
+ case eSectionTypeOther:
+ return eAddressClassUnknown;
+ }
+ }
+ }
+
+ const SymbolType symbol_type = symbol->GetType();
+ switch (symbol_type)
+ {
+ case eSymbolTypeAny: return eAddressClassUnknown;
+ case eSymbolTypeAbsolute: return eAddressClassUnknown;
+
+ case eSymbolTypeCode:
+ case eSymbolTypeTrampoline:
+ case eSymbolTypeResolver:
+ if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM)
+ {
+ // For ARM we have a bit in the n_desc field of the symbol
+ // that tells us ARM/Thumb which is bit 0x0008.
+ if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB)
+ return eAddressClassCodeAlternateISA;
+ }
+ return eAddressClassCode;
+
+ case eSymbolTypeData: return eAddressClassData;
+ case eSymbolTypeRuntime: return eAddressClassRuntime;
+ case eSymbolTypeException: return eAddressClassRuntime;
+ case eSymbolTypeSourceFile: return eAddressClassDebug;
+ case eSymbolTypeHeaderFile: return eAddressClassDebug;
+ case eSymbolTypeObjectFile: return eAddressClassDebug;
+ case eSymbolTypeCommonBlock: return eAddressClassDebug;
+ case eSymbolTypeBlock: return eAddressClassDebug;
+ case eSymbolTypeLocal: return eAddressClassData;
+ case eSymbolTypeParam: return eAddressClassData;
+ case eSymbolTypeVariable: return eAddressClassData;
+ case eSymbolTypeVariableType: return eAddressClassDebug;
+ case eSymbolTypeLineEntry: return eAddressClassDebug;
+ case eSymbolTypeLineHeader: return eAddressClassDebug;
+ case eSymbolTypeScopeBegin: return eAddressClassDebug;
+ case eSymbolTypeScopeEnd: return eAddressClassDebug;
+ case eSymbolTypeAdditional: return eAddressClassUnknown;
+ case eSymbolTypeCompiler: return eAddressClassDebug;
+ case eSymbolTypeInstrumentation:return eAddressClassDebug;
+ case eSymbolTypeUndefined: return eAddressClassUnknown;
+ case eSymbolTypeObjCClass: return eAddressClassRuntime;
+ case eSymbolTypeObjCMetaClass: return eAddressClassRuntime;
+ case eSymbolTypeObjCIVar: return eAddressClassRuntime;
+ case eSymbolTypeReExported: return eAddressClassRuntime;
+ }
+ }
+ }
+ return eAddressClassUnknown;
+}
+
+Symtab *
+ObjectFileMachO::GetSymtab()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_symtab_ap.get() == NULL)
+ {
+ m_symtab_ap.reset(new Symtab(this));
+ Mutex::Locker symtab_locker (m_symtab_ap->GetMutex());
+ ParseSymtab ();
+ m_symtab_ap->Finalize ();
+ }
+ }
+ return m_symtab_ap.get();
+}
+
+bool
+ObjectFileMachO::IsStripped ()
+{
+ if (m_dysymtab.cmd == 0)
+ {
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ for (uint32_t i=0; i<m_header.ncmds; ++i)
+ {
+ const lldb::offset_t load_cmd_offset = offset;
+
+ load_command lc;
+ if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
+ break;
+ if (lc.cmd == LC_DYSYMTAB)
+ {
+ m_dysymtab.cmd = lc.cmd;
+ m_dysymtab.cmdsize = lc.cmdsize;
+ if (m_data.GetU32 (&offset, &m_dysymtab.ilocalsym, (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) == NULL)
+ {
+ // Clear m_dysymtab if we were unable to read all items from the load command
+ ::memset (&m_dysymtab, 0, sizeof(m_dysymtab));
+ }
+ }
+ offset = load_cmd_offset + lc.cmdsize;
+ }
+ }
+ }
+ if (m_dysymtab.cmd)
+ return m_dysymtab.nlocalsym <= 1;
+ return false;
+}
+
+void
+ObjectFileMachO::CreateSections (SectionList &unified_section_list)
+{
+ if (!m_sections_ap.get())
+ {
+ m_sections_ap.reset(new SectionList());
+
+ const bool is_dsym = (m_header.filetype == MH_DSYM);
+ lldb::user_id_t segID = 0;
+ lldb::user_id_t sectID = 0;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ const bool is_core = GetType() == eTypeCoreFile;
+ //bool dump_sections = false;
+ ModuleSP module_sp (GetModule());
+ // First look up any LC_ENCRYPTION_INFO load commands
+ typedef RangeArray<uint32_t, uint32_t, 8> EncryptedFileRanges;
+ EncryptedFileRanges encrypted_file_ranges;
+ encryption_info_command encryption_cmd;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const lldb::offset_t load_cmd_offset = offset;
+ if (m_data.GetU32(&offset, &encryption_cmd, 2) == NULL)
+ break;
+
+ // LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for
+ // the 3 fields we care about, so treat them the same.
+ if (encryption_cmd.cmd == LC_ENCRYPTION_INFO || encryption_cmd.cmd == LC_ENCRYPTION_INFO_64)
+ {
+ if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3))
+ {
+ if (encryption_cmd.cryptid != 0)
+ {
+ EncryptedFileRanges::Entry entry;
+ entry.SetRangeBase(encryption_cmd.cryptoff);
+ entry.SetByteSize(encryption_cmd.cryptsize);
+ encrypted_file_ranges.Append(entry);
+ }
+ }
+ }
+ offset = load_cmd_offset + encryption_cmd.cmdsize;
+ }
+
+ bool section_file_addresses_changed = false;
+
+ offset = MachHeaderSizeFromMagic(m_header.magic);
+
+ struct segment_command_64 load_cmd;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const lldb::offset_t load_cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64)
+ {
+ if (m_data.GetU8(&offset, (uint8_t*)load_cmd.segname, 16))
+ {
+ bool add_section = true;
+ bool add_to_unified = true;
+ ConstString const_segname (load_cmd.segname, std::min<size_t>(strlen(load_cmd.segname), sizeof(load_cmd.segname)));
+
+ SectionSP unified_section_sp(unified_section_list.FindSectionByName(const_segname));
+ if (is_dsym && unified_section_sp)
+ {
+ if (const_segname == GetSegmentNameLINKEDIT())
+ {
+ // We need to keep the __LINKEDIT segment private to this object file only
+ add_to_unified = false;
+ }
+ else
+ {
+ // This is the dSYM file and this section has already been created by
+ // the object file, no need to create it.
+ add_section = false;
+ }
+ }
+ load_cmd.vmaddr = m_data.GetAddress(&offset);
+ load_cmd.vmsize = m_data.GetAddress(&offset);
+ load_cmd.fileoff = m_data.GetAddress(&offset);
+ load_cmd.filesize = m_data.GetAddress(&offset);
+ if (m_length != 0 && load_cmd.filesize != 0)
+ {
+ if (load_cmd.fileoff > m_length)
+ {
+ // We have a load command that says it extends past the end of the file. This is likely
+ // a corrupt file. We don't have any way to return an error condition here (this method
+ // was likely invoked from something like ObjectFile::GetSectionList()) -- all we can do
+ // is null out the SectionList vector and if a process has been set up, dump a message
+ // to stdout. The most common case here is core file debugging with a truncated file.
+ const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT";
+ module_sp->ReportWarning("load command %u %s has a fileoff (0x%" PRIx64 ") that extends beyond the end of the file (0x%" PRIx64 "), ignoring this section",
+ i,
+ lc_segment_name,
+ load_cmd.fileoff,
+ m_length);
+
+ load_cmd.fileoff = 0;
+ load_cmd.filesize = 0;
+ }
+
+ if (load_cmd.fileoff + load_cmd.filesize > m_length)
+ {
+ // We have a load command that says it extends past the end of the file. This is likely
+ // a corrupt file. We don't have any way to return an error condition here (this method
+ // was likely invoked from something like ObjectFile::GetSectionList()) -- all we can do
+ // is null out the SectionList vector and if a process has been set up, dump a message
+ // to stdout. The most common case here is core file debugging with a truncated file.
+ const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT";
+ GetModule()->ReportWarning("load command %u %s has a fileoff + filesize (0x%" PRIx64 ") that extends beyond the end of the file (0x%" PRIx64 "), the segment will be truncated to match",
+ i,
+ lc_segment_name,
+ load_cmd.fileoff + load_cmd.filesize,
+ m_length);
+
+ // Tuncase the length
+ load_cmd.filesize = m_length - load_cmd.fileoff;
+ }
+ }
+ if (m_data.GetU32(&offset, &load_cmd.maxprot, 4))
+ {
+
+ const bool segment_is_encrypted = (load_cmd.flags & SG_PROTECTED_VERSION_1) != 0;
+
+ // Keep a list of mach segments around in case we need to
+ // get at data that isn't stored in the abstracted Sections.
+ m_mach_segments.push_back (load_cmd);
+
+ // Use a segment ID of the segment index shifted left by 8 so they
+ // never conflict with any of the sections.
+ SectionSP segment_sp;
+ if (add_section && (const_segname || is_core))
+ {
+ segment_sp.reset(new Section (module_sp, // Module to which this section belongs
+ this, // Object file to which this sections belongs
+ ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
+ const_segname, // Name of this section
+ eSectionTypeContainer, // This section is a container of other sections.
+ load_cmd.vmaddr, // File VM address == addresses as they are found in the object file
+ load_cmd.vmsize, // VM size in bytes of this section
+ load_cmd.fileoff, // Offset to the data for this section in the file
+ load_cmd.filesize, // Size in bytes of this section as found in the file
+ 0, // Segments have no alignment information
+ load_cmd.flags)); // Flags for this section
+
+ segment_sp->SetIsEncrypted (segment_is_encrypted);
+ m_sections_ap->AddSection(segment_sp);
+ if (add_to_unified)
+ unified_section_list.AddSection(segment_sp);
+ }
+ else if (unified_section_sp)
+ {
+ if (is_dsym && unified_section_sp->GetFileAddress() != load_cmd.vmaddr)
+ {
+ // Check to see if the module was read from memory?
+ if (module_sp->GetObjectFile()->GetHeaderAddress().IsValid())
+ {
+ // We have a module that is in memory and needs to have its
+ // file address adjusted. We need to do this because when we
+ // load a file from memory, its addresses will be slid already,
+ // yet the addresses in the new symbol file will still be unslid.
+ // Since everything is stored as section offset, this shouldn't
+ // cause any problems.
+
+ // Make sure we've parsed the symbol table from the
+ // ObjectFile before we go around changing its Sections.
+ module_sp->GetObjectFile()->GetSymtab();
+ // eh_frame would present the same problems but we parse that on
+ // a per-function basis as-needed so it's more difficult to
+ // remove its use of the Sections. Realistically, the environments
+ // where this code path will be taken will not have eh_frame sections.
+
+ unified_section_sp->SetFileAddress(load_cmd.vmaddr);
+
+ // Notify the module that the section addresses have been changed once
+ // we're done so any file-address caches can be updated.
+ section_file_addresses_changed = true;
+ }
+ }
+ m_sections_ap->AddSection(unified_section_sp);
+ }
+
+ struct section_64 sect64;
+ ::memset (&sect64, 0, sizeof(sect64));
+ // Push a section into our mach sections for the section at
+ // index zero (NO_SECT) if we don't have any mach sections yet...
+ if (m_mach_sections.empty())
+ m_mach_sections.push_back(sect64);
+ uint32_t segment_sect_idx;
+ const lldb::user_id_t first_segment_sectID = sectID + 1;
+
+
+ const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8;
+ for (segment_sect_idx=0; segment_sect_idx<load_cmd.nsects; ++segment_sect_idx)
+ {
+ if (m_data.GetU8(&offset, (uint8_t*)sect64.sectname, sizeof(sect64.sectname)) == NULL)
+ break;
+ if (m_data.GetU8(&offset, (uint8_t*)sect64.segname, sizeof(sect64.segname)) == NULL)
+ break;
+ sect64.addr = m_data.GetAddress(&offset);
+ sect64.size = m_data.GetAddress(&offset);
+
+ if (m_data.GetU32(&offset, &sect64.offset, num_u32s) == NULL)
+ break;
+
+ // Keep a list of mach sections around in case we need to
+ // get at data that isn't stored in the abstracted Sections.
+ m_mach_sections.push_back (sect64);
+
+ if (add_section)
+ {
+ ConstString section_name (sect64.sectname, std::min<size_t>(strlen(sect64.sectname), sizeof(sect64.sectname)));
+ if (!const_segname)
+ {
+ // We have a segment with no name so we need to conjure up
+ // segments that correspond to the section's segname if there
+ // isn't already such a section. If there is such a section,
+ // we resize the section so that it spans all sections.
+ // We also mark these sections as fake so address matches don't
+ // hit if they land in the gaps between the child sections.
+ const_segname.SetTrimmedCStringWithLength(sect64.segname, sizeof(sect64.segname));
+ segment_sp = unified_section_list.FindSectionByName (const_segname);
+ if (segment_sp.get())
+ {
+ Section *segment = segment_sp.get();
+ // Grow the section size as needed.
+ const lldb::addr_t sect64_min_addr = sect64.addr;
+ const lldb::addr_t sect64_max_addr = sect64_min_addr + sect64.size;
+ const lldb::addr_t curr_seg_byte_size = segment->GetByteSize();
+ const lldb::addr_t curr_seg_min_addr = segment->GetFileAddress();
+ const lldb::addr_t curr_seg_max_addr = curr_seg_min_addr + curr_seg_byte_size;
+ if (sect64_min_addr >= curr_seg_min_addr)
+ {
+ const lldb::addr_t new_seg_byte_size = sect64_max_addr - curr_seg_min_addr;
+ // Only grow the section size if needed
+ if (new_seg_byte_size > curr_seg_byte_size)
+ segment->SetByteSize (new_seg_byte_size);
+ }
+ else
+ {
+ // We need to change the base address of the segment and
+ // adjust the child section offsets for all existing children.
+ const lldb::addr_t slide_amount = sect64_min_addr - curr_seg_min_addr;
+ segment->Slide(slide_amount, false);
+ segment->GetChildren().Slide(-slide_amount, false);
+ segment->SetByteSize (curr_seg_max_addr - sect64_min_addr);
+ }
+
+ // Grow the section size as needed.
+ if (sect64.offset)
+ {
+ const lldb::addr_t segment_min_file_offset = segment->GetFileOffset();
+ const lldb::addr_t segment_max_file_offset = segment_min_file_offset + segment->GetFileSize();
+
+ const lldb::addr_t section_min_file_offset = sect64.offset;
+ const lldb::addr_t section_max_file_offset = section_min_file_offset + sect64.size;
+ const lldb::addr_t new_file_offset = std::min (section_min_file_offset, segment_min_file_offset);
+ const lldb::addr_t new_file_size = std::max (section_max_file_offset, segment_max_file_offset) - new_file_offset;
+ segment->SetFileOffset (new_file_offset);
+ segment->SetFileSize (new_file_size);
+ }
+ }
+ else
+ {
+ // Create a fake section for the section's named segment
+ segment_sp.reset(new Section (segment_sp, // Parent section
+ module_sp, // Module to which this section belongs
+ this, // Object file to which this section belongs
+ ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
+ const_segname, // Name of this section
+ eSectionTypeContainer, // This section is a container of other sections.
+ sect64.addr, // File VM address == addresses as they are found in the object file
+ sect64.size, // VM size in bytes of this section
+ sect64.offset, // Offset to the data for this section in the file
+ sect64.offset ? sect64.size : 0, // Size in bytes of this section as found in the file
+ sect64.align,
+ load_cmd.flags)); // Flags for this section
+ segment_sp->SetIsFake(true);
+
+ m_sections_ap->AddSection(segment_sp);
+ if (add_to_unified)
+ unified_section_list.AddSection(segment_sp);
+ segment_sp->SetIsEncrypted (segment_is_encrypted);
+ }
+ }
+ assert (segment_sp.get());
+
+ lldb::SectionType sect_type = eSectionTypeOther;
+
+ if (sect64.flags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS))
+ sect_type = eSectionTypeCode;
+ else
+ {
+ uint32_t mach_sect_type = sect64.flags & SECTION_TYPE;
+ static ConstString g_sect_name_objc_data ("__objc_data");
+ static ConstString g_sect_name_objc_msgrefs ("__objc_msgrefs");
+ static ConstString g_sect_name_objc_selrefs ("__objc_selrefs");
+ static ConstString g_sect_name_objc_classrefs ("__objc_classrefs");
+ static ConstString g_sect_name_objc_superrefs ("__objc_superrefs");
+ static ConstString g_sect_name_objc_const ("__objc_const");
+ static ConstString g_sect_name_objc_classlist ("__objc_classlist");
+ static ConstString g_sect_name_cfstring ("__cfstring");
+
+ static ConstString g_sect_name_dwarf_debug_abbrev ("__debug_abbrev");
+ static ConstString g_sect_name_dwarf_debug_aranges ("__debug_aranges");
+ static ConstString g_sect_name_dwarf_debug_frame ("__debug_frame");
+ static ConstString g_sect_name_dwarf_debug_info ("__debug_info");
+ static ConstString g_sect_name_dwarf_debug_line ("__debug_line");
+ static ConstString g_sect_name_dwarf_debug_loc ("__debug_loc");
+ static ConstString g_sect_name_dwarf_debug_macinfo ("__debug_macinfo");
+ static ConstString g_sect_name_dwarf_debug_pubnames ("__debug_pubnames");
+ static ConstString g_sect_name_dwarf_debug_pubtypes ("__debug_pubtypes");
+ static ConstString g_sect_name_dwarf_debug_ranges ("__debug_ranges");
+ static ConstString g_sect_name_dwarf_debug_str ("__debug_str");
+ static ConstString g_sect_name_dwarf_apple_names ("__apple_names");
+ static ConstString g_sect_name_dwarf_apple_types ("__apple_types");
+ static ConstString g_sect_name_dwarf_apple_namespaces ("__apple_namespac");
+ static ConstString g_sect_name_dwarf_apple_objc ("__apple_objc");
+ static ConstString g_sect_name_eh_frame ("__eh_frame");
+ static ConstString g_sect_name_compact_unwind ("__unwind_info");
+ static ConstString g_sect_name_text ("__text");
+ static ConstString g_sect_name_data ("__data");
+ static ConstString g_sect_name_go_symtab ("__gosymtab");
+
+ if (section_name == g_sect_name_dwarf_debug_abbrev)
+ sect_type = eSectionTypeDWARFDebugAbbrev;
+ else if (section_name == g_sect_name_dwarf_debug_aranges)
+ sect_type = eSectionTypeDWARFDebugAranges;
+ else if (section_name == g_sect_name_dwarf_debug_frame)
+ sect_type = eSectionTypeDWARFDebugFrame;
+ else if (section_name == g_sect_name_dwarf_debug_info)
+ sect_type = eSectionTypeDWARFDebugInfo;
+ else if (section_name == g_sect_name_dwarf_debug_line)
+ sect_type = eSectionTypeDWARFDebugLine;
+ else if (section_name == g_sect_name_dwarf_debug_loc)
+ sect_type = eSectionTypeDWARFDebugLoc;
+ else if (section_name == g_sect_name_dwarf_debug_macinfo)
+ sect_type = eSectionTypeDWARFDebugMacInfo;
+ else if (section_name == g_sect_name_dwarf_debug_pubnames)
+ sect_type = eSectionTypeDWARFDebugPubNames;
+ else if (section_name == g_sect_name_dwarf_debug_pubtypes)
+ sect_type = eSectionTypeDWARFDebugPubTypes;
+ else if (section_name == g_sect_name_dwarf_debug_ranges)
+ sect_type = eSectionTypeDWARFDebugRanges;
+ else if (section_name == g_sect_name_dwarf_debug_str)
+ sect_type = eSectionTypeDWARFDebugStr;
+ else if (section_name == g_sect_name_dwarf_apple_names)
+ sect_type = eSectionTypeDWARFAppleNames;
+ else if (section_name == g_sect_name_dwarf_apple_types)
+ sect_type = eSectionTypeDWARFAppleTypes;
+ else if (section_name == g_sect_name_dwarf_apple_namespaces)
+ sect_type = eSectionTypeDWARFAppleNamespaces;
+ else if (section_name == g_sect_name_dwarf_apple_objc)
+ sect_type = eSectionTypeDWARFAppleObjC;
+ else if (section_name == g_sect_name_objc_selrefs)
+ sect_type = eSectionTypeDataCStringPointers;
+ else if (section_name == g_sect_name_objc_msgrefs)
+ sect_type = eSectionTypeDataObjCMessageRefs;
+ else if (section_name == g_sect_name_eh_frame)
+ sect_type = eSectionTypeEHFrame;
+ else if (section_name == g_sect_name_compact_unwind)
+ sect_type = eSectionTypeCompactUnwind;
+ else if (section_name == g_sect_name_cfstring)
+ sect_type = eSectionTypeDataObjCCFStrings;
+ else if (section_name == g_sect_name_go_symtab)
+ sect_type = eSectionTypeGoSymtab;
+ else if (section_name == g_sect_name_objc_data ||
+ section_name == g_sect_name_objc_classrefs ||
+ section_name == g_sect_name_objc_superrefs ||
+ section_name == g_sect_name_objc_const ||
+ section_name == g_sect_name_objc_classlist)
+ {
+ sect_type = eSectionTypeDataPointers;
+ }
+
+ if (sect_type == eSectionTypeOther)
+ {
+ switch (mach_sect_type)
+ {
+ // TODO: categorize sections by other flags for regular sections
+ case S_REGULAR:
+ if (section_name == g_sect_name_text)
+ sect_type = eSectionTypeCode;
+ else if (section_name == g_sect_name_data)
+ sect_type = eSectionTypeData;
+ else
+ sect_type = eSectionTypeOther;
+ break;
+ case S_ZEROFILL: sect_type = eSectionTypeZeroFill; break;
+ case S_CSTRING_LITERALS: sect_type = eSectionTypeDataCString; break; // section with only literal C strings
+ case S_4BYTE_LITERALS: sect_type = eSectionTypeData4; break; // section with only 4 byte literals
+ case S_8BYTE_LITERALS: sect_type = eSectionTypeData8; break; // section with only 8 byte literals
+ case S_LITERAL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only pointers to literals
+ case S_NON_LAZY_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only non-lazy symbol pointers
+ case S_LAZY_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only lazy symbol pointers
+ case S_SYMBOL_STUBS: sect_type = eSectionTypeCode; break; // section with only symbol stubs, byte size of stub in the reserved2 field
+ case S_MOD_INIT_FUNC_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only function pointers for initialization
+ case S_MOD_TERM_FUNC_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only function pointers for termination
+ case S_COALESCED: sect_type = eSectionTypeOther; break;
+ case S_GB_ZEROFILL: sect_type = eSectionTypeZeroFill; break;
+ case S_INTERPOSING: sect_type = eSectionTypeCode; break; // section with only pairs of function pointers for interposing
+ case S_16BYTE_LITERALS: sect_type = eSectionTypeData16; break; // section with only 16 byte literals
+ case S_DTRACE_DOF: sect_type = eSectionTypeDebug; break;
+ case S_LAZY_DYLIB_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break;
+ default: break;
+ }
+ }
+ }
+
+ SectionSP section_sp(new Section (segment_sp,
+ module_sp,
+ this,
+ ++sectID,
+ section_name,
+ sect_type,
+ sect64.addr - segment_sp->GetFileAddress(),
+ sect64.size,
+ sect64.offset,
+ sect64.offset == 0 ? 0 : sect64.size,
+ sect64.align,
+ sect64.flags));
+ // Set the section to be encrypted to match the segment
+
+ bool section_is_encrypted = false;
+ if (!segment_is_encrypted && load_cmd.filesize != 0)
+ section_is_encrypted = encrypted_file_ranges.FindEntryThatContains(sect64.offset) != NULL;
+
+ section_sp->SetIsEncrypted (segment_is_encrypted || section_is_encrypted);
+ segment_sp->GetChildren().AddSection(section_sp);
+
+ if (segment_sp->IsFake())
+ {
+ segment_sp.reset();
+ const_segname.Clear();
+ }
+ }
+ }
+ if (segment_sp && is_dsym)
+ {
+ if (first_segment_sectID <= sectID)
+ {
+ lldb::user_id_t sect_uid;
+ for (sect_uid = first_segment_sectID; sect_uid <= sectID; ++sect_uid)
+ {
+ SectionSP curr_section_sp(segment_sp->GetChildren().FindSectionByID (sect_uid));
+ SectionSP next_section_sp;
+ if (sect_uid + 1 <= sectID)
+ next_section_sp = segment_sp->GetChildren().FindSectionByID (sect_uid+1);
+
+ if (curr_section_sp.get())
+ {
+ if (curr_section_sp->GetByteSize() == 0)
+ {
+ if (next_section_sp.get() != NULL)
+ curr_section_sp->SetByteSize ( next_section_sp->GetFileAddress() - curr_section_sp->GetFileAddress() );
+ else
+ curr_section_sp->SetByteSize ( load_cmd.vmsize );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (load_cmd.cmd == LC_DYSYMTAB)
+ {
+ m_dysymtab.cmd = load_cmd.cmd;
+ m_dysymtab.cmdsize = load_cmd.cmdsize;
+ m_data.GetU32 (&offset, &m_dysymtab.ilocalsym, (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2);
+ }
+
+ offset = load_cmd_offset + load_cmd.cmdsize;
+ }
+
+
+ if (section_file_addresses_changed && module_sp.get())
+ {
+ module_sp->SectionFileAddressesChanged();
+ }
+ }
+}
+
+class MachSymtabSectionInfo
+{
+public:
+ MachSymtabSectionInfo (SectionList *section_list) :
+ m_section_list (section_list),
+ m_section_infos()
+ {
+ // Get the number of sections down to a depth of 1 to include
+ // all segments and their sections, but no other sections that
+ // may be added for debug map or
+ m_section_infos.resize(section_list->GetNumSections(1));
+ }
+
+ SectionSP
+ GetSection (uint8_t n_sect, addr_t file_addr)
+ {
+ if (n_sect == 0)
+ return SectionSP();
+ if (n_sect < m_section_infos.size())
+ {
+ if (!m_section_infos[n_sect].section_sp)
+ {
+ SectionSP section_sp (m_section_list->FindSectionByID (n_sect));
+ m_section_infos[n_sect].section_sp = section_sp;
+ if (section_sp)
+ {
+ m_section_infos[n_sect].vm_range.SetBaseAddress (section_sp->GetFileAddress());
+ m_section_infos[n_sect].vm_range.SetByteSize (section_sp->GetByteSize());
+ }
+ else
+ {
+ Host::SystemLog (Host::eSystemLogError, "error: unable to find section for section %u\n", n_sect);
+ }
+ }
+ if (m_section_infos[n_sect].vm_range.Contains(file_addr))
+ {
+ // Symbol is in section.
+ return m_section_infos[n_sect].section_sp;
+ }
+ else if (m_section_infos[n_sect].vm_range.GetByteSize () == 0 &&
+ m_section_infos[n_sect].vm_range.GetBaseAddress() == file_addr)
+ {
+ // Symbol is in section with zero size, but has the same start
+ // address as the section. This can happen with linker symbols
+ // (symbols that start with the letter 'l' or 'L'.
+ return m_section_infos[n_sect].section_sp;
+ }
+ }
+ return m_section_list->FindSectionContainingFileAddress(file_addr);
+ }
+
+protected:
+ struct SectionInfo
+ {
+ SectionInfo () :
+ vm_range(),
+ section_sp ()
+ {
+ }
+
+ VMRange vm_range;
+ SectionSP section_sp;
+ };
+ SectionList *m_section_list;
+ std::vector<SectionInfo> m_section_infos;
+};
+
+struct TrieEntry
+{
+ TrieEntry () :
+ name(),
+ address(LLDB_INVALID_ADDRESS),
+ flags (0),
+ other(0),
+ import_name()
+ {
+ }
+
+ void
+ Clear ()
+ {
+ name.Clear();
+ address = LLDB_INVALID_ADDRESS;
+ flags = 0;
+ other = 0;
+ import_name.Clear();
+ }
+
+ void
+ Dump () const
+ {
+ printf ("0x%16.16llx 0x%16.16llx 0x%16.16llx \"%s\"",
+ static_cast<unsigned long long>(address),
+ static_cast<unsigned long long>(flags),
+ static_cast<unsigned long long>(other), name.GetCString());
+ if (import_name)
+ printf (" -> \"%s\"\n", import_name.GetCString());
+ else
+ printf ("\n");
+ }
+ ConstString name;
+ uint64_t address;
+ uint64_t flags;
+ uint64_t other;
+ ConstString import_name;
+};
+
+struct TrieEntryWithOffset
+{
+ lldb::offset_t nodeOffset;
+ TrieEntry entry;
+
+ TrieEntryWithOffset (lldb::offset_t offset) :
+ nodeOffset (offset),
+ entry()
+ {
+ }
+
+ void
+ Dump (uint32_t idx) const
+ {
+ printf ("[%3u] 0x%16.16llx: ", idx,
+ static_cast<unsigned long long>(nodeOffset));
+ entry.Dump();
+ }
+
+ bool
+ operator<(const TrieEntryWithOffset& other) const
+ {
+ return ( nodeOffset < other.nodeOffset );
+ }
+};
+
+static bool
+ParseTrieEntries (DataExtractor &data,
+ lldb::offset_t offset,
+ const bool is_arm,
+ std::vector<llvm::StringRef> &nameSlices,
+ std::set<lldb::addr_t> &resolver_addresses,
+ std::vector<TrieEntryWithOffset>& output)
+{
+ if (!data.ValidOffset(offset))
+ return true;
+
+ const uint64_t terminalSize = data.GetULEB128(&offset);
+ lldb::offset_t children_offset = offset + terminalSize;
+ if ( terminalSize != 0 ) {
+ TrieEntryWithOffset e (offset);
+ e.entry.flags = data.GetULEB128(&offset);
+ const char *import_name = NULL;
+ if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+ e.entry.address = 0;
+ e.entry.other = data.GetULEB128(&offset); // dylib ordinal
+ import_name = data.GetCStr(&offset);
+ }
+ else {
+ e.entry.address = data.GetULEB128(&offset);
+ if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
+ {
+ e.entry.other = data.GetULEB128(&offset);
+ uint64_t resolver_addr = e.entry.other;
+ if (is_arm)
+ resolver_addr &= THUMB_ADDRESS_BIT_MASK;
+ resolver_addresses.insert(resolver_addr);
+ }
+ else
+ e.entry.other = 0;
+ }
+ // Only add symbols that are reexport symbols with a valid import name
+ if (EXPORT_SYMBOL_FLAGS_REEXPORT & e.entry.flags && import_name && import_name[0])
+ {
+ std::string name;
+ if (!nameSlices.empty())
+ {
+ for (auto name_slice: nameSlices)
+ name.append(name_slice.data(), name_slice.size());
+ }
+ if (name.size() > 1)
+ {
+ // Skip the leading '_'
+ e.entry.name.SetCStringWithLength(name.c_str() + 1,name.size() - 1);
+ }
+ if (import_name)
+ {
+ // Skip the leading '_'
+ e.entry.import_name.SetCString(import_name+1);
+ }
+ output.push_back(e);
+ }
+ }
+
+ const uint8_t childrenCount = data.GetU8(&children_offset);
+ for (uint8_t i=0; i < childrenCount; ++i) {
+ const char *cstr = data.GetCStr(&children_offset);
+ if (cstr)
+ nameSlices.push_back(llvm::StringRef(cstr));
+ else
+ return false; // Corrupt data
+ lldb::offset_t childNodeOffset = data.GetULEB128(&children_offset);
+ if (childNodeOffset)
+ {
+ if (!ParseTrieEntries(data,
+ childNodeOffset,
+ is_arm,
+ nameSlices,
+ resolver_addresses,
+ output))
+ {
+ return false;
+ }
+ }
+ nameSlices.pop_back();
+ }
+ return true;
+}
+
+// Read the UUID out of a dyld_shared_cache file on-disk.
+UUID
+ObjectFileMachO::GetSharedCacheUUID (FileSpec dyld_shared_cache, const ByteOrder byte_order, const uint32_t addr_byte_size)
+{
+ UUID dsc_uuid;
+ DataBufferSP dsc_data_sp = dyld_shared_cache.MemoryMapFileContentsIfLocal(0, sizeof(struct lldb_copy_dyld_cache_header_v1));
+ if (dsc_data_sp)
+ {
+ DataExtractor dsc_header_data (dsc_data_sp, byte_order, addr_byte_size);
+
+ char version_str[7];
+ lldb::offset_t offset = 0;
+ memcpy (version_str, dsc_header_data.GetData (&offset, 6), 6);
+ version_str[6] = '\0';
+ if (strcmp (version_str, "dyld_v") == 0)
+ {
+ offset = offsetof (struct lldb_copy_dyld_cache_header_v1, uuid);
+ uint8_t uuid_bytes[sizeof (uuid_t)];
+ memcpy (uuid_bytes, dsc_header_data.GetData (&offset, sizeof (uuid_t)), sizeof (uuid_t));
+ dsc_uuid.SetBytes (uuid_bytes);
+ }
+ }
+ return dsc_uuid;
+}
+
+size_t
+ObjectFileMachO::ParseSymtab ()
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "ObjectFileMachO::ParseSymtab () module = %s",
+ m_file.GetFilename().AsCString(""));
+ ModuleSP module_sp (GetModule());
+ if (!module_sp)
+ return 0;
+
+ struct symtab_command symtab_load_command = { 0, 0, 0, 0, 0, 0 };
+ struct linkedit_data_command function_starts_load_command = { 0, 0, 0, 0 };
+ struct dyld_info_command dyld_info = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ typedef AddressDataArray<lldb::addr_t, bool, 100> FunctionStarts;
+ FunctionStarts function_starts;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ FileSpecList dylib_files;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS));
+ static const llvm::StringRef g_objc_v2_prefix_class ("_OBJC_CLASS_$_");
+ static const llvm::StringRef g_objc_v2_prefix_metaclass ("_OBJC_METACLASS_$_");
+ static const llvm::StringRef g_objc_v2_prefix_ivar ("_OBJC_IVAR_$_");
+
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const lldb::offset_t cmd_offset = offset;
+ // Read in the load command and load command size
+ struct load_command lc;
+ if (m_data.GetU32(&offset, &lc, 2) == NULL)
+ break;
+ // Watch for the symbol table load command
+ switch (lc.cmd)
+ {
+ case LC_SYMTAB:
+ symtab_load_command.cmd = lc.cmd;
+ symtab_load_command.cmdsize = lc.cmdsize;
+ // Read in the rest of the symtab load command
+ if (m_data.GetU32(&offset, &symtab_load_command.symoff, 4) == 0) // fill in symoff, nsyms, stroff, strsize fields
+ return 0;
+ if (symtab_load_command.symoff == 0)
+ {
+ if (log)
+ module_sp->LogMessage(log, "LC_SYMTAB.symoff == 0");
+ return 0;
+ }
+
+ if (symtab_load_command.stroff == 0)
+ {
+ if (log)
+ module_sp->LogMessage(log, "LC_SYMTAB.stroff == 0");
+ return 0;
+ }
+
+ if (symtab_load_command.nsyms == 0)
+ {
+ if (log)
+ module_sp->LogMessage(log, "LC_SYMTAB.nsyms == 0");
+ return 0;
+ }
+
+ if (symtab_load_command.strsize == 0)
+ {
+ if (log)
+ module_sp->LogMessage(log, "LC_SYMTAB.strsize == 0");
+ return 0;
+ }
+ break;
+
+ case LC_DYLD_INFO:
+ case LC_DYLD_INFO_ONLY:
+ if (m_data.GetU32(&offset, &dyld_info.rebase_off, 10))
+ {
+ dyld_info.cmd = lc.cmd;
+ dyld_info.cmdsize = lc.cmdsize;
+ }
+ else
+ {
+ memset (&dyld_info, 0, sizeof(dyld_info));
+ }
+ break;
+
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOADFVMLIB:
+ case LC_LOAD_UPWARD_DYLIB:
+ {
+ uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
+ const char *path = m_data.PeekCStr(name_offset);
+ if (path)
+ {
+ FileSpec file_spec(path, false);
+ // Strip the path if there is @rpath, @executable, etc so we just use the basename
+ if (path[0] == '@')
+ file_spec.GetDirectory().Clear();
+
+ if (lc.cmd == LC_REEXPORT_DYLIB)
+ {
+ m_reexported_dylibs.AppendIfUnique(file_spec);
+ }
+
+ dylib_files.Append(file_spec);
+ }
+ }
+ break;
+
+ case LC_FUNCTION_STARTS:
+ function_starts_load_command.cmd = lc.cmd;
+ function_starts_load_command.cmdsize = lc.cmdsize;
+ if (m_data.GetU32(&offset, &function_starts_load_command.dataoff, 2) == NULL) // fill in symoff, nsyms, stroff, strsize fields
+ memset (&function_starts_load_command, 0, sizeof(function_starts_load_command));
+ break;
+
+ default:
+ break;
+ }
+ offset = cmd_offset + lc.cmdsize;
+ }
+
+ if (symtab_load_command.cmd)
+ {
+ Symtab *symtab = m_symtab_ap.get();
+ SectionList *section_list = GetSectionList();
+ if (section_list == NULL)
+ return 0;
+
+ const uint32_t addr_byte_size = m_data.GetAddressByteSize();
+ const ByteOrder byte_order = m_data.GetByteOrder();
+ bool bit_width_32 = addr_byte_size == 4;
+ const size_t nlist_byte_size = bit_width_32 ? sizeof(struct nlist) : sizeof(struct nlist_64);
+
+ DataExtractor nlist_data (NULL, 0, byte_order, addr_byte_size);
+ DataExtractor strtab_data (NULL, 0, byte_order, addr_byte_size);
+ DataExtractor function_starts_data (NULL, 0, byte_order, addr_byte_size);
+ DataExtractor indirect_symbol_index_data (NULL, 0, byte_order, addr_byte_size);
+ DataExtractor dyld_trie_data (NULL, 0, byte_order, addr_byte_size);
+
+ const addr_t nlist_data_byte_size = symtab_load_command.nsyms * nlist_byte_size;
+ const addr_t strtab_data_byte_size = symtab_load_command.strsize;
+ addr_t strtab_addr = LLDB_INVALID_ADDRESS;
+
+ ProcessSP process_sp (m_process_wp.lock());
+ Process *process = process_sp.get();
+
+ uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete;
+
+ if (process && m_header.filetype != llvm::MachO::MH_OBJECT)
+ {
+ Target &target = process->GetTarget();
+
+ memory_module_load_level = target.GetMemoryModuleLoadLevel();
+
+ SectionSP linkedit_section_sp(section_list->FindSectionByName(GetSegmentNameLINKEDIT()));
+ // Reading mach file from memory in a process or core file...
+
+ if (linkedit_section_sp)
+ {
+ addr_t linkedit_load_addr = linkedit_section_sp->GetLoadBaseAddress(&target);
+ if (linkedit_load_addr == LLDB_INVALID_ADDRESS)
+ {
+ // We might be trying to access the symbol table before the __LINKEDIT's load
+ // address has been set in the target. We can't fail to read the symbol table,
+ // so calculate the right address manually
+ linkedit_load_addr = CalculateSectionLoadAddressForMemoryImage(m_memory_addr, GetMachHeaderSection(), linkedit_section_sp.get());
+ }
+
+ const addr_t linkedit_file_offset = linkedit_section_sp->GetFileOffset();
+ const addr_t symoff_addr = linkedit_load_addr + symtab_load_command.symoff - linkedit_file_offset;
+ strtab_addr = linkedit_load_addr + symtab_load_command.stroff - linkedit_file_offset;
+
+ bool data_was_read = false;
+
+#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__))
+ if (m_header.flags & 0x80000000u && process->GetAddressByteSize() == sizeof (void*))
+ {
+ // This mach-o memory file is in the dyld shared cache. If this
+ // program is not remote and this is iOS, then this process will
+ // share the same shared cache as the process we are debugging and
+ // we can read the entire __LINKEDIT from the address space in this
+ // process. This is a needed optimization that is used for local iOS
+ // debugging only since all shared libraries in the shared cache do
+ // not have corresponding files that exist in the file system of the
+ // device. They have been combined into a single file. This means we
+ // always have to load these files from memory. All of the symbol and
+ // string tables from all of the __LINKEDIT sections from the shared
+ // libraries in the shared cache have been merged into a single large
+ // symbol and string table. Reading all of this symbol and string table
+ // data across can slow down debug launch times, so we optimize this by
+ // reading the memory for the __LINKEDIT section from this process.
+
+ UUID lldb_shared_cache(GetLLDBSharedCacheUUID());
+ UUID process_shared_cache(GetProcessSharedCacheUUID(process));
+ bool use_lldb_cache = true;
+ if (lldb_shared_cache.IsValid() && process_shared_cache.IsValid() && lldb_shared_cache != process_shared_cache)
+ {
+ use_lldb_cache = false;
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ module_sp->ReportWarning ("shared cache in process does not match lldb's own shared cache, startup will be slow.");
+
+ }
+
+ PlatformSP platform_sp (target.GetPlatform());
+ if (platform_sp && platform_sp->IsHost() && use_lldb_cache)
+ {
+ data_was_read = true;
+ nlist_data.SetData((void *)symoff_addr, nlist_data_byte_size, eByteOrderLittle);
+ strtab_data.SetData((void *)strtab_addr, strtab_data_byte_size, eByteOrderLittle);
+ if (function_starts_load_command.cmd)
+ {
+ const addr_t func_start_addr = linkedit_load_addr + function_starts_load_command.dataoff - linkedit_file_offset;
+ function_starts_data.SetData ((void *)func_start_addr, function_starts_load_command.datasize, eByteOrderLittle);
+ }
+ }
+ }
+#endif
+
+ if (!data_was_read)
+ {
+ if (memory_module_load_level == eMemoryModuleLoadLevelComplete)
+ {
+ DataBufferSP nlist_data_sp (ReadMemory (process_sp, symoff_addr, nlist_data_byte_size));
+ if (nlist_data_sp)
+ nlist_data.SetData (nlist_data_sp, 0, nlist_data_sp->GetByteSize());
+ // Load strings individually from memory when loading from memory since shared cache
+ // string tables contain strings for all symbols from all shared cached libraries
+ //DataBufferSP strtab_data_sp (ReadMemory (process_sp, strtab_addr, strtab_data_byte_size));
+ //if (strtab_data_sp)
+ // strtab_data.SetData (strtab_data_sp, 0, strtab_data_sp->GetByteSize());
+ if (m_dysymtab.nindirectsyms != 0)
+ {
+ const addr_t indirect_syms_addr = linkedit_load_addr + m_dysymtab.indirectsymoff - linkedit_file_offset;
+ DataBufferSP indirect_syms_data_sp (ReadMemory (process_sp, indirect_syms_addr, m_dysymtab.nindirectsyms * 4));
+ if (indirect_syms_data_sp)
+ indirect_symbol_index_data.SetData (indirect_syms_data_sp, 0, indirect_syms_data_sp->GetByteSize());
+ }
+ }
+
+ if (memory_module_load_level >= eMemoryModuleLoadLevelPartial)
+ {
+ if (function_starts_load_command.cmd)
+ {
+ const addr_t func_start_addr = linkedit_load_addr + function_starts_load_command.dataoff - linkedit_file_offset;
+ DataBufferSP func_start_data_sp (ReadMemory (process_sp, func_start_addr, function_starts_load_command.datasize));
+ if (func_start_data_sp)
+ function_starts_data.SetData (func_start_data_sp, 0, func_start_data_sp->GetByteSize());
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ nlist_data.SetData (m_data,
+ symtab_load_command.symoff,
+ nlist_data_byte_size);
+ strtab_data.SetData (m_data,
+ symtab_load_command.stroff,
+ strtab_data_byte_size);
+
+ if (dyld_info.export_size > 0)
+ {
+ dyld_trie_data.SetData (m_data,
+ dyld_info.export_off,
+ dyld_info.export_size);
+ }
+
+ if (m_dysymtab.nindirectsyms != 0)
+ {
+ indirect_symbol_index_data.SetData (m_data,
+ m_dysymtab.indirectsymoff,
+ m_dysymtab.nindirectsyms * 4);
+ }
+ if (function_starts_load_command.cmd)
+ {
+ function_starts_data.SetData (m_data,
+ function_starts_load_command.dataoff,
+ function_starts_load_command.datasize);
+ }
+ }
+
+ if (nlist_data.GetByteSize() == 0 && memory_module_load_level == eMemoryModuleLoadLevelComplete)
+ {
+ if (log)
+ module_sp->LogMessage(log, "failed to read nlist data");
+ return 0;
+ }
+
+ const bool have_strtab_data = strtab_data.GetByteSize() > 0;
+ if (!have_strtab_data)
+ {
+ if (process)
+ {
+ if (strtab_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ module_sp->LogMessage(log, "failed to locate the strtab in memory");
+ return 0;
+ }
+ }
+ else
+ {
+ if (log)
+ module_sp->LogMessage(log, "failed to read strtab data");
+ return 0;
+ }
+ }
+
+ const ConstString &g_segment_name_TEXT = GetSegmentNameTEXT();
+ const ConstString &g_segment_name_DATA = GetSegmentNameDATA();
+ const ConstString &g_segment_name_DATA_DIRTY = GetSegmentNameDATA_DIRTY();
+ const ConstString &g_segment_name_DATA_CONST = GetSegmentNameDATA_CONST();
+ const ConstString &g_segment_name_OBJC = GetSegmentNameOBJC();
+ const ConstString &g_section_name_eh_frame = GetSectionNameEHFrame();
+ SectionSP text_section_sp(section_list->FindSectionByName(g_segment_name_TEXT));
+ SectionSP data_section_sp(section_list->FindSectionByName(g_segment_name_DATA));
+ SectionSP data_dirty_section_sp(section_list->FindSectionByName(g_segment_name_DATA_DIRTY));
+ SectionSP data_const_section_sp(section_list->FindSectionByName(g_segment_name_DATA_CONST));
+ SectionSP objc_section_sp(section_list->FindSectionByName(g_segment_name_OBJC));
+ SectionSP eh_frame_section_sp;
+ if (text_section_sp.get())
+ eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName (g_section_name_eh_frame);
+ else
+ eh_frame_section_sp = section_list->FindSectionByName (g_section_name_eh_frame);
+
+ const bool is_arm = (m_header.cputype == llvm::MachO::CPU_TYPE_ARM);
+
+ // lldb works best if it knows the start address of all functions in a module.
+ // Linker symbols or debug info are normally the best source of information for start addr / size but
+ // they may be stripped in a released binary.
+ // Two additional sources of information exist in Mach-O binaries:
+ // LC_FUNCTION_STARTS - a list of ULEB128 encoded offsets of each function's start address in the
+ // binary, relative to the text section.
+ // eh_frame - the eh_frame FDEs have the start addr & size of each function
+ // LC_FUNCTION_STARTS is the fastest source to read in, and is present on all modern binaries.
+ // Binaries built to run on older releases may need to use eh_frame information.
+
+ if (text_section_sp && function_starts_data.GetByteSize())
+ {
+ FunctionStarts::Entry function_start_entry;
+ function_start_entry.data = false;
+ lldb::offset_t function_start_offset = 0;
+ function_start_entry.addr = text_section_sp->GetFileAddress();
+ uint64_t delta;
+ while ((delta = function_starts_data.GetULEB128(&function_start_offset)) > 0)
+ {
+ // Now append the current entry
+ function_start_entry.addr += delta;
+ function_starts.Append(function_start_entry);
+ }
+ }
+ else
+ {
+ // If m_type is eTypeDebugInfo, then this is a dSYM - it will have the load command claiming an eh_frame
+ // but it doesn't actually have the eh_frame content. And if we have a dSYM, we don't need to do any
+ // of this fill-in-the-missing-symbols works anyway - the debug info should give us all the functions in
+ // the module.
+ if (text_section_sp.get() && eh_frame_section_sp.get() && m_type != eTypeDebugInfo)
+ {
+ DWARFCallFrameInfo eh_frame(*this, eh_frame_section_sp, eRegisterKindEHFrame, true);
+ DWARFCallFrameInfo::FunctionAddressAndSizeVector functions;
+ eh_frame.GetFunctionAddressAndSizeVector (functions);
+ addr_t text_base_addr = text_section_sp->GetFileAddress();
+ size_t count = functions.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ const DWARFCallFrameInfo::FunctionAddressAndSizeVector::Entry *func = functions.GetEntryAtIndex (i);
+ if (func)
+ {
+ FunctionStarts::Entry function_start_entry;
+ function_start_entry.addr = func->base - text_base_addr;
+ function_starts.Append(function_start_entry);
+ }
+ }
+ }
+ }
+
+ const size_t function_starts_count = function_starts.GetSize();
+
+ const user_id_t TEXT_eh_frame_sectID =
+ eh_frame_section_sp.get() ? eh_frame_section_sp->GetID()
+ : static_cast<user_id_t>(NO_SECT);
+
+ lldb::offset_t nlist_data_offset = 0;
+
+ uint32_t N_SO_index = UINT32_MAX;
+
+ MachSymtabSectionInfo section_info (section_list);
+ std::vector<uint32_t> N_FUN_indexes;
+ std::vector<uint32_t> N_NSYM_indexes;
+ std::vector<uint32_t> N_INCL_indexes;
+ std::vector<uint32_t> N_BRAC_indexes;
+ std::vector<uint32_t> N_COMM_indexes;
+ typedef std::multimap <uint64_t, uint32_t> ValueToSymbolIndexMap;
+ typedef std::map <uint32_t, uint32_t> NListIndexToSymbolIndexMap;
+ typedef std::map <const char *, uint32_t> ConstNameToSymbolIndexMap;
+ ValueToSymbolIndexMap N_FUN_addr_to_sym_idx;
+ ValueToSymbolIndexMap N_STSYM_addr_to_sym_idx;
+ ConstNameToSymbolIndexMap N_GSYM_name_to_sym_idx;
+ // Any symbols that get merged into another will get an entry
+ // in this map so we know
+ NListIndexToSymbolIndexMap m_nlist_idx_to_sym_idx;
+ uint32_t nlist_idx = 0;
+ Symbol *symbol_ptr = NULL;
+
+ uint32_t sym_idx = 0;
+ Symbol *sym = NULL;
+ size_t num_syms = 0;
+ std::string memory_symbol_name;
+ uint32_t unmapped_local_symbols_found = 0;
+
+ std::vector<TrieEntryWithOffset> trie_entries;
+ std::set<lldb::addr_t> resolver_addresses;
+
+ if (dyld_trie_data.GetByteSize() > 0)
+ {
+ std::vector<llvm::StringRef> nameSlices;
+ ParseTrieEntries (dyld_trie_data,
+ 0,
+ is_arm,
+ nameSlices,
+ resolver_addresses,
+ trie_entries);
+
+ ConstString text_segment_name ("__TEXT");
+ SectionSP text_segment_sp = GetSectionList()->FindSectionByName(text_segment_name);
+ if (text_segment_sp)
+ {
+ const lldb::addr_t text_segment_file_addr = text_segment_sp->GetFileAddress();
+ if (text_segment_file_addr != LLDB_INVALID_ADDRESS)
+ {
+ for (auto &e : trie_entries)
+ e.entry.address += text_segment_file_addr;
+ }
+ }
+ }
+
+ typedef std::set<ConstString> IndirectSymbols;
+ IndirectSymbols indirect_symbol_names;
+
+#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__))
+
+ // Some recent builds of the dyld_shared_cache (hereafter: DSC) have been optimized by moving LOCAL
+ // symbols out of the memory mapped portion of the DSC. The symbol information has all been retained,
+ // but it isn't available in the normal nlist data. However, there *are* duplicate entries of *some*
+ // LOCAL symbols in the normal nlist data. To handle this situation correctly, we must first attempt
+ // to parse any DSC unmapped symbol information. If we find any, we set a flag that tells the normal
+ // nlist parser to ignore all LOCAL symbols.
+
+ if (m_header.flags & 0x80000000u)
+ {
+ // Before we can start mapping the DSC, we need to make certain the target process is actually
+ // using the cache we can find.
+
+ // Next we need to determine the correct path for the dyld shared cache.
+
+ ArchSpec header_arch;
+ GetArchitecture(header_arch);
+ char dsc_path[PATH_MAX];
+ char dsc_path_development[PATH_MAX];
+
+ snprintf(dsc_path, sizeof(dsc_path), "%s%s%s",
+ "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR */
+ "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */
+ header_arch.GetArchitectureName());
+
+ snprintf(dsc_path_development, sizeof(dsc_path), "%s%s%s%s",
+ "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR */
+ "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */
+ header_arch.GetArchitectureName(),
+ ".development");
+
+ FileSpec dsc_nondevelopment_filespec(dsc_path, false);
+ FileSpec dsc_development_filespec(dsc_path_development, false);
+ FileSpec dsc_filespec;
+
+ UUID dsc_uuid;
+ UUID process_shared_cache_uuid;
+
+ if (process)
+ {
+ process_shared_cache_uuid = GetProcessSharedCacheUUID(process);
+ }
+
+ // First see if we can find an exact match for the inferior process shared cache UUID in
+ // the development or non-development shared caches on disk.
+ if (process_shared_cache_uuid.IsValid())
+ {
+ if (dsc_development_filespec.Exists())
+ {
+ UUID dsc_development_uuid = GetSharedCacheUUID (dsc_development_filespec, byte_order, addr_byte_size);
+ if (dsc_development_uuid.IsValid() && dsc_development_uuid == process_shared_cache_uuid)
+ {
+ dsc_filespec = dsc_development_filespec;
+ dsc_uuid = dsc_development_uuid;
+ }
+ }
+ if (!dsc_uuid.IsValid() && dsc_nondevelopment_filespec.Exists())
+ {
+ UUID dsc_nondevelopment_uuid = GetSharedCacheUUID (dsc_nondevelopment_filespec, byte_order, addr_byte_size);
+ if (dsc_nondevelopment_uuid.IsValid() && dsc_nondevelopment_uuid == process_shared_cache_uuid)
+ {
+ dsc_filespec = dsc_nondevelopment_filespec;
+ dsc_uuid = dsc_nondevelopment_uuid;
+ }
+ }
+ }
+
+ // Failing a UUID match, prefer the development dyld_shared cache if both are present.
+ if (!dsc_filespec.Exists())
+ {
+ if (dsc_development_filespec.Exists())
+ {
+ dsc_filespec = dsc_development_filespec;
+ }
+ else
+ {
+ dsc_filespec = dsc_nondevelopment_filespec;
+ }
+ }
+
+ /* The dyld_cache_header has a pointer to the dyld_cache_local_symbols_info structure (localSymbolsOffset).
+ The dyld_cache_local_symbols_info structure gives us three things:
+ 1. The start and count of the nlist records in the dyld_shared_cache file
+ 2. The start and size of the strings for these nlist records
+ 3. The start and count of dyld_cache_local_symbols_entry entries
+
+ There is one dyld_cache_local_symbols_entry per dylib/framework in the dyld shared cache.
+ The "dylibOffset" field is the Mach-O header of this dylib/framework in the dyld shared cache.
+ The dyld_cache_local_symbols_entry also lists the start of this dylib/framework's nlist records
+ and the count of how many nlist records there are for this dylib/framework.
+ */
+
+ // Process the dyld shared cache header to find the unmapped symbols
+
+ DataBufferSP dsc_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(0, sizeof(struct lldb_copy_dyld_cache_header_v1));
+ if (!dsc_uuid.IsValid())
+ {
+ dsc_uuid = GetSharedCacheUUID (dsc_filespec, byte_order, addr_byte_size);
+ }
+ if (dsc_data_sp)
+ {
+ DataExtractor dsc_header_data (dsc_data_sp, byte_order, addr_byte_size);
+
+ bool uuid_match = true;
+ if (dsc_uuid.IsValid() && process)
+ {
+ if (process_shared_cache_uuid.IsValid() && dsc_uuid != process_shared_cache_uuid)
+ {
+ // The on-disk dyld_shared_cache file is not the same as the one in this
+ // process' memory, don't use it.
+ uuid_match = false;
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ module_sp->ReportWarning ("process shared cache does not match on-disk dyld_shared_cache file, some symbol names will be missing.");
+ }
+ }
+
+ offset = offsetof (struct lldb_copy_dyld_cache_header_v1, mappingOffset);
+
+ uint32_t mappingOffset = dsc_header_data.GetU32(&offset);
+
+ // If the mappingOffset points to a location inside the header, we've
+ // opened an old dyld shared cache, and should not proceed further.
+ if (uuid_match && mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v1))
+ {
+
+ DataBufferSP dsc_mapping_info_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(mappingOffset, sizeof (struct lldb_copy_dyld_cache_mapping_info));
+ DataExtractor dsc_mapping_info_data(dsc_mapping_info_data_sp, byte_order, addr_byte_size);
+ offset = 0;
+
+ // The File addresses (from the in-memory Mach-O load commands) for the shared libraries
+ // in the shared library cache need to be adjusted by an offset to match up with the
+ // dylibOffset identifying field in the dyld_cache_local_symbol_entry's. This offset is
+ // recorded in mapping_offset_value.
+ const uint64_t mapping_offset_value = dsc_mapping_info_data.GetU64(&offset);
+
+ offset = offsetof (struct lldb_copy_dyld_cache_header_v1, localSymbolsOffset);
+ uint64_t localSymbolsOffset = dsc_header_data.GetU64(&offset);
+ uint64_t localSymbolsSize = dsc_header_data.GetU64(&offset);
+
+ if (localSymbolsOffset && localSymbolsSize)
+ {
+ // Map the local symbols
+ if (DataBufferSP dsc_local_symbols_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(localSymbolsOffset, localSymbolsSize))
+ {
+ DataExtractor dsc_local_symbols_data(dsc_local_symbols_data_sp, byte_order, addr_byte_size);
+
+ offset = 0;
+
+ typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap;
+ typedef std::map<uint32_t, ConstString> SymbolIndexToName;
+ UndefinedNameToDescMap undefined_name_to_desc;
+ SymbolIndexToName reexport_shlib_needs_fixup;
+
+
+ // Read the local_symbols_infos struct in one shot
+ struct lldb_copy_dyld_cache_local_symbols_info local_symbols_info;
+ dsc_local_symbols_data.GetU32(&offset, &local_symbols_info.nlistOffset, 6);
+
+ SectionSP text_section_sp(section_list->FindSectionByName(GetSegmentNameTEXT()));
+
+ uint32_t header_file_offset = (text_section_sp->GetFileAddress() - mapping_offset_value);
+
+ offset = local_symbols_info.entriesOffset;
+ for (uint32_t entry_index = 0; entry_index < local_symbols_info.entriesCount; entry_index++)
+ {
+ struct lldb_copy_dyld_cache_local_symbols_entry local_symbols_entry;
+ local_symbols_entry.dylibOffset = dsc_local_symbols_data.GetU32(&offset);
+ local_symbols_entry.nlistStartIndex = dsc_local_symbols_data.GetU32(&offset);
+ local_symbols_entry.nlistCount = dsc_local_symbols_data.GetU32(&offset);
+
+ if (header_file_offset == local_symbols_entry.dylibOffset)
+ {
+ unmapped_local_symbols_found = local_symbols_entry.nlistCount;
+
+ // The normal nlist code cannot correctly size the Symbols array, we need to allocate it here.
+ sym = symtab->Resize (symtab_load_command.nsyms + m_dysymtab.nindirectsyms + unmapped_local_symbols_found - m_dysymtab.nlocalsym);
+ num_syms = symtab->GetNumSymbols();
+
+ nlist_data_offset = local_symbols_info.nlistOffset + (nlist_byte_size * local_symbols_entry.nlistStartIndex);
+ uint32_t string_table_offset = local_symbols_info.stringsOffset;
+
+ for (uint32_t nlist_index = 0; nlist_index < local_symbols_entry.nlistCount; nlist_index++)
+ {
+ /////////////////////////////
+ {
+ struct nlist_64 nlist;
+ if (!dsc_local_symbols_data.ValidOffsetForDataOfSize(nlist_data_offset, nlist_byte_size))
+ break;
+
+ nlist.n_strx = dsc_local_symbols_data.GetU32_unchecked(&nlist_data_offset);
+ nlist.n_type = dsc_local_symbols_data.GetU8_unchecked (&nlist_data_offset);
+ nlist.n_sect = dsc_local_symbols_data.GetU8_unchecked (&nlist_data_offset);
+ nlist.n_desc = dsc_local_symbols_data.GetU16_unchecked (&nlist_data_offset);
+ nlist.n_value = dsc_local_symbols_data.GetAddress_unchecked (&nlist_data_offset);
+
+ SymbolType type = eSymbolTypeInvalid;
+ const char *symbol_name = dsc_local_symbols_data.PeekCStr(string_table_offset + nlist.n_strx);
+
+ if (symbol_name == NULL)
+ {
+ // No symbol should be NULL, even the symbols with no
+ // string values should have an offset zero which points
+ // to an empty C-string
+ Host::SystemLog (Host::eSystemLogError,
+ "error: DSC unmapped local symbol[%u] has invalid string table offset 0x%x in %s, ignoring symbol\n",
+ entry_index,
+ nlist.n_strx,
+ module_sp->GetFileSpec().GetPath().c_str());
+ continue;
+ }
+ if (symbol_name[0] == '\0')
+ symbol_name = NULL;
+
+ const char *symbol_name_non_abi_mangled = NULL;
+
+ SectionSP symbol_section;
+ uint32_t symbol_byte_size = 0;
+ bool add_nlist = true;
+ bool is_debug = ((nlist.n_type & N_STAB) != 0);
+ bool demangled_is_synthesized = false;
+ bool is_gsym = false;
+ bool set_value = true;
+
+ assert (sym_idx < num_syms);
+
+ sym[sym_idx].SetDebug (is_debug);
+
+ if (is_debug)
+ {
+ switch (nlist.n_type)
+ {
+ case N_GSYM:
+ // global symbol: name,,NO_SECT,type,0
+ // Sometimes the N_GSYM value contains the address.
+
+ // FIXME: In the .o files, we have a GSYM and a debug symbol for all the ObjC data. They
+ // have the same address, but we want to ensure that we always find only the real symbol,
+ // 'cause we don't currently correctly attribute the GSYM one to the ObjCClass/Ivar/MetaClass
+ // symbol type. This is a temporary hack to make sure the ObjectiveC symbols get treated
+ // correctly. To do this right, we should coalesce all the GSYM & global symbols that have the
+ // same address.
+
+ is_gsym = true;
+ sym[sym_idx].SetExternal(true);
+
+ if (symbol_name && symbol_name[0] == '_' && symbol_name[1] == 'O')
+ {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ if (symbol_name_ref.startswith(g_objc_v2_prefix_class))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+
+ }
+ else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size();
+ type = eSymbolTypeObjCMetaClass;
+ demangled_is_synthesized = true;
+ }
+ else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_ivar.size();
+ type = eSymbolTypeObjCIVar;
+ demangled_is_synthesized = true;
+ }
+ }
+ else
+ {
+ if (nlist.n_value != 0)
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeData;
+ }
+ break;
+
+ case N_FNAME:
+ // procedure name (f77 kludge): name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_FUN:
+ // procedure: name,,n_sect,linenumber,address
+ if (symbol_name)
+ {
+ type = eSymbolTypeCode;
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+
+ N_FUN_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx));
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_FUN_indexes.push_back(sym_idx);
+ }
+ else
+ {
+ type = eSymbolTypeCompiler;
+
+ if ( !N_FUN_indexes.empty() )
+ {
+ // Copy the size of the function into the original STAB entry so we don't have
+ // to hunt for it later
+ symtab->SymbolAtIndex(N_FUN_indexes.back())->SetByteSize(nlist.n_value);
+ N_FUN_indexes.pop_back();
+ // We don't really need the end function STAB as it contains the size which
+ // we already placed with the original symbol, so don't add it if we want a
+ // minimal symbol table
+ add_nlist = false;
+ }
+ }
+ break;
+
+ case N_STSYM:
+ // static symbol: name,,n_sect,type,address
+ N_STSYM_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx));
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ if (symbol_name && symbol_name[0])
+ {
+ type = ObjectFile::GetSymbolTypeFromName(symbol_name+1, eSymbolTypeData);
+ }
+ break;
+
+ case N_LCSYM:
+ // .lcomm symbol: name,,n_sect,type,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeCommonBlock;
+ break;
+
+ case N_BNSYM:
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ break;
+
+ case N_ENSYM:
+ // Set the size of the N_BNSYM to the terminating index of this N_ENSYM
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ break;
+
+ case N_OPT:
+ // emitted with gcc2_compiled and in gcc source
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_RSYM:
+ // register sym: name,,NO_SECT,type,register
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_SLINE:
+ // src line: 0,,n_sect,linenumber,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ case N_SSYM:
+ // structure elt: name,,NO_SECT,type,struct_offset
+ type = eSymbolTypeVariableType;
+ break;
+
+ case N_SO:
+ // source file name
+ type = eSymbolTypeSourceFile;
+ if (symbol_name == NULL)
+ {
+ add_nlist = false;
+ if (N_SO_index != UINT32_MAX)
+ {
+ // Set the size of the N_SO to the terminating index of this N_SO
+ // so that we can always skip the entire N_SO if we need to navigate
+ // more quickly at the source level when parsing STABS
+ symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
+ symbol_ptr->SetByteSize(sym_idx);
+ symbol_ptr->SetSizeIsSibling(true);
+ }
+ N_NSYM_indexes.clear();
+ N_INCL_indexes.clear();
+ N_BRAC_indexes.clear();
+ N_COMM_indexes.clear();
+ N_FUN_indexes.clear();
+ N_SO_index = UINT32_MAX;
+ }
+ else
+ {
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ const bool N_SO_has_full_path = symbol_name[0] == '/';
+ if (N_SO_has_full_path)
+ {
+ if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms))
+ {
+ // We have two consecutive N_SO entries where the first contains a directory
+ // and the second contains a full path.
+ sym[sym_idx - 1].GetMangled().SetValue(ConstString(symbol_name), false);
+ m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
+ add_nlist = false;
+ }
+ else
+ {
+ // This is the first entry in a N_SO that contains a directory or
+ // a full path to the source file
+ N_SO_index = sym_idx;
+ }
+ }
+ else if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms))
+ {
+ // This is usually the second N_SO entry that contains just the filename,
+ // so here we combine it with the first one if we are minimizing the symbol table
+ const char *so_path = sym[sym_idx - 1].GetMangled().GetDemangledName().AsCString();
+ if (so_path && so_path[0])
+ {
+ std::string full_so_path (so_path);
+ const size_t double_slash_pos = full_so_path.find("//");
+ if (double_slash_pos != std::string::npos)
+ {
+ // The linker has been generating bad N_SO entries with doubled up paths
+ // in the format "%s%s" where the first string in the DW_AT_comp_dir,
+ // and the second is the directory for the source file so you end up with
+ // a path that looks like "/tmp/src//tmp/src/"
+ FileSpec so_dir(so_path, false);
+ if (!so_dir.Exists())
+ {
+ so_dir.SetFile(&full_so_path[double_slash_pos + 1], false);
+ if (so_dir.Exists())
+ {
+ // Trim off the incorrect path
+ full_so_path.erase(0, double_slash_pos + 1);
+ }
+ }
+ }
+ if (*full_so_path.rbegin() != '/')
+ full_so_path += '/';
+ full_so_path += symbol_name;
+ sym[sym_idx - 1].GetMangled().SetValue(ConstString(full_so_path.c_str()), false);
+ add_nlist = false;
+ m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
+ }
+ }
+ else
+ {
+ // This could be a relative path to a N_SO
+ N_SO_index = sym_idx;
+ }
+ }
+ break;
+
+ case N_OSO:
+ // object file name: name,,0,0,st_mtime
+ type = eSymbolTypeObjectFile;
+ break;
+
+ case N_LSYM:
+ // local sym: name,,NO_SECT,type,offset
+ type = eSymbolTypeLocal;
+ break;
+
+ //----------------------------------------------------------------------
+ // INCL scopes
+ //----------------------------------------------------------------------
+ case N_BINCL:
+ // include file beginning: name,,NO_SECT,0,sum
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_INCL_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+
+ case N_EINCL:
+ // include file end: name,,NO_SECT,0,0
+ // Set the size of the N_BINCL to the terminating index of this N_EINCL
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ if ( !N_INCL_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_INCL_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_SOL:
+ // #included file name: name,,n_sect,0,address
+ type = eSymbolTypeHeaderFile;
+
+ // We currently don't use the header files on darwin
+ add_nlist = false;
+ break;
+
+ case N_PARAMS:
+ // compiler parameters: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_VERSION:
+ // compiler version: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_OLEVEL:
+ // compiler -O level: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_PSYM:
+ // parameter: name,,NO_SECT,type,offset
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_ENTRY:
+ // alternate entry: name,,n_sect,linenumber,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ //----------------------------------------------------------------------
+ // Left and Right Braces
+ //----------------------------------------------------------------------
+ case N_LBRAC:
+ // left bracket: 0,,NO_SECT,nesting level,address
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ N_BRAC_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+
+ case N_RBRAC:
+ // right bracket: 0,,NO_SECT,nesting level,address
+ // Set the size of the N_LBRAC to the terminating index of this N_RBRAC
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ if ( !N_BRAC_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_BRAC_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_EXCL:
+ // deleted include file: name,,NO_SECT,0,sum
+ type = eSymbolTypeHeaderFile;
+ break;
+
+ //----------------------------------------------------------------------
+ // COMM scopes
+ //----------------------------------------------------------------------
+ case N_BCOMM:
+ // begin common: name,,NO_SECT,0,0
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ type = eSymbolTypeScopeBegin;
+ N_COMM_indexes.push_back(sym_idx);
+ break;
+
+ case N_ECOML:
+ // end common (local name): 0,,n_sect,0,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ // Fall through
+
+ case N_ECOMM:
+ // end common: name,,n_sect,0,0
+ // Set the size of the N_BCOMM to the terminating index of this N_ECOMM/N_ECOML
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ if ( !N_COMM_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_COMM_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_LENG:
+ // second stab entry with length information
+ type = eSymbolTypeAdditional;
+ break;
+
+ default: break;
+ }
+ }
+ else
+ {
+ //uint8_t n_pext = N_PEXT & nlist.n_type;
+ uint8_t n_type = N_TYPE & nlist.n_type;
+ sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0);
+
+ switch (n_type)
+ {
+ case N_INDR:
+ {
+ const char *reexport_name_cstr = strtab_data.PeekCStr(nlist.n_value);
+ if (reexport_name_cstr && reexport_name_cstr[0])
+ {
+ type = eSymbolTypeReExported;
+ ConstString reexport_name(reexport_name_cstr + ((reexport_name_cstr[0] == '_') ? 1 : 0));
+ sym[sym_idx].SetReExportedSymbolName(reexport_name);
+ set_value = false;
+ reexport_shlib_needs_fixup[sym_idx] = reexport_name;
+ indirect_symbol_names.insert(ConstString(symbol_name + ((symbol_name[0] == '_') ? 1 : 0)));
+ }
+ else
+ type = eSymbolTypeUndefined;
+ }
+ break;
+
+ case N_UNDF:
+ if (symbol_name && symbol_name[0])
+ {
+ ConstString undefined_name(symbol_name + ((symbol_name[0] == '_') ? 1 : 0));
+ undefined_name_to_desc[undefined_name] = nlist.n_desc;
+ }
+ // Fall through
+ case N_PBUD:
+ type = eSymbolTypeUndefined;
+ break;
+
+ case N_ABS:
+ type = eSymbolTypeAbsolute;
+ break;
+
+ case N_SECT:
+ {
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+
+ if (symbol_section == NULL)
+ {
+ // TODO: warn about this?
+ add_nlist = false;
+ break;
+ }
+
+ if (TEXT_eh_frame_sectID == nlist.n_sect)
+ {
+ type = eSymbolTypeException;
+ }
+ else
+ {
+ uint32_t section_type = symbol_section->Get() & SECTION_TYPE;
+
+ switch (section_type)
+ {
+ case S_CSTRING_LITERALS: type = eSymbolTypeData; break; // section with only literal C strings
+ case S_4BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 4 byte literals
+ case S_8BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 8 byte literals
+ case S_LITERAL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only pointers to literals
+ case S_NON_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only non-lazy symbol pointers
+ case S_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only lazy symbol pointers
+ case S_SYMBOL_STUBS: type = eSymbolTypeTrampoline; break; // section with only symbol stubs, byte size of stub in the reserved2 field
+ case S_MOD_INIT_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for initialization
+ case S_MOD_TERM_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for termination
+ case S_INTERPOSING: type = eSymbolTypeTrampoline; break; // section with only pairs of function pointers for interposing
+ case S_16BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 16 byte literals
+ case S_DTRACE_DOF: type = eSymbolTypeInstrumentation; break;
+ case S_LAZY_DYLIB_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break;
+ default:
+ switch (symbol_section->GetType())
+ {
+ case lldb::eSectionTypeCode:
+ type = eSymbolTypeCode;
+ break;
+ case eSectionTypeData:
+ case eSectionTypeDataCString: // Inlined C string data
+ case eSectionTypeDataCStringPointers: // Pointers to C string data
+ case eSectionTypeDataSymbolAddress: // Address of a symbol in the symbol table
+ case eSectionTypeData4:
+ case eSectionTypeData8:
+ case eSectionTypeData16:
+ type = eSymbolTypeData;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (type == eSymbolTypeInvalid)
+ {
+ const char *symbol_sect_name = symbol_section->GetName().AsCString();
+ if (symbol_section->IsDescendant (text_section_sp.get()))
+ {
+ if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS |
+ S_ATTR_SELF_MODIFYING_CODE |
+ S_ATTR_SOME_INSTRUCTIONS))
+ type = eSymbolTypeData;
+ else
+ type = eSymbolTypeCode;
+ }
+ else if (symbol_section->IsDescendant(data_section_sp.get()) ||
+ symbol_section->IsDescendant(data_dirty_section_sp.get()) ||
+ symbol_section->IsDescendant(data_const_section_sp.get()))
+ {
+ if (symbol_sect_name && ::strstr (symbol_sect_name, "__objc") == symbol_sect_name)
+ {
+ type = eSymbolTypeRuntime;
+
+ if (symbol_name)
+ {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ if (symbol_name_ref.startswith("_OBJC_"))
+ {
+ static const llvm::StringRef g_objc_v2_prefix_class ("_OBJC_CLASS_$_");
+ static const llvm::StringRef g_objc_v2_prefix_metaclass ("_OBJC_METACLASS_$_");
+ static const llvm::StringRef g_objc_v2_prefix_ivar ("_OBJC_IVAR_$_");
+ if (symbol_name_ref.startswith(g_objc_v2_prefix_class))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+ }
+ else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size();
+ type = eSymbolTypeObjCMetaClass;
+ demangled_is_synthesized = true;
+ }
+ else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_ivar.size();
+ type = eSymbolTypeObjCIVar;
+ demangled_is_synthesized = true;
+ }
+ }
+ }
+ }
+ else if (symbol_sect_name && ::strstr (symbol_sect_name, "__gcc_except_tab") == symbol_sect_name)
+ {
+ type = eSymbolTypeException;
+ }
+ else
+ {
+ type = eSymbolTypeData;
+ }
+ }
+ else if (symbol_sect_name && ::strstr (symbol_sect_name, "__IMPORT") == symbol_sect_name)
+ {
+ type = eSymbolTypeTrampoline;
+ }
+ else if (symbol_section->IsDescendant(objc_section_sp.get()))
+ {
+ type = eSymbolTypeRuntime;
+ if (symbol_name && symbol_name[0] == '.')
+ {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ static const llvm::StringRef g_objc_v1_prefix_class (".objc_class_name_");
+ if (symbol_name_ref.startswith(g_objc_v1_prefix_class))
+ {
+ symbol_name_non_abi_mangled = symbol_name;
+ symbol_name = symbol_name + g_objc_v1_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (add_nlist)
+ {
+ uint64_t symbol_value = nlist.n_value;
+ if (symbol_name_non_abi_mangled)
+ {
+ sym[sym_idx].GetMangled().SetMangledName (ConstString(symbol_name_non_abi_mangled));
+ sym[sym_idx].GetMangled().SetDemangledName (ConstString(symbol_name));
+ }
+ else
+ {
+ bool symbol_name_is_mangled = false;
+
+ if (symbol_name && symbol_name[0] == '_')
+ {
+ symbol_name_is_mangled = symbol_name[1] == '_';
+ symbol_name++; // Skip the leading underscore
+ }
+
+ if (symbol_name)
+ {
+ ConstString const_symbol_name(symbol_name);
+ sym[sym_idx].GetMangled().SetValue(const_symbol_name, symbol_name_is_mangled);
+ if (is_gsym && is_debug)
+ {
+ const char *gsym_name = sym[sym_idx].GetMangled().GetName(Mangled::ePreferMangled).GetCString();
+ if (gsym_name)
+ N_GSYM_name_to_sym_idx[gsym_name] = sym_idx;
+ }
+ }
+ }
+ if (symbol_section)
+ {
+ const addr_t section_file_addr = symbol_section->GetFileAddress();
+ if (symbol_byte_size == 0 && function_starts_count > 0)
+ {
+ addr_t symbol_lookup_file_addr = nlist.n_value;
+ // Do an exact address match for non-ARM addresses, else get the closest since
+ // the symbol might be a thumb symbol which has an address with bit zero set
+ FunctionStarts::Entry *func_start_entry = function_starts.FindEntry (symbol_lookup_file_addr, !is_arm);
+ if (is_arm && func_start_entry)
+ {
+ // Verify that the function start address is the symbol address (ARM)
+ // or the symbol address + 1 (thumb)
+ if (func_start_entry->addr != symbol_lookup_file_addr &&
+ func_start_entry->addr != (symbol_lookup_file_addr + 1))
+ {
+ // Not the right entry, NULL it out...
+ func_start_entry = NULL;
+ }
+ }
+ if (func_start_entry)
+ {
+ func_start_entry->data = true;
+
+ addr_t symbol_file_addr = func_start_entry->addr;
+ uint32_t symbol_flags = 0;
+ if (is_arm)
+ {
+ if (symbol_file_addr & 1)
+ symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB;
+ symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+ }
+
+ const FunctionStarts::Entry *next_func_start_entry = function_starts.FindNextEntry (func_start_entry);
+ const addr_t section_end_file_addr = section_file_addr + symbol_section->GetByteSize();
+ if (next_func_start_entry)
+ {
+ addr_t next_symbol_file_addr = next_func_start_entry->addr;
+ // Be sure the clear the Thumb address bit when we calculate the size
+ // from the current and next address
+ if (is_arm)
+ next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+ symbol_byte_size = std::min<lldb::addr_t>(next_symbol_file_addr - symbol_file_addr, section_end_file_addr - symbol_file_addr);
+ }
+ else
+ {
+ symbol_byte_size = section_end_file_addr - symbol_file_addr;
+ }
+ }
+ }
+ symbol_value -= section_file_addr;
+ }
+
+ if (is_debug == false)
+ {
+ if (type == eSymbolTypeCode)
+ {
+ // See if we can find a N_FUN entry for any code symbols.
+ // If we do find a match, and the name matches, then we
+ // can merge the two into just the function symbol to avoid
+ // duplicate entries in the symbol table
+ std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range;
+ range = N_FUN_addr_to_sym_idx.equal_range(nlist.n_value);
+ if (range.first != range.second)
+ {
+ bool found_it = false;
+ for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos)
+ {
+ if (sym[sym_idx].GetMangled().GetName(Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(Mangled::ePreferMangled))
+ {
+ m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
+ // We just need the flags from the linker symbol, so put these flags
+ // into the N_FUN flags to avoid duplicate symbols in the symbol table
+ sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
+ sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc);
+ if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end())
+ sym[pos->second].SetType (eSymbolTypeResolver);
+ sym[sym_idx].Clear();
+ found_it = true;
+ break;
+ }
+ }
+ if (found_it)
+ continue;
+ }
+ else
+ {
+ if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end())
+ type = eSymbolTypeResolver;
+ }
+ }
+ else if (type == eSymbolTypeData ||
+ type == eSymbolTypeObjCClass ||
+ type == eSymbolTypeObjCMetaClass ||
+ type == eSymbolTypeObjCIVar )
+ {
+ // See if we can find a N_STSYM entry for any data symbols.
+ // If we do find a match, and the name matches, then we
+ // can merge the two into just the Static symbol to avoid
+ // duplicate entries in the symbol table
+ std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range;
+ range = N_STSYM_addr_to_sym_idx.equal_range(nlist.n_value);
+ if (range.first != range.second)
+ {
+ bool found_it = false;
+ for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos)
+ {
+ if (sym[sym_idx].GetMangled().GetName(Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(Mangled::ePreferMangled))
+ {
+ m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
+ // We just need the flags from the linker symbol, so put these flags
+ // into the N_STSYM flags to avoid duplicate symbols in the symbol table
+ sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
+ sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc);
+ sym[sym_idx].Clear();
+ found_it = true;
+ break;
+ }
+ }
+ if (found_it)
+ continue;
+ }
+ else
+ {
+ const char *gsym_name = sym[sym_idx].GetMangled().GetName(Mangled::ePreferMangled).GetCString();
+ if (gsym_name)
+ {
+ // Combine N_GSYM stab entries with the non stab symbol
+ ConstNameToSymbolIndexMap::const_iterator pos = N_GSYM_name_to_sym_idx.find(gsym_name);
+ if (pos != N_GSYM_name_to_sym_idx.end())
+ {
+ const uint32_t GSYM_sym_idx = pos->second;
+ m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx;
+ // Copy the address, because often the N_GSYM address has an invalid address of zero
+ // when the global is a common symbol
+ sym[GSYM_sym_idx].GetAddressRef().SetSection (symbol_section);
+ sym[GSYM_sym_idx].GetAddressRef().SetOffset (symbol_value);
+ // We just need the flags from the linker symbol, so put these flags
+ // into the N_GSYM flags to avoid duplicate symbols in the symbol table
+ sym[GSYM_sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc);
+ sym[sym_idx].Clear();
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ sym[sym_idx].SetID (nlist_idx);
+ sym[sym_idx].SetType (type);
+ if (set_value)
+ {
+ sym[sym_idx].GetAddressRef().SetSection (symbol_section);
+ sym[sym_idx].GetAddressRef().SetOffset (symbol_value);
+ }
+ sym[sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc);
+
+ if (symbol_byte_size > 0)
+ sym[sym_idx].SetByteSize(symbol_byte_size);
+
+ if (demangled_is_synthesized)
+ sym[sym_idx].SetDemangledNameIsSynthesized(true);
+ ++sym_idx;
+ }
+ else
+ {
+ sym[sym_idx].Clear();
+ }
+
+ }
+ /////////////////////////////
+ }
+ break; // No more entries to consider
+ }
+ }
+
+ for (const auto &pos :reexport_shlib_needs_fixup)
+ {
+ const auto undef_pos = undefined_name_to_desc.find(pos.second);
+ if (undef_pos != undefined_name_to_desc.end())
+ {
+ const uint8_t dylib_ordinal = llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second);
+ if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize())
+ sym[pos.first].SetReExportedSymbolSharedLibrary(dylib_files.GetFileSpecAtIndex(dylib_ordinal-1));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Must reset this in case it was mutated above!
+ nlist_data_offset = 0;
+#endif
+
+ if (nlist_data.GetByteSize() > 0)
+ {
+
+ // If the sym array was not created while parsing the DSC unmapped
+ // symbols, create it now.
+ if (sym == NULL)
+ {
+ sym = symtab->Resize (symtab_load_command.nsyms + m_dysymtab.nindirectsyms);
+ num_syms = symtab->GetNumSymbols();
+ }
+
+ if (unmapped_local_symbols_found)
+ {
+ assert(m_dysymtab.ilocalsym == 0);
+ nlist_data_offset += (m_dysymtab.nlocalsym * nlist_byte_size);
+ nlist_idx = m_dysymtab.nlocalsym;
+ }
+ else
+ {
+ nlist_idx = 0;
+ }
+
+ typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap;
+ typedef std::map<uint32_t, ConstString> SymbolIndexToName;
+ UndefinedNameToDescMap undefined_name_to_desc;
+ SymbolIndexToName reexport_shlib_needs_fixup;
+ for (; nlist_idx < symtab_load_command.nsyms; ++nlist_idx)
+ {
+ struct nlist_64 nlist;
+ if (!nlist_data.ValidOffsetForDataOfSize(nlist_data_offset, nlist_byte_size))
+ break;
+
+ nlist.n_strx = nlist_data.GetU32_unchecked(&nlist_data_offset);
+ nlist.n_type = nlist_data.GetU8_unchecked (&nlist_data_offset);
+ nlist.n_sect = nlist_data.GetU8_unchecked (&nlist_data_offset);
+ nlist.n_desc = nlist_data.GetU16_unchecked (&nlist_data_offset);
+ nlist.n_value = nlist_data.GetAddress_unchecked (&nlist_data_offset);
+
+ SymbolType type = eSymbolTypeInvalid;
+ const char *symbol_name = NULL;
+
+ if (have_strtab_data)
+ {
+ symbol_name = strtab_data.PeekCStr(nlist.n_strx);
+
+ if (symbol_name == NULL)
+ {
+ // No symbol should be NULL, even the symbols with no
+ // string values should have an offset zero which points
+ // to an empty C-string
+ Host::SystemLog (Host::eSystemLogError,
+ "error: symbol[%u] has invalid string table offset 0x%x in %s, ignoring symbol\n",
+ nlist_idx,
+ nlist.n_strx,
+ module_sp->GetFileSpec().GetPath().c_str());
+ continue;
+ }
+ if (symbol_name[0] == '\0')
+ symbol_name = NULL;
+ }
+ else
+ {
+ const addr_t str_addr = strtab_addr + nlist.n_strx;
+ Error str_error;
+ if (process->ReadCStringFromMemory(str_addr, memory_symbol_name, str_error))
+ symbol_name = memory_symbol_name.c_str();
+ }
+ const char *symbol_name_non_abi_mangled = NULL;
+
+ SectionSP symbol_section;
+ lldb::addr_t symbol_byte_size = 0;
+ bool add_nlist = true;
+ bool is_gsym = false;
+ bool is_debug = ((nlist.n_type & N_STAB) != 0);
+ bool demangled_is_synthesized = false;
+ bool set_value = true;
+ assert (sym_idx < num_syms);
+
+ sym[sym_idx].SetDebug (is_debug);
+
+ if (is_debug)
+ {
+ switch (nlist.n_type)
+ {
+ case N_GSYM:
+ // global symbol: name,,NO_SECT,type,0
+ // Sometimes the N_GSYM value contains the address.
+
+ // FIXME: In the .o files, we have a GSYM and a debug symbol for all the ObjC data. They
+ // have the same address, but we want to ensure that we always find only the real symbol,
+ // 'cause we don't currently correctly attribute the GSYM one to the ObjCClass/Ivar/MetaClass
+ // symbol type. This is a temporary hack to make sure the ObjectiveC symbols get treated
+ // correctly. To do this right, we should coalesce all the GSYM & global symbols that have the
+ // same address.
+ is_gsym = true;
+ sym[sym_idx].SetExternal(true);
+
+ if (symbol_name && symbol_name[0] == '_' && symbol_name[1] == 'O')
+ {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ if (symbol_name_ref.startswith(g_objc_v2_prefix_class))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+
+ }
+ else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size();
+ type = eSymbolTypeObjCMetaClass;
+ demangled_is_synthesized = true;
+ }
+ else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_ivar.size();
+ type = eSymbolTypeObjCIVar;
+ demangled_is_synthesized = true;
+ }
+ }
+ else
+ {
+ if (nlist.n_value != 0)
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeData;
+ }
+ break;
+
+ case N_FNAME:
+ // procedure name (f77 kludge): name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_FUN:
+ // procedure: name,,n_sect,linenumber,address
+ if (symbol_name)
+ {
+ type = eSymbolTypeCode;
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+
+ N_FUN_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx));
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_FUN_indexes.push_back(sym_idx);
+ }
+ else
+ {
+ type = eSymbolTypeCompiler;
+
+ if ( !N_FUN_indexes.empty() )
+ {
+ // Copy the size of the function into the original STAB entry so we don't have
+ // to hunt for it later
+ symtab->SymbolAtIndex(N_FUN_indexes.back())->SetByteSize(nlist.n_value);
+ N_FUN_indexes.pop_back();
+ // We don't really need the end function STAB as it contains the size which
+ // we already placed with the original symbol, so don't add it if we want a
+ // minimal symbol table
+ add_nlist = false;
+ }
+ }
+ break;
+
+ case N_STSYM:
+ // static symbol: name,,n_sect,type,address
+ N_STSYM_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx));
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ if (symbol_name && symbol_name[0])
+ {
+ type = ObjectFile::GetSymbolTypeFromName(symbol_name+1, eSymbolTypeData);
+ }
+ break;
+
+ case N_LCSYM:
+ // .lcomm symbol: name,,n_sect,type,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeCommonBlock;
+ break;
+
+ case N_BNSYM:
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ break;
+
+ case N_ENSYM:
+ // Set the size of the N_BNSYM to the terminating index of this N_ENSYM
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ break;
+
+
+ case N_OPT:
+ // emitted with gcc2_compiled and in gcc source
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_RSYM:
+ // register sym: name,,NO_SECT,type,register
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_SLINE:
+ // src line: 0,,n_sect,linenumber,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ case N_SSYM:
+ // structure elt: name,,NO_SECT,type,struct_offset
+ type = eSymbolTypeVariableType;
+ break;
+
+ case N_SO:
+ // source file name
+ type = eSymbolTypeSourceFile;
+ if (symbol_name == NULL)
+ {
+ add_nlist = false;
+ if (N_SO_index != UINT32_MAX)
+ {
+ // Set the size of the N_SO to the terminating index of this N_SO
+ // so that we can always skip the entire N_SO if we need to navigate
+ // more quickly at the source level when parsing STABS
+ symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
+ symbol_ptr->SetByteSize(sym_idx);
+ symbol_ptr->SetSizeIsSibling(true);
+ }
+ N_NSYM_indexes.clear();
+ N_INCL_indexes.clear();
+ N_BRAC_indexes.clear();
+ N_COMM_indexes.clear();
+ N_FUN_indexes.clear();
+ N_SO_index = UINT32_MAX;
+ }
+ else
+ {
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ const bool N_SO_has_full_path = symbol_name[0] == '/';
+ if (N_SO_has_full_path)
+ {
+ if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms))
+ {
+ // We have two consecutive N_SO entries where the first contains a directory
+ // and the second contains a full path.
+ sym[sym_idx - 1].GetMangled().SetValue(ConstString(symbol_name), false);
+ m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
+ add_nlist = false;
+ }
+ else
+ {
+ // This is the first entry in a N_SO that contains a directory or
+ // a full path to the source file
+ N_SO_index = sym_idx;
+ }
+ }
+ else if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms))
+ {
+ // This is usually the second N_SO entry that contains just the filename,
+ // so here we combine it with the first one if we are minimizing the symbol table
+ const char *so_path = sym[sym_idx - 1].GetMangled().GetDemangledName(lldb::eLanguageTypeUnknown).AsCString();
+ if (so_path && so_path[0])
+ {
+ std::string full_so_path (so_path);
+ const size_t double_slash_pos = full_so_path.find("//");
+ if (double_slash_pos != std::string::npos)
+ {
+ // The linker has been generating bad N_SO entries with doubled up paths
+ // in the format "%s%s" where the first string in the DW_AT_comp_dir,
+ // and the second is the directory for the source file so you end up with
+ // a path that looks like "/tmp/src//tmp/src/"
+ FileSpec so_dir(so_path, false);
+ if (!so_dir.Exists())
+ {
+ so_dir.SetFile(&full_so_path[double_slash_pos + 1], false);
+ if (so_dir.Exists())
+ {
+ // Trim off the incorrect path
+ full_so_path.erase(0, double_slash_pos + 1);
+ }
+ }
+ }
+ if (*full_so_path.rbegin() != '/')
+ full_so_path += '/';
+ full_so_path += symbol_name;
+ sym[sym_idx - 1].GetMangled().SetValue(ConstString(full_so_path.c_str()), false);
+ add_nlist = false;
+ m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
+ }
+ }
+ else
+ {
+ // This could be a relative path to a N_SO
+ N_SO_index = sym_idx;
+ }
+ }
+ break;
+
+ case N_OSO:
+ // object file name: name,,0,0,st_mtime
+ type = eSymbolTypeObjectFile;
+ break;
+
+ case N_LSYM:
+ // local sym: name,,NO_SECT,type,offset
+ type = eSymbolTypeLocal;
+ break;
+
+ //----------------------------------------------------------------------
+ // INCL scopes
+ //----------------------------------------------------------------------
+ case N_BINCL:
+ // include file beginning: name,,NO_SECT,0,sum
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_INCL_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+
+ case N_EINCL:
+ // include file end: name,,NO_SECT,0,0
+ // Set the size of the N_BINCL to the terminating index of this N_EINCL
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ if ( !N_INCL_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_INCL_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_SOL:
+ // #included file name: name,,n_sect,0,address
+ type = eSymbolTypeHeaderFile;
+
+ // We currently don't use the header files on darwin
+ add_nlist = false;
+ break;
+
+ case N_PARAMS:
+ // compiler parameters: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_VERSION:
+ // compiler version: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_OLEVEL:
+ // compiler -O level: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_PSYM:
+ // parameter: name,,NO_SECT,type,offset
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_ENTRY:
+ // alternate entry: name,,n_sect,linenumber,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ //----------------------------------------------------------------------
+ // Left and Right Braces
+ //----------------------------------------------------------------------
+ case N_LBRAC:
+ // left bracket: 0,,NO_SECT,nesting level,address
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ N_BRAC_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+
+ case N_RBRAC:
+ // right bracket: 0,,NO_SECT,nesting level,address
+ // Set the size of the N_LBRAC to the terminating index of this N_RBRAC
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ if ( !N_BRAC_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_BRAC_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_EXCL:
+ // deleted include file: name,,NO_SECT,0,sum
+ type = eSymbolTypeHeaderFile;
+ break;
+
+ //----------------------------------------------------------------------
+ // COMM scopes
+ //----------------------------------------------------------------------
+ case N_BCOMM:
+ // begin common: name,,NO_SECT,0,0
+ // We use the current number of symbols in the symbol table in lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ type = eSymbolTypeScopeBegin;
+ N_COMM_indexes.push_back(sym_idx);
+ break;
+
+ case N_ECOML:
+ // end common (local name): 0,,n_sect,0,address
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ // Fall through
+
+ case N_ECOMM:
+ // end common: name,,n_sect,0,0
+ // Set the size of the N_BCOMM to the terminating index of this N_ECOMM/N_ECOML
+ // so that we can always skip the entire symbol if we need to navigate
+ // more quickly at the source level when parsing STABS
+ if ( !N_COMM_indexes.empty() )
+ {
+ symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_COMM_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_LENG:
+ // second stab entry with length information
+ type = eSymbolTypeAdditional;
+ break;
+
+ default: break;
+ }
+ }
+ else
+ {
+ //uint8_t n_pext = N_PEXT & nlist.n_type;
+ uint8_t n_type = N_TYPE & nlist.n_type;
+ sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0);
+
+ switch (n_type)
+ {
+ case N_INDR:
+ {
+ const char *reexport_name_cstr = strtab_data.PeekCStr(nlist.n_value);
+ if (reexport_name_cstr && reexport_name_cstr[0])
+ {
+ type = eSymbolTypeReExported;
+ ConstString reexport_name(reexport_name_cstr + ((reexport_name_cstr[0] == '_') ? 1 : 0));
+ sym[sym_idx].SetReExportedSymbolName(reexport_name);
+ set_value = false;
+ reexport_shlib_needs_fixup[sym_idx] = reexport_name;
+ indirect_symbol_names.insert(ConstString(symbol_name + ((symbol_name[0] == '_') ? 1 : 0)));
+ }
+ else
+ type = eSymbolTypeUndefined;
+ }
+ break;
+
+ case N_UNDF:
+ if (symbol_name && symbol_name[0])
+ {
+ ConstString undefined_name(symbol_name + ((symbol_name[0] == '_') ? 1 : 0));
+ undefined_name_to_desc[undefined_name] = nlist.n_desc;
+ }
+ // Fall through
+ case N_PBUD:
+ type = eSymbolTypeUndefined;
+ break;
+
+ case N_ABS:
+ type = eSymbolTypeAbsolute;
+ break;
+
+ case N_SECT:
+ {
+ symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+
+ if (!symbol_section)
+ {
+ // TODO: warn about this?
+ add_nlist = false;
+ break;
+ }
+
+ if (TEXT_eh_frame_sectID == nlist.n_sect)
+ {
+ type = eSymbolTypeException;
+ }
+ else
+ {
+ uint32_t section_type = symbol_section->Get() & SECTION_TYPE;
+
+ switch (section_type)
+ {
+ case S_CSTRING_LITERALS: type = eSymbolTypeData; break; // section with only literal C strings
+ case S_4BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 4 byte literals
+ case S_8BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 8 byte literals
+ case S_LITERAL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only pointers to literals
+ case S_NON_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only non-lazy symbol pointers
+ case S_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only lazy symbol pointers
+ case S_SYMBOL_STUBS: type = eSymbolTypeTrampoline; break; // section with only symbol stubs, byte size of stub in the reserved2 field
+ case S_MOD_INIT_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for initialization
+ case S_MOD_TERM_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for termination
+ case S_INTERPOSING: type = eSymbolTypeTrampoline; break; // section with only pairs of function pointers for interposing
+ case S_16BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 16 byte literals
+ case S_DTRACE_DOF: type = eSymbolTypeInstrumentation; break;
+ case S_LAZY_DYLIB_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break;
+ default:
+ switch (symbol_section->GetType())
+ {
+ case lldb::eSectionTypeCode:
+ type = eSymbolTypeCode;
+ break;
+ case eSectionTypeData:
+ case eSectionTypeDataCString: // Inlined C string data
+ case eSectionTypeDataCStringPointers: // Pointers to C string data
+ case eSectionTypeDataSymbolAddress: // Address of a symbol in the symbol table
+ case eSectionTypeData4:
+ case eSectionTypeData8:
+ case eSectionTypeData16:
+ type = eSymbolTypeData;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (type == eSymbolTypeInvalid)
+ {
+ const char *symbol_sect_name = symbol_section->GetName().AsCString();
+ if (symbol_section->IsDescendant (text_section_sp.get()))
+ {
+ if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS |
+ S_ATTR_SELF_MODIFYING_CODE |
+ S_ATTR_SOME_INSTRUCTIONS))
+ type = eSymbolTypeData;
+ else
+ type = eSymbolTypeCode;
+ }
+ else
+ if (symbol_section->IsDescendant(data_section_sp.get()) ||
+ symbol_section->IsDescendant(data_dirty_section_sp.get()) ||
+ symbol_section->IsDescendant(data_const_section_sp.get()))
+ {
+ if (symbol_sect_name && ::strstr (symbol_sect_name, "__objc") == symbol_sect_name)
+ {
+ type = eSymbolTypeRuntime;
+
+ if (symbol_name)
+ {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ if (symbol_name_ref.startswith("_OBJC_"))
+ {
+ static const llvm::StringRef g_objc_v2_prefix_class ("_OBJC_CLASS_$_");
+ static const llvm::StringRef g_objc_v2_prefix_metaclass ("_OBJC_METACLASS_$_");
+ static const llvm::StringRef g_objc_v2_prefix_ivar ("_OBJC_IVAR_$_");
+ if (symbol_name_ref.startswith(g_objc_v2_prefix_class))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+ }
+ else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size();
+ type = eSymbolTypeObjCMetaClass;
+ demangled_is_synthesized = true;
+ }
+ else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar))
+ {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_ivar.size();
+ type = eSymbolTypeObjCIVar;
+ demangled_is_synthesized = true;
+ }
+ }
+ }
+ }
+ else
+ if (symbol_sect_name && ::strstr (symbol_sect_name, "__gcc_except_tab") == symbol_sect_name)
+ {
+ type = eSymbolTypeException;
+ }
+ else
+ {
+ type = eSymbolTypeData;
+ }
+ }
+ else
+ if (symbol_sect_name && ::strstr (symbol_sect_name, "__IMPORT") == symbol_sect_name)
+ {
+ type = eSymbolTypeTrampoline;
+ }
+ else
+ if (symbol_section->IsDescendant(objc_section_sp.get()))
+ {
+ type = eSymbolTypeRuntime;
+ if (symbol_name && symbol_name[0] == '.')
+ {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ static const llvm::StringRef g_objc_v1_prefix_class (".objc_class_name_");
+ if (symbol_name_ref.startswith(g_objc_v1_prefix_class))
+ {
+ symbol_name_non_abi_mangled = symbol_name;
+ symbol_name = symbol_name + g_objc_v1_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (add_nlist)
+ {
+ uint64_t symbol_value = nlist.n_value;
+
+ if (symbol_name_non_abi_mangled)
+ {
+ sym[sym_idx].GetMangled().SetMangledName (ConstString(symbol_name_non_abi_mangled));
+ sym[sym_idx].GetMangled().SetDemangledName (ConstString(symbol_name));
+ }
+ else
+ {
+ bool symbol_name_is_mangled = false;
+
+ if (symbol_name && symbol_name[0] == '_')
+ {
+ symbol_name_is_mangled = symbol_name[1] == '_';
+ symbol_name++; // Skip the leading underscore
+ }
+
+ if (symbol_name)
+ {
+ ConstString const_symbol_name(symbol_name);
+ sym[sym_idx].GetMangled().SetValue(const_symbol_name, symbol_name_is_mangled);
+ }
+ }
+
+ if (is_gsym)
+ {
+ const char *gsym_name = sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled).GetCString();
+ if (gsym_name)
+ N_GSYM_name_to_sym_idx[gsym_name] = sym_idx;
+ }
+
+ if (symbol_section)
+ {
+ const addr_t section_file_addr = symbol_section->GetFileAddress();
+ if (symbol_byte_size == 0 && function_starts_count > 0)
+ {
+ addr_t symbol_lookup_file_addr = nlist.n_value;
+ // Do an exact address match for non-ARM addresses, else get the closest since
+ // the symbol might be a thumb symbol which has an address with bit zero set
+ FunctionStarts::Entry *func_start_entry = function_starts.FindEntry (symbol_lookup_file_addr, !is_arm);
+ if (is_arm && func_start_entry)
+ {
+ // Verify that the function start address is the symbol address (ARM)
+ // or the symbol address + 1 (thumb)
+ if (func_start_entry->addr != symbol_lookup_file_addr &&
+ func_start_entry->addr != (symbol_lookup_file_addr + 1))
+ {
+ // Not the right entry, NULL it out...
+ func_start_entry = NULL;
+ }
+ }
+ if (func_start_entry)
+ {
+ func_start_entry->data = true;
+
+ addr_t symbol_file_addr = func_start_entry->addr;
+ if (is_arm)
+ symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+
+ const FunctionStarts::Entry *next_func_start_entry = function_starts.FindNextEntry (func_start_entry);
+ const addr_t section_end_file_addr = section_file_addr + symbol_section->GetByteSize();
+ if (next_func_start_entry)
+ {
+ addr_t next_symbol_file_addr = next_func_start_entry->addr;
+ // Be sure the clear the Thumb address bit when we calculate the size
+ // from the current and next address
+ if (is_arm)
+ next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+ symbol_byte_size = std::min<lldb::addr_t>(next_symbol_file_addr - symbol_file_addr, section_end_file_addr - symbol_file_addr);
+ }
+ else
+ {
+ symbol_byte_size = section_end_file_addr - symbol_file_addr;
+ }
+ }
+ }
+ symbol_value -= section_file_addr;
+ }
+
+ if (is_debug == false)
+ {
+ if (type == eSymbolTypeCode)
+ {
+ // See if we can find a N_FUN entry for any code symbols.
+ // If we do find a match, and the name matches, then we
+ // can merge the two into just the function symbol to avoid
+ // duplicate entries in the symbol table
+ std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range;
+ range = N_FUN_addr_to_sym_idx.equal_range(nlist.n_value);
+ if (range.first != range.second)
+ {
+ bool found_it = false;
+ for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos)
+ {
+ if (sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled))
+ {
+ m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
+ // We just need the flags from the linker symbol, so put these flags
+ // into the N_FUN flags to avoid duplicate symbols in the symbol table
+ sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
+ sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc);
+ if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end())
+ sym[pos->second].SetType (eSymbolTypeResolver);
+ sym[sym_idx].Clear();
+ found_it = true;
+ break;
+ }
+ }
+ if (found_it)
+ continue;
+ }
+ else
+ {
+ if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end())
+ type = eSymbolTypeResolver;
+ }
+ }
+ else if (type == eSymbolTypeData ||
+ type == eSymbolTypeObjCClass ||
+ type == eSymbolTypeObjCMetaClass ||
+ type == eSymbolTypeObjCIVar )
+ {
+ // See if we can find a N_STSYM entry for any data symbols.
+ // If we do find a match, and the name matches, then we
+ // can merge the two into just the Static symbol to avoid
+ // duplicate entries in the symbol table
+ std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range;
+ range = N_STSYM_addr_to_sym_idx.equal_range(nlist.n_value);
+ if (range.first != range.second)
+ {
+ bool found_it = false;
+ for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos)
+ {
+ if (sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled))
+ {
+ m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
+ // We just need the flags from the linker symbol, so put these flags
+ // into the N_STSYM flags to avoid duplicate symbols in the symbol table
+ sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
+ sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc);
+ sym[sym_idx].Clear();
+ found_it = true;
+ break;
+ }
+ }
+ if (found_it)
+ continue;
+ }
+ else
+ {
+ // Combine N_GSYM stab entries with the non stab symbol
+ const char *gsym_name = sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled).GetCString();
+ if (gsym_name)
+ {
+ ConstNameToSymbolIndexMap::const_iterator pos = N_GSYM_name_to_sym_idx.find(gsym_name);
+ if (pos != N_GSYM_name_to_sym_idx.end())
+ {
+ const uint32_t GSYM_sym_idx = pos->second;
+ m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx;
+ // Copy the address, because often the N_GSYM address has an invalid address of zero
+ // when the global is a common symbol
+ sym[GSYM_sym_idx].GetAddressRef().SetSection (symbol_section);
+ sym[GSYM_sym_idx].GetAddressRef().SetOffset (symbol_value);
+ // We just need the flags from the linker symbol, so put these flags
+ // into the N_GSYM flags to avoid duplicate symbols in the symbol table
+ sym[GSYM_sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc);
+ sym[sym_idx].Clear();
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ sym[sym_idx].SetID (nlist_idx);
+ sym[sym_idx].SetType (type);
+ if (set_value)
+ {
+ sym[sym_idx].GetAddressRef().SetSection (symbol_section);
+ sym[sym_idx].GetAddressRef().SetOffset (symbol_value);
+ }
+ sym[sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc);
+
+ if (symbol_byte_size > 0)
+ sym[sym_idx].SetByteSize(symbol_byte_size);
+
+ if (demangled_is_synthesized)
+ sym[sym_idx].SetDemangledNameIsSynthesized(true);
+
+ ++sym_idx;
+ }
+ else
+ {
+ sym[sym_idx].Clear();
+ }
+ }
+
+ for (const auto &pos :reexport_shlib_needs_fixup)
+ {
+ const auto undef_pos = undefined_name_to_desc.find(pos.second);
+ if (undef_pos != undefined_name_to_desc.end())
+ {
+ const uint8_t dylib_ordinal = llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second);
+ if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize())
+ sym[pos.first].SetReExportedSymbolSharedLibrary(dylib_files.GetFileSpecAtIndex(dylib_ordinal-1));
+ }
+ }
+ }
+
+ uint32_t synthetic_sym_id = symtab_load_command.nsyms;
+
+ if (function_starts_count > 0)
+ {
+ char synthetic_function_symbol[PATH_MAX];
+ uint32_t num_synthetic_function_symbols = 0;
+ for (i=0; i<function_starts_count; ++i)
+ {
+ if (function_starts.GetEntryRef (i).data == false)
+ ++num_synthetic_function_symbols;
+ }
+
+ if (num_synthetic_function_symbols > 0)
+ {
+ if (num_syms < sym_idx + num_synthetic_function_symbols)
+ {
+ num_syms = sym_idx + num_synthetic_function_symbols;
+ sym = symtab->Resize (num_syms);
+ }
+ uint32_t synthetic_function_symbol_idx = 0;
+ for (i=0; i<function_starts_count; ++i)
+ {
+ const FunctionStarts::Entry *func_start_entry = function_starts.GetEntryAtIndex (i);
+ if (func_start_entry->data == false)
+ {
+ addr_t symbol_file_addr = func_start_entry->addr;
+ uint32_t symbol_flags = 0;
+ if (is_arm)
+ {
+ if (symbol_file_addr & 1)
+ symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB;
+ symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+ }
+ Address symbol_addr;
+ if (module_sp->ResolveFileAddress (symbol_file_addr, symbol_addr))
+ {
+ SectionSP symbol_section (symbol_addr.GetSection());
+ uint32_t symbol_byte_size = 0;
+ if (symbol_section)
+ {
+ const addr_t section_file_addr = symbol_section->GetFileAddress();
+ const FunctionStarts::Entry *next_func_start_entry = function_starts.FindNextEntry (func_start_entry);
+ const addr_t section_end_file_addr = section_file_addr + symbol_section->GetByteSize();
+ if (next_func_start_entry)
+ {
+ addr_t next_symbol_file_addr = next_func_start_entry->addr;
+ if (is_arm)
+ next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+ symbol_byte_size = std::min<lldb::addr_t>(next_symbol_file_addr - symbol_file_addr, section_end_file_addr - symbol_file_addr);
+ }
+ else
+ {
+ symbol_byte_size = section_end_file_addr - symbol_file_addr;
+ }
+ snprintf (synthetic_function_symbol,
+ sizeof(synthetic_function_symbol),
+ "___lldb_unnamed_function%u$$%s",
+ ++synthetic_function_symbol_idx,
+ module_sp->GetFileSpec().GetFilename().GetCString());
+ sym[sym_idx].SetID (synthetic_sym_id++);
+ sym[sym_idx].GetMangled().SetDemangledName(ConstString(synthetic_function_symbol));
+ sym[sym_idx].SetType (eSymbolTypeCode);
+ sym[sym_idx].SetIsSynthetic (true);
+ sym[sym_idx].GetAddressRef() = symbol_addr;
+ if (symbol_flags)
+ sym[sym_idx].SetFlags (symbol_flags);
+ if (symbol_byte_size)
+ sym[sym_idx].SetByteSize (symbol_byte_size);
+ ++sym_idx;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Trim our symbols down to just what we ended up with after
+ // removing any symbols.
+ if (sym_idx < num_syms)
+ {
+ num_syms = sym_idx;
+ sym = symtab->Resize (num_syms);
+ }
+
+ // Now synthesize indirect symbols
+ if (m_dysymtab.nindirectsyms != 0)
+ {
+ if (indirect_symbol_index_data.GetByteSize())
+ {
+ NListIndexToSymbolIndexMap::const_iterator end_index_pos = m_nlist_idx_to_sym_idx.end();
+
+ for (uint32_t sect_idx = 1; sect_idx < m_mach_sections.size(); ++sect_idx)
+ {
+ if ((m_mach_sections[sect_idx].flags & SECTION_TYPE) == S_SYMBOL_STUBS)
+ {
+ uint32_t symbol_stub_byte_size = m_mach_sections[sect_idx].reserved2;
+ if (symbol_stub_byte_size == 0)
+ continue;
+
+ const uint32_t num_symbol_stubs = m_mach_sections[sect_idx].size / symbol_stub_byte_size;
+
+ if (num_symbol_stubs == 0)
+ continue;
+
+ const uint32_t symbol_stub_index_offset = m_mach_sections[sect_idx].reserved1;
+ for (uint32_t stub_idx = 0; stub_idx < num_symbol_stubs; ++stub_idx)
+ {
+ const uint32_t symbol_stub_index = symbol_stub_index_offset + stub_idx;
+ const lldb::addr_t symbol_stub_addr = m_mach_sections[sect_idx].addr + (stub_idx * symbol_stub_byte_size);
+ lldb::offset_t symbol_stub_offset = symbol_stub_index * 4;
+ if (indirect_symbol_index_data.ValidOffsetForDataOfSize(symbol_stub_offset, 4))
+ {
+ const uint32_t stub_sym_id = indirect_symbol_index_data.GetU32 (&symbol_stub_offset);
+ if (stub_sym_id & (INDIRECT_SYMBOL_ABS | INDIRECT_SYMBOL_LOCAL))
+ continue;
+
+ NListIndexToSymbolIndexMap::const_iterator index_pos = m_nlist_idx_to_sym_idx.find (stub_sym_id);
+ Symbol *stub_symbol = NULL;
+ if (index_pos != end_index_pos)
+ {
+ // We have a remapping from the original nlist index to
+ // a current symbol index, so just look this up by index
+ stub_symbol = symtab->SymbolAtIndex (index_pos->second);
+ }
+ else
+ {
+ // We need to lookup a symbol using the original nlist
+ // symbol index since this index is coming from the
+ // S_SYMBOL_STUBS
+ stub_symbol = symtab->FindSymbolByID (stub_sym_id);
+ }
+
+ if (stub_symbol)
+ {
+ Address so_addr(symbol_stub_addr, section_list);
+
+ if (stub_symbol->GetType() == eSymbolTypeUndefined)
+ {
+ // Change the external symbol into a trampoline that makes sense
+ // These symbols were N_UNDF N_EXT, and are useless to us, so we
+ // can re-use them so we don't have to make up a synthetic symbol
+ // for no good reason.
+ if (resolver_addresses.find(symbol_stub_addr) == resolver_addresses.end())
+ stub_symbol->SetType (eSymbolTypeTrampoline);
+ else
+ stub_symbol->SetType (eSymbolTypeResolver);
+ stub_symbol->SetExternal (false);
+ stub_symbol->GetAddressRef() = so_addr;
+ stub_symbol->SetByteSize (symbol_stub_byte_size);
+ }
+ else
+ {
+ // Make a synthetic symbol to describe the trampoline stub
+ Mangled stub_symbol_mangled_name(stub_symbol->GetMangled());
+ if (sym_idx >= num_syms)
+ {
+ sym = symtab->Resize (++num_syms);
+ stub_symbol = NULL; // this pointer no longer valid
+ }
+ sym[sym_idx].SetID (synthetic_sym_id++);
+ sym[sym_idx].GetMangled() = stub_symbol_mangled_name;
+ if (resolver_addresses.find(symbol_stub_addr) == resolver_addresses.end())
+ sym[sym_idx].SetType (eSymbolTypeTrampoline);
+ else
+ sym[sym_idx].SetType (eSymbolTypeResolver);
+ sym[sym_idx].SetIsSynthetic (true);
+ sym[sym_idx].GetAddressRef() = so_addr;
+ sym[sym_idx].SetByteSize (symbol_stub_byte_size);
+ ++sym_idx;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Warning ("symbol stub referencing symbol table symbol %u that isn't in our minimal symbol table, fix this!!!", stub_sym_id);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!trie_entries.empty())
+ {
+ for (const auto &e : trie_entries)
+ {
+ if (e.entry.import_name)
+ {
+ // Only add indirect symbols from the Trie entries if we
+ // didn't have a N_INDR nlist entry for this already
+ if (indirect_symbol_names.find(e.entry.name) == indirect_symbol_names.end())
+ {
+ // Make a synthetic symbol to describe re-exported symbol.
+ if (sym_idx >= num_syms)
+ sym = symtab->Resize (++num_syms);
+ sym[sym_idx].SetID (synthetic_sym_id++);
+ sym[sym_idx].GetMangled() = Mangled(e.entry.name);
+ sym[sym_idx].SetType (eSymbolTypeReExported);
+ sym[sym_idx].SetIsSynthetic (true);
+ sym[sym_idx].SetReExportedSymbolName(e.entry.import_name);
+ if (e.entry.other > 0 && e.entry.other <= dylib_files.GetSize())
+ {
+ sym[sym_idx].SetReExportedSymbolSharedLibrary(dylib_files.GetFileSpecAtIndex(e.entry.other-1));
+ }
+ ++sym_idx;
+ }
+ }
+ }
+ }
+
+// StreamFile s(stdout, false);
+// s.Printf ("Symbol table before CalculateSymbolSizes():\n");
+// symtab->Dump(&s, NULL, eSortOrderNone);
+ // Set symbol byte sizes correctly since mach-o nlist entries don't have sizes
+ symtab->CalculateSymbolSizes();
+
+// s.Printf ("Symbol table after CalculateSymbolSizes():\n");
+// symtab->Dump(&s, NULL, eSortOrderNone);
+
+ return symtab->GetNumSymbols();
+ }
+ return 0;
+}
+
+void
+ObjectFileMachO::Dump (Stream *s)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ s->Printf("%p: ", static_cast<void*>(this));
+ s->Indent();
+ if (m_header.magic == MH_MAGIC_64 || m_header.magic == MH_CIGAM_64)
+ s->PutCString("ObjectFileMachO64");
+ else
+ s->PutCString("ObjectFileMachO32");
+
+ ArchSpec header_arch;
+ GetArchitecture(header_arch);
+
+ *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n";
+
+ SectionList *sections = GetSectionList();
+ if (sections)
+ sections->Dump(s, NULL, true, UINT32_MAX);
+
+ if (m_symtab_ap.get())
+ m_symtab_ap->Dump(s, NULL, eSortOrderNone);
+ }
+}
+
+bool
+ObjectFileMachO::GetUUID (const llvm::MachO::mach_header &header,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t lc_offset,
+ lldb_private::UUID& uuid)
+{
+ uint32_t i;
+ struct uuid_command load_cmd;
+
+ lldb::offset_t offset = lc_offset;
+ for (i=0; i<header.ncmds; ++i)
+ {
+ const lldb::offset_t cmd_offset = offset;
+ if (data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ if (load_cmd.cmd == LC_UUID)
+ {
+ const uint8_t *uuid_bytes = data.PeekData(offset, 16);
+
+ if (uuid_bytes)
+ {
+ // OpenCL on Mac OS X uses the same UUID for each of its object files.
+ // We pretend these object files have no UUID to prevent crashing.
+
+ const uint8_t opencl_uuid[] = { 0x8c, 0x8e, 0xb3, 0x9b,
+ 0x3b, 0xa8,
+ 0x4b, 0x16,
+ 0xb6, 0xa4,
+ 0x27, 0x63, 0xbb, 0x14, 0xf0, 0x0d };
+
+ if (!memcmp(uuid_bytes, opencl_uuid, 16))
+ return false;
+
+ uuid.SetBytes (uuid_bytes);
+ return true;
+ }
+ return false;
+ }
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+ return false;
+}
+
+bool
+ObjectFileMachO::GetArchitecture (const llvm::MachO::mach_header &header,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t lc_offset,
+ ArchSpec &arch)
+{
+ arch.SetArchitecture (eArchTypeMachO, header.cputype, header.cpusubtype);
+
+ if (arch.IsValid())
+ {
+ llvm::Triple &triple = arch.GetTriple();
+
+ // Set OS to an unspecified unknown or a "*" so it can match any OS
+ triple.setOS(llvm::Triple::UnknownOS);
+ triple.setOSName(llvm::StringRef());
+
+ if (header.filetype == MH_PRELOAD)
+ {
+ // Set vendor to an unspecified unknown or a "*" so it can match any vendor
+ triple.setVendor(llvm::Triple::UnknownVendor);
+ triple.setVendorName(llvm::StringRef());
+ return true;
+ }
+ else
+ {
+ struct load_command load_cmd;
+
+ lldb::offset_t offset = lc_offset;
+ for (uint32_t i=0; i<header.ncmds; ++i)
+ {
+ const lldb::offset_t cmd_offset = offset;
+ if (data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ switch (load_cmd.cmd)
+ {
+ case llvm::MachO::LC_VERSION_MIN_IPHONEOS:
+ triple.setOS (llvm::Triple::IOS);
+ return true;
+
+ case llvm::MachO::LC_VERSION_MIN_MACOSX:
+ triple.setOS (llvm::Triple::MacOSX);
+ return true;
+
+ case llvm::MachO::LC_VERSION_MIN_TVOS:
+ triple.setOS (llvm::Triple::TvOS);
+ return true;
+
+ case llvm::MachO::LC_VERSION_MIN_WATCHOS:
+ triple.setOS (llvm::Triple::WatchOS);
+ return true;
+
+ default:
+ break;
+ }
+
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+
+ if (header.filetype != MH_KEXT_BUNDLE)
+ {
+ // We didn't find a LC_VERSION_MIN load command and this isn't a KEXT
+ // so lets not say our Vendor is Apple, leave it as an unspecified unknown
+ triple.setVendor(llvm::Triple::UnknownVendor);
+ triple.setVendorName(llvm::StringRef());
+ }
+ }
+ }
+ return arch.IsValid();
+}
+
+bool
+ObjectFileMachO::GetUUID (lldb_private::UUID* uuid)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ return GetUUID (m_header, m_data, offset, *uuid);
+ }
+ return false;
+}
+
+uint32_t
+ObjectFileMachO::GetDependentModules (FileSpecList& files)
+{
+ uint32_t count = 0;
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ struct load_command load_cmd;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ std::vector<std::string> rpath_paths;
+ std::vector<std::string> rpath_relative_paths;
+ const bool resolve_path = false; // Don't resolve the dependent file paths since they may not reside on this system
+ uint32_t i;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const uint32_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ switch (load_cmd.cmd)
+ {
+ case LC_RPATH:
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOAD_DYLINKER:
+ case LC_LOADFVMLIB:
+ case LC_LOAD_UPWARD_DYLIB:
+ {
+ uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
+ const char *path = m_data.PeekCStr(name_offset);
+ if (path)
+ {
+ if (load_cmd.cmd == LC_RPATH)
+ rpath_paths.push_back(path);
+ else
+ {
+ if (path[0] == '@')
+ {
+ if (strncmp(path, "@rpath", strlen("@rpath")) == 0)
+ rpath_relative_paths.push_back(path + strlen("@rpath"));
+ }
+ else
+ {
+ FileSpec file_spec(path, resolve_path);
+ if (files.AppendIfUnique(file_spec))
+ count++;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+
+ if (!rpath_paths.empty())
+ {
+ // Fixup all LC_RPATH values to be absolute paths
+ FileSpec this_file_spec(m_file);
+ this_file_spec.ResolvePath();
+ std::string loader_path("@loader_path");
+ std::string executable_path("@executable_path");
+ for (auto &rpath : rpath_paths)
+ {
+ if (rpath.find(loader_path) == 0)
+ {
+ rpath.erase(0, loader_path.size());
+ rpath.insert(0, this_file_spec.GetDirectory().GetCString());
+ }
+ else if (rpath.find(executable_path) == 0)
+ {
+ rpath.erase(0, executable_path.size());
+ rpath.insert(0, this_file_spec.GetDirectory().GetCString());
+ }
+ }
+
+ for (const auto &rpath_relative_path : rpath_relative_paths)
+ {
+ for (const auto &rpath : rpath_paths)
+ {
+ std::string path = rpath;
+ path += rpath_relative_path;
+ // It is OK to resolve this path because we must find a file on
+ // disk for us to accept it anyway if it is rpath relative.
+ FileSpec file_spec(path, true);
+ // Remove any redundant parts of the path (like "../foo") since
+ // LC_RPATH values often contain "..".
+ file_spec.NormalizePath ();
+ if (file_spec.Exists() && files.AppendIfUnique(file_spec))
+ {
+ count++;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return count;
+}
+
+lldb_private::Address
+ObjectFileMachO::GetEntryPointAddress ()
+{
+ // If the object file is not an executable it can't hold the entry point. m_entry_point_address
+ // is initialized to an invalid address, so we can just return that.
+ // If m_entry_point_address is valid it means we've found it already, so return the cached value.
+
+ if (!IsExecutable() || m_entry_point_address.IsValid())
+ return m_entry_point_address;
+
+ // Otherwise, look for the UnixThread or Thread command. The data for the Thread command is given in
+ // /usr/include/mach-o.h, but it is basically:
+ //
+ // uint32_t flavor - this is the flavor argument you would pass to thread_get_state
+ // uint32_t count - this is the count of longs in the thread state data
+ // struct XXX_thread_state state - this is the structure from <machine/thread_status.h> corresponding to the flavor.
+ // <repeat this trio>
+ //
+ // So we just keep reading the various register flavors till we find the GPR one, then read the PC out of there.
+ // FIXME: We will need to have a "RegisterContext data provider" class at some point that can get all the registers
+ // out of data in this form & attach them to a given thread. That should underlie the MacOS X User process plugin,
+ // and we'll also need it for the MacOS X Core File process plugin. When we have that we can also use it here.
+ //
+ // For now we hard-code the offsets and flavors we need:
+ //
+ //
+
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ struct load_command load_cmd;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ lldb::addr_t start_address = LLDB_INVALID_ADDRESS;
+ bool done = false;
+
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const lldb::offset_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ switch (load_cmd.cmd)
+ {
+ case LC_UNIXTHREAD:
+ case LC_THREAD:
+ {
+ while (offset < cmd_offset + load_cmd.cmdsize)
+ {
+ uint32_t flavor = m_data.GetU32(&offset);
+ uint32_t count = m_data.GetU32(&offset);
+ if (count == 0)
+ {
+ // We've gotten off somehow, log and exit;
+ return m_entry_point_address;
+ }
+
+ switch (m_header.cputype)
+ {
+ case llvm::MachO::CPU_TYPE_ARM:
+ if (flavor == 1) // ARM_THREAD_STATE from mach/arm/thread_status.h
+ {
+ offset += 60; // This is the offset of pc in the GPR thread state data structure.
+ start_address = m_data.GetU32(&offset);
+ done = true;
+ }
+ break;
+ case llvm::MachO::CPU_TYPE_ARM64:
+ if (flavor == 6) // ARM_THREAD_STATE64 from mach/arm/thread_status.h
+ {
+ offset += 256; // This is the offset of pc in the GPR thread state data structure.
+ start_address = m_data.GetU64(&offset);
+ done = true;
+ }
+ break;
+ case llvm::MachO::CPU_TYPE_I386:
+ if (flavor == 1) // x86_THREAD_STATE32 from mach/i386/thread_status.h
+ {
+ offset += 40; // This is the offset of eip in the GPR thread state data structure.
+ start_address = m_data.GetU32(&offset);
+ done = true;
+ }
+ break;
+ case llvm::MachO::CPU_TYPE_X86_64:
+ if (flavor == 4) // x86_THREAD_STATE64 from mach/i386/thread_status.h
+ {
+ offset += 16 * 8; // This is the offset of rip in the GPR thread state data structure.
+ start_address = m_data.GetU64(&offset);
+ done = true;
+ }
+ break;
+ default:
+ return m_entry_point_address;
+ }
+ // Haven't found the GPR flavor yet, skip over the data for this flavor:
+ if (done)
+ break;
+ offset += count * 4;
+ }
+ }
+ break;
+ case LC_MAIN:
+ {
+ ConstString text_segment_name ("__TEXT");
+ uint64_t entryoffset = m_data.GetU64(&offset);
+ SectionSP text_segment_sp = GetSectionList()->FindSectionByName(text_segment_name);
+ if (text_segment_sp)
+ {
+ done = true;
+ start_address = text_segment_sp->GetFileAddress() + entryoffset;
+ }
+ }
+
+ default:
+ break;
+ }
+ if (done)
+ break;
+
+ // Go to the next load command:
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+
+ if (start_address != LLDB_INVALID_ADDRESS)
+ {
+ // We got the start address from the load commands, so now resolve that address in the sections
+ // of this ObjectFile:
+ if (!m_entry_point_address.ResolveAddressUsingFileSections (start_address, GetSectionList()))
+ {
+ m_entry_point_address.Clear();
+ }
+ }
+ else
+ {
+ // We couldn't read the UnixThread load command - maybe it wasn't there. As a fallback look for the
+ // "start" symbol in the main executable.
+
+ ModuleSP module_sp (GetModule());
+
+ if (module_sp)
+ {
+ SymbolContextList contexts;
+ SymbolContext context;
+ if (module_sp->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
+ {
+ if (contexts.GetContextAtIndex(0, context))
+ m_entry_point_address = context.symbol->GetAddress();
+ }
+ }
+ }
+ }
+
+ return m_entry_point_address;
+}
+
+lldb_private::Address
+ObjectFileMachO::GetHeaderAddress ()
+{
+ lldb_private::Address header_addr;
+ SectionList *section_list = GetSectionList();
+ if (section_list)
+ {
+ SectionSP text_segment_sp (section_list->FindSectionByName (GetSegmentNameTEXT()));
+ if (text_segment_sp)
+ {
+ header_addr.SetSection (text_segment_sp);
+ header_addr.SetOffset (0);
+ }
+ }
+ return header_addr;
+}
+
+uint32_t
+ObjectFileMachO::GetNumThreadContexts ()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (!m_thread_context_offsets_valid)
+ {
+ m_thread_context_offsets_valid = true;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ FileRangeArray::Entry file_range;
+ thread_command thread_cmd;
+ for (uint32_t i=0; i<m_header.ncmds; ++i)
+ {
+ const uint32_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &thread_cmd, 2) == NULL)
+ break;
+
+ if (thread_cmd.cmd == LC_THREAD)
+ {
+ file_range.SetRangeBase (offset);
+ file_range.SetByteSize (thread_cmd.cmdsize - 8);
+ m_thread_context_offsets.Append (file_range);
+ }
+ offset = cmd_offset + thread_cmd.cmdsize;
+ }
+ }
+ }
+ return m_thread_context_offsets.GetSize();
+}
+
+lldb::RegisterContextSP
+ObjectFileMachO::GetThreadContextAtIndex (uint32_t idx, lldb_private::Thread &thread)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (!m_thread_context_offsets_valid)
+ GetNumThreadContexts ();
+
+ const FileRangeArray::Entry *thread_context_file_range = m_thread_context_offsets.GetEntryAtIndex (idx);
+ if (thread_context_file_range)
+ {
+
+ DataExtractor data (m_data,
+ thread_context_file_range->GetRangeBase(),
+ thread_context_file_range->GetByteSize());
+
+ switch (m_header.cputype)
+ {
+ case llvm::MachO::CPU_TYPE_ARM64:
+ reg_ctx_sp.reset (new RegisterContextDarwin_arm64_Mach (thread, data));
+ break;
+
+ case llvm::MachO::CPU_TYPE_ARM:
+ reg_ctx_sp.reset (new RegisterContextDarwin_arm_Mach (thread, data));
+ break;
+
+ case llvm::MachO::CPU_TYPE_I386:
+ reg_ctx_sp.reset (new RegisterContextDarwin_i386_Mach (thread, data));
+ break;
+
+ case llvm::MachO::CPU_TYPE_X86_64:
+ reg_ctx_sp.reset (new RegisterContextDarwin_x86_64_Mach (thread, data));
+ break;
+ }
+ }
+ }
+ return reg_ctx_sp;
+}
+
+ObjectFile::Type
+ObjectFileMachO::CalculateType()
+{
+ switch (m_header.filetype)
+ {
+ case MH_OBJECT: // 0x1u
+ if (GetAddressByteSize () == 4)
+ {
+ // 32 bit kexts are just object files, but they do have a valid
+ // UUID load command.
+ UUID uuid;
+ if (GetUUID(&uuid))
+ {
+ // this checking for the UUID load command is not enough
+ // we could eventually look for the symbol named
+ // "OSKextGetCurrentIdentifier" as this is required of kexts
+ if (m_strata == eStrataInvalid)
+ m_strata = eStrataKernel;
+ return eTypeSharedLibrary;
+ }
+ }
+ return eTypeObjectFile;
+
+ case MH_EXECUTE: return eTypeExecutable; // 0x2u
+ case MH_FVMLIB: return eTypeSharedLibrary; // 0x3u
+ case MH_CORE: return eTypeCoreFile; // 0x4u
+ case MH_PRELOAD: return eTypeSharedLibrary; // 0x5u
+ case MH_DYLIB: return eTypeSharedLibrary; // 0x6u
+ case MH_DYLINKER: return eTypeDynamicLinker; // 0x7u
+ case MH_BUNDLE: return eTypeSharedLibrary; // 0x8u
+ case MH_DYLIB_STUB: return eTypeStubLibrary; // 0x9u
+ case MH_DSYM: return eTypeDebugInfo; // 0xAu
+ case MH_KEXT_BUNDLE: return eTypeSharedLibrary; // 0xBu
+ default:
+ break;
+ }
+ return eTypeUnknown;
+}
+
+ObjectFile::Strata
+ObjectFileMachO::CalculateStrata()
+{
+ switch (m_header.filetype)
+ {
+ case MH_OBJECT: // 0x1u
+ {
+ // 32 bit kexts are just object files, but they do have a valid
+ // UUID load command.
+ UUID uuid;
+ if (GetUUID(&uuid))
+ {
+ // this checking for the UUID load command is not enough
+ // we could eventually look for the symbol named
+ // "OSKextGetCurrentIdentifier" as this is required of kexts
+ if (m_type == eTypeInvalid)
+ m_type = eTypeSharedLibrary;
+
+ return eStrataKernel;
+ }
+ }
+ return eStrataUnknown;
+
+ case MH_EXECUTE: // 0x2u
+ // Check for the MH_DYLDLINK bit in the flags
+ if (m_header.flags & MH_DYLDLINK)
+ {
+ return eStrataUser;
+ }
+ else
+ {
+ SectionList *section_list = GetSectionList();
+ if (section_list)
+ {
+ static ConstString g_kld_section_name ("__KLD");
+ if (section_list->FindSectionByName(g_kld_section_name))
+ return eStrataKernel;
+ }
+ }
+ return eStrataRawImage;
+
+ case MH_FVMLIB: return eStrataUser; // 0x3u
+ case MH_CORE: return eStrataUnknown; // 0x4u
+ case MH_PRELOAD: return eStrataRawImage; // 0x5u
+ case MH_DYLIB: return eStrataUser; // 0x6u
+ case MH_DYLINKER: return eStrataUser; // 0x7u
+ case MH_BUNDLE: return eStrataUser; // 0x8u
+ case MH_DYLIB_STUB: return eStrataUser; // 0x9u
+ case MH_DSYM: return eStrataUnknown; // 0xAu
+ case MH_KEXT_BUNDLE: return eStrataKernel; // 0xBu
+ default:
+ break;
+ }
+ return eStrataUnknown;
+}
+
+uint32_t
+ObjectFileMachO::GetVersion (uint32_t *versions, uint32_t num_versions)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ struct dylib_command load_cmd;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t version_cmd = 0;
+ uint64_t version = 0;
+ uint32_t i;
+ for (i=0; i<m_header.ncmds; ++i)
+ {
+ const lldb::offset_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ if (load_cmd.cmd == LC_ID_DYLIB)
+ {
+ if (version_cmd == 0)
+ {
+ version_cmd = load_cmd.cmd;
+ if (m_data.GetU32(&offset, &load_cmd.dylib, 4) == NULL)
+ break;
+ version = load_cmd.dylib.current_version;
+ }
+ break; // Break for now unless there is another more complete version
+ // number load command in the future.
+ }
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+
+ if (version_cmd == LC_ID_DYLIB)
+ {
+ if (versions != NULL && num_versions > 0)
+ {
+ if (num_versions > 0)
+ versions[0] = (version & 0xFFFF0000ull) >> 16;
+ if (num_versions > 1)
+ versions[1] = (version & 0x0000FF00ull) >> 8;
+ if (num_versions > 2)
+ versions[2] = (version & 0x000000FFull);
+ // Fill in an remaining version numbers with invalid values
+ for (i=3; i<num_versions; ++i)
+ versions[i] = UINT32_MAX;
+ }
+ // The LC_ID_DYLIB load command has a version with 3 version numbers
+ // in it, so always return 3
+ return 3;
+ }
+ }
+ return false;
+}
+
+bool
+ObjectFileMachO::GetArchitecture (ArchSpec &arch)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ return GetArchitecture (m_header, m_data, MachHeaderSizeFromMagic(m_header.magic), arch);
+ }
+ return false;
+}
+
+UUID
+ObjectFileMachO::GetProcessSharedCacheUUID (Process *process)
+{
+ UUID uuid;
+ if (process)
+ {
+ addr_t all_image_infos = process->GetImageInfoAddress();
+
+ // The address returned by GetImageInfoAddress may be the address of dyld (don't want)
+ // or it may be the address of the dyld_all_image_infos structure (want). The first four
+ // bytes will be either the version field (all_image_infos) or a Mach-O file magic constant.
+ // Version 13 and higher of dyld_all_image_infos is required to get the sharedCacheUUID field.
+
+ Error err;
+ uint32_t version_or_magic = process->ReadUnsignedIntegerFromMemory (all_image_infos, 4, -1, err);
+ if (version_or_magic != static_cast<uint32_t>(-1)
+ && version_or_magic != MH_MAGIC
+ && version_or_magic != MH_CIGAM
+ && version_or_magic != MH_MAGIC_64
+ && version_or_magic != MH_CIGAM_64
+ && version_or_magic >= 13)
+ {
+ addr_t sharedCacheUUID_address = LLDB_INVALID_ADDRESS;
+ int wordsize = process->GetAddressByteSize();
+ if (wordsize == 8)
+ {
+ sharedCacheUUID_address = all_image_infos + 160; // sharedCacheUUID <mach-o/dyld_images.h>
+ }
+ if (wordsize == 4)
+ {
+ sharedCacheUUID_address = all_image_infos + 84; // sharedCacheUUID <mach-o/dyld_images.h>
+ }
+ if (sharedCacheUUID_address != LLDB_INVALID_ADDRESS)
+ {
+ uuid_t shared_cache_uuid;
+ if (process->ReadMemory (sharedCacheUUID_address, shared_cache_uuid, sizeof (uuid_t), err) == sizeof (uuid_t))
+ {
+ uuid.SetBytes (shared_cache_uuid);
+ }
+ }
+ }
+ }
+ return uuid;
+}
+
+UUID
+ObjectFileMachO::GetLLDBSharedCacheUUID ()
+{
+ UUID uuid;
+#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__))
+ uint8_t *(*dyld_get_all_image_infos)(void);
+ dyld_get_all_image_infos = (uint8_t*(*)()) dlsym (RTLD_DEFAULT, "_dyld_get_all_image_infos");
+ if (dyld_get_all_image_infos)
+ {
+ uint8_t *dyld_all_image_infos_address = dyld_get_all_image_infos();
+ if (dyld_all_image_infos_address)
+ {
+ uint32_t *version = (uint32_t*) dyld_all_image_infos_address; // version <mach-o/dyld_images.h>
+ if (*version >= 13)
+ {
+ uuid_t *sharedCacheUUID_address = 0;
+ int wordsize = sizeof (uint8_t *);
+ if (wordsize == 8)
+ {
+ sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 160); // sharedCacheUUID <mach-o/dyld_images.h>
+ }
+ else
+ {
+ sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 84); // sharedCacheUUID <mach-o/dyld_images.h>
+ }
+ uuid.SetBytes (sharedCacheUUID_address);
+ }
+ }
+ }
+#endif
+ return uuid;
+}
+
+uint32_t
+ObjectFileMachO::GetMinimumOSVersion (uint32_t *versions, uint32_t num_versions)
+{
+ if (m_min_os_versions.empty())
+ {
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ bool success = false;
+ for (uint32_t i=0; success == false && i < m_header.ncmds; ++i)
+ {
+ const lldb::offset_t load_cmd_offset = offset;
+
+ version_min_command lc;
+ if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
+ break;
+ if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX
+ || lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS
+ || lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS
+ || lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS)
+ {
+ if (m_data.GetU32 (&offset, &lc.version, (sizeof(lc) / sizeof(uint32_t)) - 2))
+ {
+ const uint32_t xxxx = lc.version >> 16;
+ const uint32_t yy = (lc.version >> 8) & 0xffu;
+ const uint32_t zz = lc.version & 0xffu;
+ if (xxxx)
+ {
+ m_min_os_versions.push_back(xxxx);
+ m_min_os_versions.push_back(yy);
+ m_min_os_versions.push_back(zz);
+ }
+ success = true;
+ }
+ }
+ offset = load_cmd_offset + lc.cmdsize;
+ }
+
+ if (success == false)
+ {
+ // Push an invalid value so we don't keep trying to
+ m_min_os_versions.push_back(UINT32_MAX);
+ }
+ }
+
+ if (m_min_os_versions.size() > 1 || m_min_os_versions[0] != UINT32_MAX)
+ {
+ if (versions != NULL && num_versions > 0)
+ {
+ for (size_t i=0; i<num_versions; ++i)
+ {
+ if (i < m_min_os_versions.size())
+ versions[i] = m_min_os_versions[i];
+ else
+ versions[i] = 0;
+ }
+ }
+ return m_min_os_versions.size();
+ }
+ // Call the superclasses version that will empty out the data
+ return ObjectFile::GetMinimumOSVersion (versions, num_versions);
+}
+
+uint32_t
+ObjectFileMachO::GetSDKVersion(uint32_t *versions, uint32_t num_versions)
+{
+ if (m_sdk_versions.empty())
+ {
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ bool success = false;
+ for (uint32_t i=0; success == false && i < m_header.ncmds; ++i)
+ {
+ const lldb::offset_t load_cmd_offset = offset;
+
+ version_min_command lc;
+ if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
+ break;
+ if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX
+ || lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS
+ || lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS
+ || lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS)
+ {
+ if (m_data.GetU32 (&offset, &lc.version, (sizeof(lc) / sizeof(uint32_t)) - 2))
+ {
+ const uint32_t xxxx = lc.sdk >> 16;
+ const uint32_t yy = (lc.sdk >> 8) & 0xffu;
+ const uint32_t zz = lc.sdk & 0xffu;
+ if (xxxx)
+ {
+ m_sdk_versions.push_back(xxxx);
+ m_sdk_versions.push_back(yy);
+ m_sdk_versions.push_back(zz);
+ }
+ success = true;
+ }
+ }
+ offset = load_cmd_offset + lc.cmdsize;
+ }
+
+ if (success == false)
+ {
+ // Push an invalid value so we don't keep trying to
+ m_sdk_versions.push_back(UINT32_MAX);
+ }
+ }
+
+ if (m_sdk_versions.size() > 1 || m_sdk_versions[0] != UINT32_MAX)
+ {
+ if (versions != NULL && num_versions > 0)
+ {
+ for (size_t i=0; i<num_versions; ++i)
+ {
+ if (i < m_sdk_versions.size())
+ versions[i] = m_sdk_versions[i];
+ else
+ versions[i] = 0;
+ }
+ }
+ return m_sdk_versions.size();
+ }
+ // Call the superclasses version that will empty out the data
+ return ObjectFile::GetSDKVersion (versions, num_versions);
+}
+
+bool
+ObjectFileMachO::GetIsDynamicLinkEditor()
+{
+ return m_header.filetype == llvm::MachO::MH_DYLINKER;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ObjectFileMachO::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectFileMachO::GetPluginVersion()
+{
+ return 1;
+}
+
+Section *
+ObjectFileMachO::GetMachHeaderSection()
+{
+ // Find the first address of the mach header which is the first non-zero
+ // file sized section whose file offset is zero. This is the base file address
+ // of the mach-o file which can be subtracted from the vmaddr of the other
+ // segments found in memory and added to the load address
+ ModuleSP module_sp = GetModule();
+ if (module_sp)
+ {
+ SectionList *section_list = GetSectionList ();
+ if (section_list)
+ {
+ lldb::addr_t mach_base_file_addr = LLDB_INVALID_ADDRESS;
+ const size_t num_sections = section_list->GetSize();
+
+ for (size_t sect_idx = 0;
+ sect_idx < num_sections && mach_base_file_addr == LLDB_INVALID_ADDRESS;
+ ++sect_idx)
+ {
+ Section *section = section_list->GetSectionAtIndex (sect_idx).get();
+ if (section &&
+ section->GetFileSize() > 0 &&
+ section->GetFileOffset() == 0 &&
+ section->IsThreadSpecific() == false &&
+ module_sp.get() == section->GetModule().get())
+ {
+ return section;
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+lldb::addr_t
+ObjectFileMachO::CalculateSectionLoadAddressForMemoryImage(lldb::addr_t mach_header_load_address, const Section *mach_header_section, const Section *section)
+{
+ ModuleSP module_sp = GetModule();
+ if (module_sp && mach_header_section && section && mach_header_load_address != LLDB_INVALID_ADDRESS)
+ {
+ lldb::addr_t mach_header_file_addr = mach_header_section->GetFileAddress();
+ if (mach_header_file_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (section &&
+ section->GetFileSize() > 0 &&
+ section->IsThreadSpecific() == false &&
+ module_sp.get() == section->GetModule().get())
+ {
+ // Ignore __LINKEDIT and __DWARF segments
+ if (section->GetName() == GetSegmentNameLINKEDIT())
+ {
+ // Only map __LINKEDIT if we have an in memory image and this isn't
+ // a kernel binary like a kext or mach_kernel.
+ const bool is_memory_image = (bool)m_process_wp.lock();
+ const Strata strata = GetStrata();
+ if (is_memory_image == false || strata == eStrataKernel)
+ return LLDB_INVALID_ADDRESS;
+ }
+ return section->GetFileAddress() - mach_header_file_addr + mach_header_load_address;
+ }
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+ObjectFileMachO::SetLoadAddress (Target &target,
+ lldb::addr_t value,
+ bool value_is_offset)
+{
+ ModuleSP module_sp = GetModule();
+ if (module_sp)
+ {
+ size_t num_loaded_sections = 0;
+ SectionList *section_list = GetSectionList ();
+ if (section_list)
+ {
+ const size_t num_sections = section_list->GetSize();
+
+ if (value_is_offset)
+ {
+ // "value" is an offset to apply to each top level segment
+ for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ // Iterate through the object file sections to find all
+ // of the sections that size on disk (to avoid __PAGEZERO)
+ // and load them
+ SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
+ if (section_sp &&
+ section_sp->GetFileSize() > 0 &&
+ section_sp->IsThreadSpecific() == false &&
+ module_sp.get() == section_sp->GetModule().get())
+ {
+ // Ignore __LINKEDIT and __DWARF segments
+ if (section_sp->GetName() == GetSegmentNameLINKEDIT())
+ {
+ // Only map __LINKEDIT if we have an in memory image and this isn't
+ // a kernel binary like a kext or mach_kernel.
+ const bool is_memory_image = (bool)m_process_wp.lock();
+ const Strata strata = GetStrata();
+ if (is_memory_image == false || strata == eStrataKernel)
+ continue;
+ }
+ if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value))
+ ++num_loaded_sections;
+ }
+ }
+ }
+ else
+ {
+ // "value" is the new base address of the mach_header, adjust each
+ // section accordingly
+
+ Section *mach_header_section = GetMachHeaderSection();
+ if (mach_header_section)
+ {
+ for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
+
+ lldb::addr_t section_load_addr = CalculateSectionLoadAddressForMemoryImage(value, mach_header_section, section_sp.get());
+ if (section_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_load_addr))
+ ++num_loaded_sections;
+ }
+ }
+ }
+ }
+ }
+ return num_loaded_sections > 0;
+ }
+ return false;
+}
+
+bool
+ObjectFileMachO::SaveCore (const lldb::ProcessSP &process_sp,
+ const FileSpec &outfile,
+ Error &error)
+{
+ if (process_sp)
+ {
+ Target &target = process_sp->GetTarget();
+ const ArchSpec target_arch = target.GetArchitecture();
+ const llvm::Triple &target_triple = target_arch.GetTriple();
+ if (target_triple.getVendor() == llvm::Triple::Apple &&
+ (target_triple.getOS() == llvm::Triple::MacOSX
+ || target_triple.getOS() == llvm::Triple::IOS
+ || target_triple.getOS() == llvm::Triple::WatchOS
+ || target_triple.getOS() == llvm::Triple::TvOS))
+ {
+ bool make_core = false;
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ make_core = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unsupported core architecture: %s", target_triple.str().c_str());
+ break;
+ }
+
+ if (make_core)
+ {
+ std::vector<segment_command_64> segment_load_commands;
+// uint32_t range_info_idx = 0;
+ MemoryRegionInfo range_info;
+ Error range_error = process_sp->GetMemoryRegionInfo(0, range_info);
+ const uint32_t addr_byte_size = target_arch.GetAddressByteSize();
+ const ByteOrder byte_order = target_arch.GetByteOrder();
+ if (range_error.Success())
+ {
+ while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS)
+ {
+ const addr_t addr = range_info.GetRange().GetRangeBase();
+ const addr_t size = range_info.GetRange().GetByteSize();
+
+ if (size == 0)
+ break;
+
+ // Calculate correct protections
+ uint32_t prot = 0;
+ if (range_info.GetReadable() == MemoryRegionInfo::eYes)
+ prot |= VM_PROT_READ;
+ if (range_info.GetWritable() == MemoryRegionInfo::eYes)
+ prot |= VM_PROT_WRITE;
+ if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
+ prot |= VM_PROT_EXECUTE;
+
+// printf ("[%3u] [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") %c%c%c\n",
+// range_info_idx,
+// addr,
+// size,
+// (prot & VM_PROT_READ ) ? 'r' : '-',
+// (prot & VM_PROT_WRITE ) ? 'w' : '-',
+// (prot & VM_PROT_EXECUTE) ? 'x' : '-');
+
+ if (prot != 0)
+ {
+ uint32_t cmd_type = LC_SEGMENT_64;
+ uint32_t segment_size = sizeof (segment_command_64);
+ if (addr_byte_size == 4)
+ {
+ cmd_type = LC_SEGMENT;
+ segment_size = sizeof (segment_command);
+ }
+ segment_command_64 segment = {
+ cmd_type, // uint32_t cmd;
+ segment_size, // uint32_t cmdsize;
+ {0}, // char segname[16];
+ addr, // uint64_t vmaddr; // uint32_t for 32-bit Mach-O
+ size, // uint64_t vmsize; // uint32_t for 32-bit Mach-O
+ 0, // uint64_t fileoff; // uint32_t for 32-bit Mach-O
+ size, // uint64_t filesize; // uint32_t for 32-bit Mach-O
+ prot, // uint32_t maxprot;
+ prot, // uint32_t initprot;
+ 0, // uint32_t nsects;
+ 0 }; // uint32_t flags;
+ segment_load_commands.push_back(segment);
+ }
+ else
+ {
+ // No protections and a size of 1 used to be returned from old
+ // debugservers when we asked about a region that was past the
+ // last memory region and it indicates the end...
+ if (size == 1)
+ break;
+ }
+
+ range_error = process_sp->GetMemoryRegionInfo(range_info.GetRange().GetRangeEnd(), range_info);
+ if (range_error.Fail())
+ break;
+ }
+
+ StreamString buffer (Stream::eBinary,
+ addr_byte_size,
+ byte_order);
+
+ mach_header_64 mach_header;
+ if (addr_byte_size == 8)
+ {
+ mach_header.magic = MH_MAGIC_64;
+ }
+ else
+ {
+ mach_header.magic = MH_MAGIC;
+ }
+ mach_header.cputype = target_arch.GetMachOCPUType();
+ mach_header.cpusubtype = target_arch.GetMachOCPUSubType();
+ mach_header.filetype = MH_CORE;
+ mach_header.ncmds = segment_load_commands.size();
+ mach_header.flags = 0;
+ mach_header.reserved = 0;
+ ThreadList &thread_list = process_sp->GetThreadList();
+ const uint32_t num_threads = thread_list.GetSize();
+
+ // Make an array of LC_THREAD data items. Each one contains
+ // the contents of the LC_THREAD load command. The data doesn't
+ // contain the load command + load command size, we will
+ // add the load command and load command size as we emit the data.
+ std::vector<StreamString> LC_THREAD_datas(num_threads);
+ for (auto &LC_THREAD_data : LC_THREAD_datas)
+ {
+ LC_THREAD_data.GetFlags().Set(Stream::eBinary);
+ LC_THREAD_data.SetAddressByteSize(addr_byte_size);
+ LC_THREAD_data.SetByteOrder(byte_order);
+ }
+ for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx)
+ {
+ ThreadSP thread_sp (thread_list.GetThreadAtIndex(thread_idx));
+ if (thread_sp)
+ {
+ switch (mach_header.cputype)
+ {
+ case llvm::MachO::CPU_TYPE_ARM64:
+ RegisterContextDarwin_arm64_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]);
+ break;
+
+ case llvm::MachO::CPU_TYPE_ARM:
+ RegisterContextDarwin_arm_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]);
+ break;
+
+ case llvm::MachO::CPU_TYPE_I386:
+ RegisterContextDarwin_i386_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]);
+ break;
+
+ case llvm::MachO::CPU_TYPE_X86_64:
+ RegisterContextDarwin_x86_64_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]);
+ break;
+ }
+
+ }
+ }
+
+ // The size of the load command is the size of the segments...
+ if (addr_byte_size == 8)
+ {
+ mach_header.sizeofcmds = segment_load_commands.size() * sizeof (struct segment_command_64);
+ }
+ else
+ {
+ mach_header.sizeofcmds = segment_load_commands.size() * sizeof (struct segment_command);
+ }
+
+ // and the size of all LC_THREAD load command
+ for (const auto &LC_THREAD_data : LC_THREAD_datas)
+ {
+ ++mach_header.ncmds;
+ mach_header.sizeofcmds += 8 + LC_THREAD_data.GetSize();
+ }
+
+ printf ("mach_header: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
+ mach_header.magic,
+ mach_header.cputype,
+ mach_header.cpusubtype,
+ mach_header.filetype,
+ mach_header.ncmds,
+ mach_header.sizeofcmds,
+ mach_header.flags,
+ mach_header.reserved);
+
+ // Write the mach header
+ buffer.PutHex32(mach_header.magic);
+ buffer.PutHex32(mach_header.cputype);
+ buffer.PutHex32(mach_header.cpusubtype);
+ buffer.PutHex32(mach_header.filetype);
+ buffer.PutHex32(mach_header.ncmds);
+ buffer.PutHex32(mach_header.sizeofcmds);
+ buffer.PutHex32(mach_header.flags);
+ if (addr_byte_size == 8)
+ {
+ buffer.PutHex32(mach_header.reserved);
+ }
+
+ // Skip the mach header and all load commands and align to the next
+ // 0x1000 byte boundary
+ addr_t file_offset = buffer.GetSize() + mach_header.sizeofcmds;
+ if (file_offset & 0x00000fff)
+ {
+ file_offset += 0x00001000ull;
+ file_offset &= (~0x00001000ull + 1);
+ }
+
+ for (auto &segment : segment_load_commands)
+ {
+ segment.fileoff = file_offset;
+ file_offset += segment.filesize;
+ }
+
+ // Write out all of the LC_THREAD load commands
+ for (const auto &LC_THREAD_data : LC_THREAD_datas)
+ {
+ const size_t LC_THREAD_data_size = LC_THREAD_data.GetSize();
+ buffer.PutHex32(LC_THREAD);
+ buffer.PutHex32(8 + LC_THREAD_data_size); // cmd + cmdsize + data
+ buffer.Write(LC_THREAD_data.GetData(), LC_THREAD_data_size);
+ }
+
+ // Write out all of the segment load commands
+ for (const auto &segment : segment_load_commands)
+ {
+ printf ("0x%8.8x 0x%8.8x [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") [0x%16.16" PRIx64 " 0x%16.16" PRIx64 ") 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x]\n",
+ segment.cmd,
+ segment.cmdsize,
+ segment.vmaddr,
+ segment.vmaddr + segment.vmsize,
+ segment.fileoff,
+ segment.filesize,
+ segment.maxprot,
+ segment.initprot,
+ segment.nsects,
+ segment.flags);
+
+ buffer.PutHex32(segment.cmd);
+ buffer.PutHex32(segment.cmdsize);
+ buffer.PutRawBytes(segment.segname, sizeof(segment.segname));
+ if (addr_byte_size == 8)
+ {
+ buffer.PutHex64(segment.vmaddr);
+ buffer.PutHex64(segment.vmsize);
+ buffer.PutHex64(segment.fileoff);
+ buffer.PutHex64(segment.filesize);
+ }
+ else
+ {
+ buffer.PutHex32(static_cast<uint32_t>(segment.vmaddr));
+ buffer.PutHex32(static_cast<uint32_t>(segment.vmsize));
+ buffer.PutHex32(static_cast<uint32_t>(segment.fileoff));
+ buffer.PutHex32(static_cast<uint32_t>(segment.filesize));
+ }
+ buffer.PutHex32(segment.maxprot);
+ buffer.PutHex32(segment.initprot);
+ buffer.PutHex32(segment.nsects);
+ buffer.PutHex32(segment.flags);
+ }
+
+ File core_file;
+ std::string core_file_path(outfile.GetPath());
+ error = core_file.Open(core_file_path.c_str(),
+ File::eOpenOptionWrite |
+ File::eOpenOptionTruncate |
+ File::eOpenOptionCanCreate);
+ if (error.Success())
+ {
+ // Read 1 page at a time
+ uint8_t bytes[0x1000];
+ // Write the mach header and load commands out to the core file
+ size_t bytes_written = buffer.GetString().size();
+ error = core_file.Write(buffer.GetString().data(), bytes_written);
+ if (error.Success())
+ {
+ // Now write the file data for all memory segments in the process
+ for (const auto &segment : segment_load_commands)
+ {
+ if (core_file.SeekFromStart(segment.fileoff) == -1)
+ {
+ error.SetErrorStringWithFormat("unable to seek to offset 0x%" PRIx64 " in '%s'", segment.fileoff, core_file_path.c_str());
+ break;
+ }
+
+ printf ("Saving %" PRId64 " bytes of data for memory region at 0x%" PRIx64 "\n", segment.vmsize, segment.vmaddr);
+ addr_t bytes_left = segment.vmsize;
+ addr_t addr = segment.vmaddr;
+ Error memory_read_error;
+ while (bytes_left > 0 && error.Success())
+ {
+ const size_t bytes_to_read = bytes_left > sizeof(bytes) ? sizeof(bytes) : bytes_left;
+ const size_t bytes_read = process_sp->ReadMemory(addr, bytes, bytes_to_read, memory_read_error);
+ if (bytes_read == bytes_to_read)
+ {
+ size_t bytes_written = bytes_read;
+ error = core_file.Write(bytes, bytes_written);
+ bytes_left -= bytes_read;
+ addr += bytes_read;
+ }
+ else
+ {
+ // Some pages within regions are not readable, those
+ // should be zero filled
+ memset (bytes, 0, bytes_to_read);
+ size_t bytes_written = bytes_to_read;
+ error = core_file.Write(bytes, bytes_written);
+ bytes_left -= bytes_to_read;
+ addr += bytes_to_read;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("process doesn't support getting memory region info");
+ }
+ }
+ return true; // This is the right plug to handle saving core files for this process
+ }
+ }
+ return false;
+}
diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
new file mode 100644
index 000000000000..6b7ad531b83b
--- /dev/null
+++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
@@ -0,0 +1,252 @@
+//===-- ObjectFileMachO.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_ObjectFileMachO_h_
+#define liblldb_ObjectFileMachO_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Utility/SafeMachO.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+//----------------------------------------------------------------------
+// This class needs to be hidden as eventually belongs in a plugin that
+// will export the ObjectFile protocol
+//----------------------------------------------------------------------
+class ObjectFileMachO :
+ public lldb_private::ObjectFile
+{
+public:
+ ObjectFileMachO(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t offset,
+ lldb::offset_t length);
+
+ ObjectFileMachO(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr);
+
+ ~ObjectFileMachO() override = default;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectFile *
+ CreateInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length);
+
+ static lldb_private::ObjectFile *
+ CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr);
+
+ static size_t
+ GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs);
+
+ static bool
+ SaveCore (const lldb::ProcessSP &process_sp,
+ const lldb_private::FileSpec &outfile,
+ lldb_private::Error &error);
+
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& data_sp,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ bool
+ ParseHeader() override;
+
+ bool
+ SetLoadAddress(lldb_private::Target &target,
+ lldb::addr_t value,
+ bool value_is_offset) override;
+
+ lldb::ByteOrder
+ GetByteOrder() const override;
+
+ bool
+ IsExecutable() const override;
+
+ uint32_t
+ GetAddressByteSize() const override;
+
+ lldb::AddressClass
+ GetAddressClass(lldb::addr_t file_addr) override;
+
+ lldb_private::Symtab *
+ GetSymtab() override;
+
+ bool
+ IsStripped() override;
+
+ void
+ CreateSections(lldb_private::SectionList &unified_section_list) override;
+
+ void
+ Dump(lldb_private::Stream *s) override;
+
+ bool
+ GetArchitecture(lldb_private::ArchSpec &arch) override;
+
+ bool
+ GetUUID(lldb_private::UUID* uuid) override;
+
+ uint32_t
+ GetDependentModules(lldb_private::FileSpecList& files) override;
+
+ lldb_private::FileSpecList
+ GetReExportedLibraries() override
+ {
+ return m_reexported_dylibs;
+ }
+
+ lldb_private::Address
+ GetEntryPointAddress() override;
+
+ lldb_private::Address
+ GetHeaderAddress() override;
+
+ uint32_t
+ GetNumThreadContexts() override;
+
+ lldb::RegisterContextSP
+ GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) override;
+
+ ObjectFile::Type
+ CalculateType() override;
+
+ ObjectFile::Strata
+ CalculateStrata() override;
+
+ uint32_t
+ GetVersion(uint32_t *versions, uint32_t num_versions) override;
+
+ uint32_t
+ GetMinimumOSVersion(uint32_t *versions, uint32_t num_versions) override;
+
+ uint32_t
+ GetSDKVersion(uint32_t *versions, uint32_t num_versions) override;
+
+ bool
+ GetIsDynamicLinkEditor() override;
+
+ static bool
+ ParseHeader (lldb_private::DataExtractor &data,
+ lldb::offset_t *data_offset_ptr,
+ llvm::MachO::mach_header &header);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+protected:
+ static bool
+ GetUUID (const llvm::MachO::mach_header &header,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t lc_offset, // Offset to the first load command
+ lldb_private::UUID& uuid);
+
+ static bool
+ GetArchitecture (const llvm::MachO::mach_header &header,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t lc_offset,
+ lldb_private::ArchSpec &arch);
+
+ // Intended for same-host arm device debugging where lldb needs to
+ // detect libraries in the shared cache and augment the nlist entries
+ // with an on-disk dyld_shared_cache file. The process will record
+ // the shared cache UUID so the on-disk cache can be matched or rejected
+ // correctly.
+ lldb_private::UUID
+ GetProcessSharedCacheUUID (lldb_private::Process *);
+
+ // Intended for same-host arm device debugging where lldb will read
+ // shared cache libraries out of its own memory instead of the remote
+ // process' memory as an optimization. If lldb's shared cache UUID
+ // does not match the process' shared cache UUID, this optimization
+ // should not be used.
+ lldb_private::UUID
+ GetLLDBSharedCacheUUID ();
+
+ lldb_private::Section *
+ GetMachHeaderSection();
+
+ lldb::addr_t
+ CalculateSectionLoadAddressForMemoryImage(lldb::addr_t mach_header_load_address,
+ const lldb_private::Section *mach_header_section,
+ const lldb_private::Section *section);
+
+ lldb_private::UUID
+ GetSharedCacheUUID (lldb_private::FileSpec dyld_shared_cache, const lldb::ByteOrder byte_order, const uint32_t addr_byte_size);
+
+ size_t
+ ParseSymtab();
+
+ llvm::MachO::mach_header m_header;
+ static const lldb_private::ConstString &GetSegmentNameTEXT();
+ static const lldb_private::ConstString &GetSegmentNameDATA();
+ static const lldb_private::ConstString &GetSegmentNameDATA_DIRTY();
+ static const lldb_private::ConstString &GetSegmentNameDATA_CONST();
+ static const lldb_private::ConstString &GetSegmentNameOBJC();
+ static const lldb_private::ConstString &GetSegmentNameLINKEDIT();
+ static const lldb_private::ConstString &GetSectionNameEHFrame();
+
+ llvm::MachO::dysymtab_command m_dysymtab;
+ std::vector<llvm::MachO::segment_command_64> m_mach_segments;
+ std::vector<llvm::MachO::section_64> m_mach_sections;
+ std::vector<uint32_t> m_min_os_versions;
+ std::vector<uint32_t> m_sdk_versions;
+ typedef lldb_private::RangeVector<uint32_t, uint32_t> FileRangeArray;
+ lldb_private::Address m_entry_point_address;
+ FileRangeArray m_thread_context_offsets;
+ bool m_thread_context_offsets_valid;
+ lldb_private::FileSpecList m_reexported_dylibs;
+};
+
+#endif // liblldb_ObjectFileMachO_h_
diff --git a/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt b/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt
new file mode 100644
index 000000000000..5c7c488f362f
--- /dev/null
+++ b/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_lldb_library(lldbPluginObjectFilePECOFF
+ ObjectFilePECOFF.cpp
+ WindowsMiniDump.cpp
+ )
diff --git a/source/Plugins/ObjectFile/PECOFF/Makefile b/source/Plugins/ObjectFile/PECOFF/Makefile
new file mode 100644
index 000000000000..1b5abc461e82
--- /dev/null
+++ b/source/Plugins/ObjectFile/PECOFF/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ObjectFile/PECOFF/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginObjectFilePECOFF
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
new file mode 100644
index 000000000000..b66244813240
--- /dev/null
+++ b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
@@ -0,0 +1,1056 @@
+//===-- ObjectFilePECOFF.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectFilePECOFF.h"
+#include "WindowsMiniDump.h"
+
+#include "llvm/Support/COFF.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+
+#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
+#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
+#define OPT_HEADER_MAGIC_PE32 0x010b
+#define OPT_HEADER_MAGIC_PE32_PLUS 0x020b
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+ObjectFilePECOFF::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ CreateMemoryInstance,
+ GetModuleSpecifications,
+ SaveCore);
+}
+
+void
+ObjectFilePECOFF::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+ObjectFilePECOFF::GetPluginNameStatic()
+{
+ static ConstString g_name("pe-coff");
+ return g_name;
+}
+
+const char *
+ObjectFilePECOFF::GetPluginDescriptionStatic()
+{
+ return "Portable Executable and Common Object File Format object file reader (32 and 64 bit)";
+}
+
+
+ObjectFile *
+ObjectFilePECOFF::CreateInstance (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length)
+{
+ if (!data_sp)
+ {
+ data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
+ data_offset = 0;
+ }
+
+ if (ObjectFilePECOFF::MagicBytesMatch(data_sp))
+ {
+ // Update the data to contain the entire file if it doesn't already
+ if (data_sp->GetByteSize() < length)
+ data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
+ std::unique_ptr<ObjectFile> objfile_ap(new ObjectFilePECOFF (module_sp, data_sp, data_offset, file, file_offset, length));
+ if (objfile_ap.get() && objfile_ap->ParseHeader())
+ return objfile_ap.release();
+ }
+ return NULL;
+}
+
+ObjectFile *
+ObjectFilePECOFF::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr)
+{
+ return NULL;
+}
+
+size_t
+ObjectFilePECOFF::GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs)
+{
+ const size_t initial_count = specs.GetSize();
+
+ if (ObjectFilePECOFF::MagicBytesMatch(data_sp))
+ {
+ DataExtractor data;
+ data.SetData(data_sp, data_offset, length);
+ data.SetByteOrder(eByteOrderLittle);
+
+ dos_header_t dos_header;
+ coff_header_t coff_header;
+
+ if (ParseDOSHeader(data, dos_header))
+ {
+ lldb::offset_t offset = dos_header.e_lfanew;
+ uint32_t pe_signature = data.GetU32(&offset);
+ if (pe_signature != IMAGE_NT_SIGNATURE)
+ return false;
+ if (ParseCOFFHeader(data, &offset, coff_header))
+ {
+ ArchSpec spec;
+ if (coff_header.machine == MachineAmd64)
+ {
+ spec.SetTriple("x86_64-pc-windows");
+ specs.Append(ModuleSpec(file, spec));
+ }
+ else if (coff_header.machine == MachineX86)
+ {
+ spec.SetTriple("i386-pc-windows");
+ specs.Append(ModuleSpec(file, spec));
+ spec.SetTriple("i686-pc-windows");
+ specs.Append(ModuleSpec(file, spec));
+ }
+ }
+ }
+ }
+
+ return specs.GetSize() - initial_count;
+}
+
+bool
+ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp,
+ const lldb_private::FileSpec &outfile,
+ lldb_private::Error &error)
+{
+ return SaveMiniDump(process_sp, outfile, error);
+}
+
+
+bool
+ObjectFilePECOFF::MagicBytesMatch (DataBufferSP& data_sp)
+{
+ DataExtractor data(data_sp, eByteOrderLittle, 4);
+ lldb::offset_t offset = 0;
+ uint16_t magic = data.GetU16 (&offset);
+ return magic == IMAGE_DOS_SIGNATURE;
+}
+
+
+ObjectFilePECOFF::ObjectFilePECOFF (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length) :
+ ObjectFile (module_sp, file, file_offset, length, data_sp, data_offset),
+ m_dos_header (),
+ m_coff_header (),
+ m_coff_header_opt (),
+ m_sect_headers ()
+{
+ ::memset (&m_dos_header, 0, sizeof(m_dos_header));
+ ::memset (&m_coff_header, 0, sizeof(m_coff_header));
+ ::memset (&m_coff_header_opt, 0, sizeof(m_coff_header_opt));
+}
+
+
+ObjectFilePECOFF::~ObjectFilePECOFF()
+{
+}
+
+
+bool
+ObjectFilePECOFF::ParseHeader ()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ m_sect_headers.clear();
+ m_data.SetByteOrder (eByteOrderLittle);
+ lldb::offset_t offset = 0;
+
+ if (ParseDOSHeader(m_data, m_dos_header))
+ {
+ offset = m_dos_header.e_lfanew;
+ uint32_t pe_signature = m_data.GetU32 (&offset);
+ if (pe_signature != IMAGE_NT_SIGNATURE)
+ return false;
+ if (ParseCOFFHeader(m_data, &offset, m_coff_header))
+ {
+ if (m_coff_header.hdrsize > 0)
+ ParseCOFFOptionalHeader(&offset);
+ ParseSectionHeaders (offset);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+ObjectFilePECOFF::SetLoadAddress(Target &target, addr_t value, bool value_is_offset)
+{
+ bool changed = false;
+ ModuleSP module_sp = GetModule();
+ if (module_sp)
+ {
+ size_t num_loaded_sections = 0;
+ SectionList *section_list = GetSectionList ();
+ if (section_list)
+ {
+ if (!value_is_offset)
+ {
+ value -= m_image_base;
+ }
+
+ const size_t num_sections = section_list->GetSize();
+ size_t sect_idx = 0;
+
+ for (sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ // Iterate through the object file sections to find all
+ // of the sections that have SHF_ALLOC in their flag bits.
+ SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
+ if (section_sp && !section_sp->IsThreadSpecific())
+ {
+ if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value))
+ ++num_loaded_sections;
+ }
+ }
+ changed = num_loaded_sections > 0;
+ }
+ }
+ return changed;
+}
+
+
+ByteOrder
+ObjectFilePECOFF::GetByteOrder () const
+{
+ return eByteOrderLittle;
+}
+
+bool
+ObjectFilePECOFF::IsExecutable() const
+{
+ return (m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0;
+}
+
+uint32_t
+ObjectFilePECOFF::GetAddressByteSize () const
+{
+ if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32_PLUS)
+ return 8;
+ else if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32)
+ return 4;
+ return 4;
+}
+
+//----------------------------------------------------------------------
+// NeedsEndianSwap
+//
+// Return true if an endian swap needs to occur when extracting data
+// from this file.
+//----------------------------------------------------------------------
+bool
+ObjectFilePECOFF::NeedsEndianSwap() const
+{
+#if defined(__LITTLE_ENDIAN__)
+ return false;
+#else
+ return true;
+#endif
+}
+//----------------------------------------------------------------------
+// ParseDOSHeader
+//----------------------------------------------------------------------
+bool
+ObjectFilePECOFF::ParseDOSHeader (DataExtractor &data, dos_header_t &dos_header)
+{
+ bool success = false;
+ lldb::offset_t offset = 0;
+ success = data.ValidOffsetForDataOfSize(0, sizeof(dos_header));
+
+ if (success)
+ {
+ dos_header.e_magic = data.GetU16(&offset); // Magic number
+ success = dos_header.e_magic == IMAGE_DOS_SIGNATURE;
+
+ if (success)
+ {
+ dos_header.e_cblp = data.GetU16(&offset); // Bytes on last page of file
+ dos_header.e_cp = data.GetU16(&offset); // Pages in file
+ dos_header.e_crlc = data.GetU16(&offset); // Relocations
+ dos_header.e_cparhdr = data.GetU16(&offset); // Size of header in paragraphs
+ dos_header.e_minalloc = data.GetU16(&offset); // Minimum extra paragraphs needed
+ dos_header.e_maxalloc = data.GetU16(&offset); // Maximum extra paragraphs needed
+ dos_header.e_ss = data.GetU16(&offset); // Initial (relative) SS value
+ dos_header.e_sp = data.GetU16(&offset); // Initial SP value
+ dos_header.e_csum = data.GetU16(&offset); // Checksum
+ dos_header.e_ip = data.GetU16(&offset); // Initial IP value
+ dos_header.e_cs = data.GetU16(&offset); // Initial (relative) CS value
+ dos_header.e_lfarlc = data.GetU16(&offset); // File address of relocation table
+ dos_header.e_ovno = data.GetU16(&offset); // Overlay number
+
+ dos_header.e_res[0] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res[1] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res[2] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res[3] = data.GetU16(&offset); // Reserved words
+
+ dos_header.e_oemid = data.GetU16(&offset); // OEM identifier (for e_oeminfo)
+ dos_header.e_oeminfo = data.GetU16(&offset); // OEM information; e_oemid specific
+ dos_header.e_res2[0] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res2[1] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res2[2] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res2[3] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res2[4] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res2[5] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res2[6] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res2[7] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res2[8] = data.GetU16(&offset); // Reserved words
+ dos_header.e_res2[9] = data.GetU16(&offset); // Reserved words
+
+ dos_header.e_lfanew = data.GetU32(&offset); // File address of new exe header
+ }
+ }
+ if (!success)
+ memset(&dos_header, 0, sizeof(dos_header));
+ return success;
+}
+
+
+//----------------------------------------------------------------------
+// ParserCOFFHeader
+//----------------------------------------------------------------------
+bool
+ObjectFilePECOFF::ParseCOFFHeader(DataExtractor &data, lldb::offset_t *offset_ptr, coff_header_t &coff_header)
+{
+ bool success = data.ValidOffsetForDataOfSize (*offset_ptr, sizeof(coff_header));
+ if (success)
+ {
+ coff_header.machine = data.GetU16(offset_ptr);
+ coff_header.nsects = data.GetU16(offset_ptr);
+ coff_header.modtime = data.GetU32(offset_ptr);
+ coff_header.symoff = data.GetU32(offset_ptr);
+ coff_header.nsyms = data.GetU32(offset_ptr);
+ coff_header.hdrsize = data.GetU16(offset_ptr);
+ coff_header.flags = data.GetU16(offset_ptr);
+ }
+ if (!success)
+ memset(&coff_header, 0, sizeof(coff_header));
+ return success;
+}
+
+bool
+ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr)
+{
+ bool success = false;
+ const lldb::offset_t end_offset = *offset_ptr + m_coff_header.hdrsize;
+ if (*offset_ptr < end_offset)
+ {
+ success = true;
+ m_coff_header_opt.magic = m_data.GetU16(offset_ptr);
+ m_coff_header_opt.major_linker_version = m_data.GetU8 (offset_ptr);
+ m_coff_header_opt.minor_linker_version = m_data.GetU8 (offset_ptr);
+ m_coff_header_opt.code_size = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.data_size = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.bss_size = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.entry = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.code_offset = m_data.GetU32(offset_ptr);
+
+ const uint32_t addr_byte_size = GetAddressByteSize ();
+
+ if (*offset_ptr < end_offset)
+ {
+ if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32)
+ {
+ // PE32 only
+ m_coff_header_opt.data_offset = m_data.GetU32(offset_ptr);
+ }
+ else
+ m_coff_header_opt.data_offset = 0;
+
+ if (*offset_ptr < end_offset)
+ {
+ m_coff_header_opt.image_base = m_data.GetMaxU64 (offset_ptr, addr_byte_size);
+ m_coff_header_opt.sect_alignment = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.file_alignment = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.major_os_system_version = m_data.GetU16(offset_ptr);
+ m_coff_header_opt.minor_os_system_version = m_data.GetU16(offset_ptr);
+ m_coff_header_opt.major_image_version = m_data.GetU16(offset_ptr);
+ m_coff_header_opt.minor_image_version = m_data.GetU16(offset_ptr);
+ m_coff_header_opt.major_subsystem_version = m_data.GetU16(offset_ptr);
+ m_coff_header_opt.minor_subsystem_version = m_data.GetU16(offset_ptr);
+ m_coff_header_opt.reserved1 = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.image_size = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.header_size = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.checksum = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.subsystem = m_data.GetU16(offset_ptr);
+ m_coff_header_opt.dll_flags = m_data.GetU16(offset_ptr);
+ m_coff_header_opt.stack_reserve_size = m_data.GetMaxU64 (offset_ptr, addr_byte_size);
+ m_coff_header_opt.stack_commit_size = m_data.GetMaxU64 (offset_ptr, addr_byte_size);
+ m_coff_header_opt.heap_reserve_size = m_data.GetMaxU64 (offset_ptr, addr_byte_size);
+ m_coff_header_opt.heap_commit_size = m_data.GetMaxU64 (offset_ptr, addr_byte_size);
+ m_coff_header_opt.loader_flags = m_data.GetU32(offset_ptr);
+ uint32_t num_data_dir_entries = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.data_dirs.clear();
+ m_coff_header_opt.data_dirs.resize(num_data_dir_entries);
+ uint32_t i;
+ for (i=0; i<num_data_dir_entries; i++)
+ {
+ m_coff_header_opt.data_dirs[i].vmaddr = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.data_dirs[i].vmsize = m_data.GetU32(offset_ptr);
+ }
+
+ m_file_offset = m_coff_header_opt.image_base;
+ m_image_base = m_coff_header_opt.image_base;
+ }
+ }
+ }
+ // Make sure we are on track for section data which follows
+ *offset_ptr = end_offset;
+ return success;
+}
+
+
+//----------------------------------------------------------------------
+// ParseSectionHeaders
+//----------------------------------------------------------------------
+bool
+ObjectFilePECOFF::ParseSectionHeaders (uint32_t section_header_data_offset)
+{
+ const uint32_t nsects = m_coff_header.nsects;
+ m_sect_headers.clear();
+
+ if (nsects > 0)
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize ();
+ const size_t section_header_byte_size = nsects * sizeof(section_header_t);
+ DataBufferSP section_header_data_sp(m_file.ReadFileContents (section_header_data_offset, section_header_byte_size));
+ DataExtractor section_header_data (section_header_data_sp, GetByteOrder(), addr_byte_size);
+
+ lldb::offset_t offset = 0;
+ if (section_header_data.ValidOffsetForDataOfSize (offset, section_header_byte_size))
+ {
+ m_sect_headers.resize(nsects);
+
+ for (uint32_t idx = 0; idx<nsects; ++idx)
+ {
+ const void *name_data = section_header_data.GetData(&offset, 8);
+ if (name_data)
+ {
+ memcpy(m_sect_headers[idx].name, name_data, 8);
+ m_sect_headers[idx].vmsize = section_header_data.GetU32(&offset);
+ m_sect_headers[idx].vmaddr = section_header_data.GetU32(&offset);
+ m_sect_headers[idx].size = section_header_data.GetU32(&offset);
+ m_sect_headers[idx].offset = section_header_data.GetU32(&offset);
+ m_sect_headers[idx].reloff = section_header_data.GetU32(&offset);
+ m_sect_headers[idx].lineoff = section_header_data.GetU32(&offset);
+ m_sect_headers[idx].nreloc = section_header_data.GetU16(&offset);
+ m_sect_headers[idx].nline = section_header_data.GetU16(&offset);
+ m_sect_headers[idx].flags = section_header_data.GetU32(&offset);
+ }
+ }
+ }
+ }
+
+ return m_sect_headers.empty() == false;
+}
+
+bool
+ObjectFilePECOFF::GetSectionName(std::string& sect_name, const section_header_t& sect)
+{
+ if (sect.name[0] == '/')
+ {
+ lldb::offset_t stroff = strtoul(&sect.name[1], NULL, 10);
+ lldb::offset_t string_file_offset = m_coff_header.symoff + (m_coff_header.nsyms * 18) + stroff;
+ const char *name = m_data.GetCStr (&string_file_offset);
+ if (name)
+ {
+ sect_name = name;
+ return true;
+ }
+
+ return false;
+ }
+ sect_name = sect.name;
+ return true;
+}
+
+//----------------------------------------------------------------------
+// GetNListSymtab
+//----------------------------------------------------------------------
+Symtab *
+ObjectFilePECOFF::GetSymtab()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_symtab_ap.get() == NULL)
+ {
+ SectionList *sect_list = GetSectionList();
+ m_symtab_ap.reset(new Symtab(this));
+ Mutex::Locker symtab_locker (m_symtab_ap->GetMutex());
+
+ const uint32_t num_syms = m_coff_header.nsyms;
+
+ if (num_syms > 0 && m_coff_header.symoff > 0)
+ {
+ const uint32_t symbol_size = 18;
+ const uint32_t addr_byte_size = GetAddressByteSize ();
+ const size_t symbol_data_size = num_syms * symbol_size;
+ // Include the 4 bytes string table size at the end of the symbols
+ DataBufferSP symtab_data_sp(m_file.ReadFileContents (m_coff_header.symoff, symbol_data_size + 4));
+ DataExtractor symtab_data (symtab_data_sp, GetByteOrder(), addr_byte_size);
+ lldb::offset_t offset = symbol_data_size;
+ const uint32_t strtab_size = symtab_data.GetU32 (&offset);
+ DataBufferSP strtab_data_sp(m_file.ReadFileContents (m_coff_header.symoff + symbol_data_size, strtab_size));
+ DataExtractor strtab_data (strtab_data_sp, GetByteOrder(), addr_byte_size);
+
+ // First 4 bytes should be zeroed after strtab_size has been read,
+ // because it is used as offset 0 to encode a NULL string.
+ uint32_t* strtab_data_start = (uint32_t*)strtab_data_sp->GetBytes();
+ strtab_data_start[0] = 0;
+
+ offset = 0;
+ std::string symbol_name;
+ Symbol *symbols = m_symtab_ap->Resize (num_syms);
+ for (uint32_t i=0; i<num_syms; ++i)
+ {
+ coff_symbol_t symbol;
+ const uint32_t symbol_offset = offset;
+ const char *symbol_name_cstr = NULL;
+ // If the first 4 bytes of the symbol string are zero, then we
+ // it is followed by a 4 byte string table offset. Else these
+ // 8 bytes contain the symbol name
+ if (symtab_data.GetU32 (&offset) == 0)
+ {
+ // Long string that doesn't fit into the symbol table name,
+ // so now we must read the 4 byte string table offset
+ uint32_t strtab_offset = symtab_data.GetU32 (&offset);
+ symbol_name_cstr = strtab_data.PeekCStr (strtab_offset);
+ symbol_name.assign (symbol_name_cstr);
+ }
+ else
+ {
+ // Short string that fits into the symbol table name which is 8 bytes
+ offset += sizeof(symbol.name) - 4; // Skip remaining
+ symbol_name_cstr = symtab_data.PeekCStr (symbol_offset);
+ if (symbol_name_cstr == NULL)
+ break;
+ symbol_name.assign (symbol_name_cstr, sizeof(symbol.name));
+ }
+ symbol.value = symtab_data.GetU32 (&offset);
+ symbol.sect = symtab_data.GetU16 (&offset);
+ symbol.type = symtab_data.GetU16 (&offset);
+ symbol.storage = symtab_data.GetU8 (&offset);
+ symbol.naux = symtab_data.GetU8 (&offset);
+ symbols[i].GetMangled ().SetValue (ConstString(symbol_name.c_str()));
+ if ((int16_t)symbol.sect >= 1)
+ {
+ Address symbol_addr(sect_list->GetSectionAtIndex(symbol.sect-1), symbol.value);
+ symbols[i].GetAddressRef() = symbol_addr;
+ }
+
+ if (symbol.naux > 0)
+ {
+ i += symbol.naux;
+ offset += symbol_size;
+ }
+ }
+
+ }
+
+ // Read export header
+ if (coff_data_dir_export_table < m_coff_header_opt.data_dirs.size()
+ && m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmsize > 0 && m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr > 0)
+ {
+ export_directory_entry export_table;
+ uint32_t data_start = m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr;
+ Address address(m_coff_header_opt.image_base + data_start, sect_list);
+ DataBufferSP symtab_data_sp(m_file.ReadFileContents(address.GetSection()->GetFileOffset() + address.GetOffset(), m_coff_header_opt.data_dirs[0].vmsize));
+ DataExtractor symtab_data (symtab_data_sp, GetByteOrder(), GetAddressByteSize());
+ lldb::offset_t offset = 0;
+
+ // Read export_table header
+ export_table.characteristics = symtab_data.GetU32(&offset);
+ export_table.time_date_stamp = symtab_data.GetU32(&offset);
+ export_table.major_version = symtab_data.GetU16(&offset);
+ export_table.minor_version = symtab_data.GetU16(&offset);
+ export_table.name = symtab_data.GetU32(&offset);
+ export_table.base = symtab_data.GetU32(&offset);
+ export_table.number_of_functions = symtab_data.GetU32(&offset);
+ export_table.number_of_names = symtab_data.GetU32(&offset);
+ export_table.address_of_functions = symtab_data.GetU32(&offset);
+ export_table.address_of_names = symtab_data.GetU32(&offset);
+ export_table.address_of_name_ordinals = symtab_data.GetU32(&offset);
+
+ bool has_ordinal = export_table.address_of_name_ordinals != 0;
+
+ lldb::offset_t name_offset = export_table.address_of_names - data_start;
+ lldb::offset_t name_ordinal_offset = export_table.address_of_name_ordinals - data_start;
+
+ Symbol *symbols = m_symtab_ap->Resize(export_table.number_of_names);
+
+ std::string symbol_name;
+
+ // Read each export table entry
+ for (size_t i = 0; i < export_table.number_of_names; ++i)
+ {
+ uint32_t name_ordinal = has_ordinal ? symtab_data.GetU16(&name_ordinal_offset) : i;
+ uint32_t name_address = symtab_data.GetU32(&name_offset);
+
+ const char* symbol_name_cstr = symtab_data.PeekCStr(name_address - data_start);
+ symbol_name.assign(symbol_name_cstr);
+
+ lldb::offset_t function_offset = export_table.address_of_functions - data_start + sizeof(uint32_t) * name_ordinal;
+ uint32_t function_rva = symtab_data.GetU32(&function_offset);
+
+ Address symbol_addr(m_coff_header_opt.image_base + function_rva, sect_list);
+ symbols[i].GetMangled().SetValue(ConstString(symbol_name.c_str()));
+ symbols[i].GetAddressRef() = symbol_addr;
+ symbols[i].SetType(lldb::eSymbolTypeCode);
+ symbols[i].SetDebug(true);
+ }
+ }
+ }
+ }
+ return m_symtab_ap.get();
+
+}
+
+bool
+ObjectFilePECOFF::IsStripped ()
+{
+ // TODO: determine this for COFF
+ return false;
+}
+
+
+
+void
+ObjectFilePECOFF::CreateSections (SectionList &unified_section_list)
+{
+ if (!m_sections_ap.get())
+ {
+ m_sections_ap.reset(new SectionList());
+
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ const uint32_t nsects = m_sect_headers.size();
+ ModuleSP module_sp (GetModule());
+ for (uint32_t idx = 0; idx<nsects; ++idx)
+ {
+ std::string sect_name;
+ GetSectionName (sect_name, m_sect_headers[idx]);
+ ConstString const_sect_name (sect_name.c_str());
+ static ConstString g_code_sect_name (".code");
+ static ConstString g_CODE_sect_name ("CODE");
+ static ConstString g_data_sect_name (".data");
+ static ConstString g_DATA_sect_name ("DATA");
+ static ConstString g_bss_sect_name (".bss");
+ static ConstString g_BSS_sect_name ("BSS");
+ static ConstString g_debug_sect_name (".debug");
+ static ConstString g_reloc_sect_name (".reloc");
+ static ConstString g_stab_sect_name (".stab");
+ static ConstString g_stabstr_sect_name (".stabstr");
+ static ConstString g_sect_name_dwarf_debug_abbrev (".debug_abbrev");
+ static ConstString g_sect_name_dwarf_debug_aranges (".debug_aranges");
+ static ConstString g_sect_name_dwarf_debug_frame (".debug_frame");
+ static ConstString g_sect_name_dwarf_debug_info (".debug_info");
+ static ConstString g_sect_name_dwarf_debug_line (".debug_line");
+ static ConstString g_sect_name_dwarf_debug_loc (".debug_loc");
+ static ConstString g_sect_name_dwarf_debug_macinfo (".debug_macinfo");
+ static ConstString g_sect_name_dwarf_debug_pubnames (".debug_pubnames");
+ static ConstString g_sect_name_dwarf_debug_pubtypes (".debug_pubtypes");
+ static ConstString g_sect_name_dwarf_debug_ranges (".debug_ranges");
+ static ConstString g_sect_name_dwarf_debug_str (".debug_str");
+ static ConstString g_sect_name_eh_frame (".eh_frame");
+ static ConstString g_sect_name_go_symtab (".gosymtab");
+ SectionType section_type = eSectionTypeOther;
+ if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE &&
+ ((const_sect_name == g_code_sect_name) || (const_sect_name == g_CODE_sect_name)))
+ {
+ section_type = eSectionTypeCode;
+ }
+ else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA &&
+ ((const_sect_name == g_data_sect_name) || (const_sect_name == g_DATA_sect_name)))
+ {
+ section_type = eSectionTypeData;
+ }
+ else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA &&
+ ((const_sect_name == g_bss_sect_name) || (const_sect_name == g_BSS_sect_name)))
+ {
+ if (m_sect_headers[idx].size == 0)
+ section_type = eSectionTypeZeroFill;
+ else
+ section_type = eSectionTypeData;
+ }
+ else if (const_sect_name == g_debug_sect_name)
+ {
+ section_type = eSectionTypeDebug;
+ }
+ else if (const_sect_name == g_stabstr_sect_name)
+ {
+ section_type = eSectionTypeDataCString;
+ }
+ else if (const_sect_name == g_reloc_sect_name)
+ {
+ section_type = eSectionTypeOther;
+ }
+ else if (const_sect_name == g_sect_name_dwarf_debug_abbrev) section_type = eSectionTypeDWARFDebugAbbrev;
+ else if (const_sect_name == g_sect_name_dwarf_debug_aranges) section_type = eSectionTypeDWARFDebugAranges;
+ else if (const_sect_name == g_sect_name_dwarf_debug_frame) section_type = eSectionTypeDWARFDebugFrame;
+ else if (const_sect_name == g_sect_name_dwarf_debug_info) section_type = eSectionTypeDWARFDebugInfo;
+ else if (const_sect_name == g_sect_name_dwarf_debug_line) section_type = eSectionTypeDWARFDebugLine;
+ else if (const_sect_name == g_sect_name_dwarf_debug_loc) section_type = eSectionTypeDWARFDebugLoc;
+ else if (const_sect_name == g_sect_name_dwarf_debug_macinfo) section_type = eSectionTypeDWARFDebugMacInfo;
+ else if (const_sect_name == g_sect_name_dwarf_debug_pubnames) section_type = eSectionTypeDWARFDebugPubNames;
+ else if (const_sect_name == g_sect_name_dwarf_debug_pubtypes) section_type = eSectionTypeDWARFDebugPubTypes;
+ else if (const_sect_name == g_sect_name_dwarf_debug_ranges) section_type = eSectionTypeDWARFDebugRanges;
+ else if (const_sect_name == g_sect_name_dwarf_debug_str) section_type = eSectionTypeDWARFDebugStr;
+ else if (const_sect_name == g_sect_name_eh_frame) section_type = eSectionTypeEHFrame;
+ else if (const_sect_name == g_sect_name_go_symtab) section_type = eSectionTypeGoSymtab;
+ else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE)
+ {
+ section_type = eSectionTypeCode;
+ }
+ else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
+ {
+ section_type = eSectionTypeData;
+ }
+ else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ {
+ if (m_sect_headers[idx].size == 0)
+ section_type = eSectionTypeZeroFill;
+ else
+ section_type = eSectionTypeData;
+ }
+
+ // Use a segment ID of the segment index shifted left by 8 so they
+ // never conflict with any of the sections.
+ SectionSP section_sp (new Section (module_sp, // Module to which this section belongs
+ this, // Object file to which this section belongs
+ idx + 1, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
+ const_sect_name, // Name of this section
+ section_type, // This section is a container of other sections.
+ m_coff_header_opt.image_base + m_sect_headers[idx].vmaddr, // File VM address == addresses as they are found in the object file
+ m_sect_headers[idx].vmsize, // VM size in bytes of this section
+ m_sect_headers[idx].offset, // Offset to the data for this section in the file
+ m_sect_headers[idx].size, // Size in bytes of this section as found in the file
+ m_coff_header_opt.sect_alignment, // Section alignment
+ m_sect_headers[idx].flags)); // Flags for this section
+
+ //section_sp->SetIsEncrypted (segment_is_encrypted);
+
+ unified_section_list.AddSection(section_sp);
+ m_sections_ap->AddSection (section_sp);
+ }
+ }
+ }
+}
+
+bool
+ObjectFilePECOFF::GetUUID (UUID* uuid)
+{
+ return false;
+}
+
+uint32_t
+ObjectFilePECOFF::GetDependentModules (FileSpecList& files)
+{
+ return 0;
+}
+
+
+//----------------------------------------------------------------------
+// Dump
+//
+// Dump the specifics of the runtime file container (such as any headers
+// segments, sections, etc).
+//----------------------------------------------------------------------
+void
+ObjectFilePECOFF::Dump(Stream *s)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ s->Printf("%p: ", static_cast<void*>(this));
+ s->Indent();
+ s->PutCString("ObjectFilePECOFF");
+
+ ArchSpec header_arch;
+ GetArchitecture (header_arch);
+
+ *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n";
+
+ SectionList *sections = GetSectionList();
+ if (sections)
+ sections->Dump(s, NULL, true, UINT32_MAX);
+
+ if (m_symtab_ap.get())
+ m_symtab_ap->Dump(s, NULL, eSortOrderNone);
+
+ if (m_dos_header.e_magic)
+ DumpDOSHeader (s, m_dos_header);
+ if (m_coff_header.machine)
+ {
+ DumpCOFFHeader (s, m_coff_header);
+ if (m_coff_header.hdrsize)
+ DumpOptCOFFHeader (s, m_coff_header_opt);
+ }
+ s->EOL();
+ DumpSectionHeaders(s);
+ s->EOL();
+ }
+}
+
+//----------------------------------------------------------------------
+// DumpDOSHeader
+//
+// Dump the MS-DOS header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFilePECOFF::DumpDOSHeader(Stream *s, const dos_header_t& header)
+{
+ s->PutCString ("MSDOS Header\n");
+ s->Printf (" e_magic = 0x%4.4x\n", header.e_magic);
+ s->Printf (" e_cblp = 0x%4.4x\n", header.e_cblp);
+ s->Printf (" e_cp = 0x%4.4x\n", header.e_cp);
+ s->Printf (" e_crlc = 0x%4.4x\n", header.e_crlc);
+ s->Printf (" e_cparhdr = 0x%4.4x\n", header.e_cparhdr);
+ s->Printf (" e_minalloc = 0x%4.4x\n", header.e_minalloc);
+ s->Printf (" e_maxalloc = 0x%4.4x\n", header.e_maxalloc);
+ s->Printf (" e_ss = 0x%4.4x\n", header.e_ss);
+ s->Printf (" e_sp = 0x%4.4x\n", header.e_sp);
+ s->Printf (" e_csum = 0x%4.4x\n", header.e_csum);
+ s->Printf (" e_ip = 0x%4.4x\n", header.e_ip);
+ s->Printf (" e_cs = 0x%4.4x\n", header.e_cs);
+ s->Printf (" e_lfarlc = 0x%4.4x\n", header.e_lfarlc);
+ s->Printf (" e_ovno = 0x%4.4x\n", header.e_ovno);
+ s->Printf (" e_res[4] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n",
+ header.e_res[0],
+ header.e_res[1],
+ header.e_res[2],
+ header.e_res[3]);
+ s->Printf (" e_oemid = 0x%4.4x\n", header.e_oemid);
+ s->Printf (" e_oeminfo = 0x%4.4x\n", header.e_oeminfo);
+ s->Printf (" e_res2[10] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n",
+ header.e_res2[0],
+ header.e_res2[1],
+ header.e_res2[2],
+ header.e_res2[3],
+ header.e_res2[4],
+ header.e_res2[5],
+ header.e_res2[6],
+ header.e_res2[7],
+ header.e_res2[8],
+ header.e_res2[9]);
+ s->Printf (" e_lfanew = 0x%8.8x\n", header.e_lfanew);
+}
+
+//----------------------------------------------------------------------
+// DumpCOFFHeader
+//
+// Dump the COFF header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFilePECOFF::DumpCOFFHeader(Stream *s, const coff_header_t& header)
+{
+ s->PutCString ("COFF Header\n");
+ s->Printf (" machine = 0x%4.4x\n", header.machine);
+ s->Printf (" nsects = 0x%4.4x\n", header.nsects);
+ s->Printf (" modtime = 0x%8.8x\n", header.modtime);
+ s->Printf (" symoff = 0x%8.8x\n", header.symoff);
+ s->Printf (" nsyms = 0x%8.8x\n", header.nsyms);
+ s->Printf (" hdrsize = 0x%4.4x\n", header.hdrsize);
+}
+
+//----------------------------------------------------------------------
+// DumpOptCOFFHeader
+//
+// Dump the optional COFF header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFilePECOFF::DumpOptCOFFHeader(Stream *s, const coff_opt_header_t& header)
+{
+ s->PutCString ("Optional COFF Header\n");
+ s->Printf (" magic = 0x%4.4x\n", header.magic);
+ s->Printf (" major_linker_version = 0x%2.2x\n", header.major_linker_version);
+ s->Printf (" minor_linker_version = 0x%2.2x\n", header.minor_linker_version);
+ s->Printf (" code_size = 0x%8.8x\n", header.code_size);
+ s->Printf (" data_size = 0x%8.8x\n", header.data_size);
+ s->Printf (" bss_size = 0x%8.8x\n", header.bss_size);
+ s->Printf (" entry = 0x%8.8x\n", header.entry);
+ s->Printf (" code_offset = 0x%8.8x\n", header.code_offset);
+ s->Printf (" data_offset = 0x%8.8x\n", header.data_offset);
+ s->Printf (" image_base = 0x%16.16" PRIx64 "\n", header.image_base);
+ s->Printf (" sect_alignment = 0x%8.8x\n", header.sect_alignment);
+ s->Printf (" file_alignment = 0x%8.8x\n", header.file_alignment);
+ s->Printf (" major_os_system_version = 0x%4.4x\n", header.major_os_system_version);
+ s->Printf (" minor_os_system_version = 0x%4.4x\n", header.minor_os_system_version);
+ s->Printf (" major_image_version = 0x%4.4x\n", header.major_image_version);
+ s->Printf (" minor_image_version = 0x%4.4x\n", header.minor_image_version);
+ s->Printf (" major_subsystem_version = 0x%4.4x\n", header.major_subsystem_version);
+ s->Printf (" minor_subsystem_version = 0x%4.4x\n", header.minor_subsystem_version);
+ s->Printf (" reserved1 = 0x%8.8x\n", header.reserved1);
+ s->Printf (" image_size = 0x%8.8x\n", header.image_size);
+ s->Printf (" header_size = 0x%8.8x\n", header.header_size);
+ s->Printf (" checksum = 0x%8.8x\n", header.checksum);
+ s->Printf (" subsystem = 0x%4.4x\n", header.subsystem);
+ s->Printf (" dll_flags = 0x%4.4x\n", header.dll_flags);
+ s->Printf (" stack_reserve_size = 0x%16.16" PRIx64 "\n", header.stack_reserve_size);
+ s->Printf (" stack_commit_size = 0x%16.16" PRIx64 "\n", header.stack_commit_size);
+ s->Printf (" heap_reserve_size = 0x%16.16" PRIx64 "\n", header.heap_reserve_size);
+ s->Printf (" heap_commit_size = 0x%16.16" PRIx64 "\n", header.heap_commit_size);
+ s->Printf (" loader_flags = 0x%8.8x\n", header.loader_flags);
+ s->Printf (" num_data_dir_entries = 0x%8.8x\n", (uint32_t)header.data_dirs.size());
+ uint32_t i;
+ for (i=0; i<header.data_dirs.size(); i++)
+ {
+ s->Printf (" data_dirs[%2u] vmaddr = 0x%8.8x, vmsize = 0x%8.8x\n",
+ i,
+ header.data_dirs[i].vmaddr,
+ header.data_dirs[i].vmsize);
+ }
+}
+//----------------------------------------------------------------------
+// DumpSectionHeader
+//
+// Dump a single ELF section header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFilePECOFF::DumpSectionHeader(Stream *s, const section_header_t& sh)
+{
+ std::string name;
+ GetSectionName(name, sh);
+ s->Printf ("%-16s 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%4.4x 0x%4.4x 0x%8.8x\n",
+ name.c_str(),
+ sh.vmaddr,
+ sh.vmsize,
+ sh.offset,
+ sh.size,
+ sh.reloff,
+ sh.lineoff,
+ sh.nreloc,
+ sh.nline,
+ sh.flags);
+}
+
+
+//----------------------------------------------------------------------
+// DumpSectionHeaders
+//
+// Dump all of the ELF section header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFilePECOFF::DumpSectionHeaders(Stream *s)
+{
+
+ s->PutCString ("Section Headers\n");
+ s->PutCString ("IDX name vm addr vm size file off file size reloc off line off nreloc nline flags\n");
+ s->PutCString ("==== ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ------ ------ ----------\n");
+
+ uint32_t idx = 0;
+ SectionHeaderCollIter pos, end = m_sect_headers.end();
+
+ for (pos = m_sect_headers.begin(); pos != end; ++pos, ++idx)
+ {
+ s->Printf ("[%2u] ", idx);
+ ObjectFilePECOFF::DumpSectionHeader(s, *pos);
+ }
+}
+
+bool
+ObjectFilePECOFF::GetArchitecture (ArchSpec &arch)
+{
+ uint16_t machine = m_coff_header.machine;
+ switch (machine)
+ {
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ case llvm::COFF::IMAGE_FILE_MACHINE_POWERPC:
+ case llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP:
+ case llvm::COFF::IMAGE_FILE_MACHINE_ARM:
+ case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
+ case llvm::COFF::IMAGE_FILE_MACHINE_THUMB:
+ arch.SetArchitecture (eArchTypeCOFF, machine, LLDB_INVALID_CPUTYPE);
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+ObjectFile::Type
+ObjectFilePECOFF::CalculateType()
+{
+ if (m_coff_header.machine != 0)
+ {
+ if ((m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0)
+ return eTypeExecutable;
+ else
+ return eTypeSharedLibrary;
+ }
+ return eTypeExecutable;
+}
+
+ObjectFile::Strata
+ObjectFilePECOFF::CalculateStrata()
+{
+ return eStrataUser;
+}
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+ObjectFilePECOFF::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectFilePECOFF::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
new file mode 100644
index 000000000000..fd33cd3d32f8
--- /dev/null
+++ b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
@@ -0,0 +1,303 @@
+//===-- ObjectFilePECOFF.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_ObjectFilePECOFF_h_
+#define liblldb_ObjectFilePECOFF_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Symbol/ObjectFile.h"
+
+class ObjectFilePECOFF :
+ public lldb_private::ObjectFile
+{
+public:
+ typedef enum MachineType
+ {
+ MachineUnknown = 0x0,
+ MachineAm33 = 0x1d3,
+ MachineAmd64 = 0x8664,
+ MachineArm = 0x1c0,
+ MachineArmNt = 0x1c4,
+ MachineArm64 = 0xaa64,
+ MachineEbc = 0xebc,
+ MachineX86 = 0x14c,
+ MachineIA64 = 0x200,
+ MachineM32R = 0x9041,
+ MachineMips16 = 0x266,
+ MachineMipsFpu = 0x366,
+ MachineMipsFpu16 = 0x466,
+ MachinePowerPc = 0x1f0,
+ MachinePowerPcfp = 0x1f1,
+ MachineR4000 = 0x166,
+ MachineSh3 = 0x1a2,
+ MachineSh3dsp = 0x1a3,
+ MachineSh4 = 0x1a6,
+ MachineSh5 = 0x1a8,
+ MachineThumb = 0x1c2,
+ MachineWcemIpsv2 = 0x169
+ } MachineType;
+
+ ObjectFilePECOFF(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length);
+
+ ~ObjectFilePECOFF() override;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static ObjectFile *
+ CreateInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t offset,
+ lldb::offset_t length);
+
+ static lldb_private::ObjectFile *
+ CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr);
+
+ static size_t
+ GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs);
+
+ static bool
+ SaveCore (const lldb::ProcessSP &process_sp,
+ const lldb_private::FileSpec &outfile,
+ lldb_private::Error &error);
+
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& data_sp);
+
+ bool
+ ParseHeader() override;
+
+ bool
+ SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, bool value_is_offset) override;
+
+ lldb::ByteOrder
+ GetByteOrder() const override;
+
+ bool
+ IsExecutable() const override;
+
+ uint32_t
+ GetAddressByteSize() const override;
+
+// virtual lldb_private::AddressClass
+// GetAddressClass (lldb::addr_t file_addr);
+
+ lldb_private::Symtab *
+ GetSymtab() override;
+
+ bool
+ IsStripped() override;
+
+ void
+ CreateSections(lldb_private::SectionList &unified_section_list) override;
+
+ void
+ Dump(lldb_private::Stream *s) override;
+
+ bool
+ GetArchitecture(lldb_private::ArchSpec &arch) override;
+
+ bool
+ GetUUID(lldb_private::UUID* uuid) override;
+
+ uint32_t
+ GetDependentModules(lldb_private::FileSpecList& files) override;
+
+// virtual lldb_private::Address
+// GetEntryPointAddress ();
+
+ ObjectFile::Type
+ CalculateType() override;
+
+ ObjectFile::Strata
+ CalculateStrata() override;
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+protected:
+ bool NeedsEndianSwap() const;
+
+ typedef struct dos_header { // DOS .EXE header
+ uint16_t e_magic; // Magic number
+ uint16_t e_cblp; // Bytes on last page of file
+ uint16_t e_cp; // Pages in file
+ uint16_t e_crlc; // Relocations
+ uint16_t e_cparhdr; // Size of header in paragraphs
+ uint16_t e_minalloc; // Minimum extra paragraphs needed
+ uint16_t e_maxalloc; // Maximum extra paragraphs needed
+ uint16_t e_ss; // Initial (relative) SS value
+ uint16_t e_sp; // Initial SP value
+ uint16_t e_csum; // Checksum
+ uint16_t e_ip; // Initial IP value
+ uint16_t e_cs; // Initial (relative) CS value
+ uint16_t e_lfarlc; // File address of relocation table
+ uint16_t e_ovno; // Overlay number
+ uint16_t e_res[4]; // Reserved words
+ uint16_t e_oemid; // OEM identifier (for e_oeminfo)
+ uint16_t e_oeminfo; // OEM information; e_oemid specific
+ uint16_t e_res2[10]; // Reserved words
+ uint32_t e_lfanew; // File address of new exe header
+ } dos_header_t;
+
+ typedef struct coff_header {
+ uint16_t machine;
+ uint16_t nsects;
+ uint32_t modtime;
+ uint32_t symoff;
+ uint32_t nsyms;
+ uint16_t hdrsize;
+ uint16_t flags;
+ } coff_header_t;
+
+ typedef struct data_directory {
+ uint32_t vmaddr;
+ uint32_t vmsize;
+ } data_directory_t;
+
+ typedef struct coff_opt_header
+ {
+ uint16_t magic;
+ uint8_t major_linker_version;
+ uint8_t minor_linker_version;
+ uint32_t code_size;
+ uint32_t data_size;
+ uint32_t bss_size;
+ uint32_t entry;
+ uint32_t code_offset;
+ uint32_t data_offset;
+
+ uint64_t image_base;
+ uint32_t sect_alignment;
+ uint32_t file_alignment;
+ uint16_t major_os_system_version;
+ uint16_t minor_os_system_version;
+ uint16_t major_image_version;
+ uint16_t minor_image_version;
+ uint16_t major_subsystem_version;
+ uint16_t minor_subsystem_version;
+ uint32_t reserved1;
+ uint32_t image_size;
+ uint32_t header_size;
+ uint32_t checksum;
+ uint16_t subsystem;
+ uint16_t dll_flags;
+ uint64_t stack_reserve_size;
+ uint64_t stack_commit_size;
+ uint64_t heap_reserve_size;
+ uint64_t heap_commit_size;
+ uint32_t loader_flags;
+ // uint32_t num_data_dir_entries;
+ std::vector<data_directory> data_dirs; // will contain num_data_dir_entries entries
+ } coff_opt_header_t;
+
+ typedef enum coff_data_dir_type
+ {
+ coff_data_dir_export_table = 0,
+ coff_data_dir_import_table = 1,
+ } coff_data_dir_type;
+
+ typedef struct section_header {
+ char name[8];
+ uint32_t vmsize; // Virtual Size
+ uint32_t vmaddr; // Virtual Addr
+ uint32_t size; // File size
+ uint32_t offset; // File offset
+ uint32_t reloff; // Offset to relocations
+ uint32_t lineoff;// Offset to line table entries
+ uint16_t nreloc; // Number of relocation entries
+ uint16_t nline; // Number of line table entries
+ uint32_t flags;
+ } section_header_t;
+
+ typedef struct coff_symbol {
+ char name[8];
+ uint32_t value;
+ uint16_t sect;
+ uint16_t type;
+ uint8_t storage;
+ uint8_t naux;
+ } coff_symbol_t;
+
+ typedef struct export_directory_entry {
+ uint32_t characteristics;
+ uint32_t time_date_stamp;
+ uint16_t major_version;
+ uint16_t minor_version;
+ uint32_t name;
+ uint32_t base;
+ uint32_t number_of_functions;
+ uint32_t number_of_names;
+ uint32_t address_of_functions;
+ uint32_t address_of_names;
+ uint32_t address_of_name_ordinals;
+ } export_directory_entry;
+
+ static bool ParseDOSHeader (lldb_private::DataExtractor &data, dos_header_t &dos_header);
+ static bool ParseCOFFHeader (lldb_private::DataExtractor &data, lldb::offset_t *offset_ptr, coff_header_t &coff_header);
+ bool ParseCOFFOptionalHeader (lldb::offset_t *offset_ptr);
+ bool ParseSectionHeaders (uint32_t offset);
+
+ static void DumpDOSHeader(lldb_private::Stream *s, const dos_header_t& header);
+ static void DumpCOFFHeader(lldb_private::Stream *s, const coff_header_t& header);
+ static void DumpOptCOFFHeader(lldb_private::Stream *s, const coff_opt_header_t& header);
+ void DumpSectionHeaders(lldb_private::Stream *s);
+ void DumpSectionHeader(lldb_private::Stream *s, const section_header_t& sh);
+ bool GetSectionName(std::string& sect_name, const section_header_t& sect);
+
+ typedef std::vector<section_header_t> SectionHeaderColl;
+ typedef SectionHeaderColl::iterator SectionHeaderCollIter;
+ typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter;
+private:
+ dos_header_t m_dos_header;
+ coff_header_t m_coff_header;
+ coff_opt_header_t m_coff_header_opt;
+ SectionHeaderColl m_sect_headers;
+ lldb::addr_t m_image_base;
+};
+
+#endif // liblldb_ObjectFilePECOFF_h_
diff --git a/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp b/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp
new file mode 100644
index 000000000000..14c73eff2388
--- /dev/null
+++ b/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp
@@ -0,0 +1,56 @@
+//===-- WindowsMiniDump.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This function is separated out from ObjectFilePECOFF.cpp to name avoid name
+// collisions with WinAPI preprocessor macros.
+
+#include "WindowsMiniDump.h"
+#include "lldb/Host/FileSpec.h"
+#include "llvm/Support/ConvertUTF.h"
+
+#ifdef _WIN32
+#include "lldb/Host/windows/windows.h"
+#include <DbgHelp.h> // for MiniDumpWriteDump
+#endif
+
+namespace lldb_private {
+
+bool
+SaveMiniDump(const lldb::ProcessSP &process_sp,
+ const lldb_private::FileSpec &outfile,
+ lldb_private::Error &error)
+{
+ if (!process_sp) return false;
+#ifdef _WIN32
+ HANDLE process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_sp->GetID());
+ const std::string file_name = outfile.GetCString();
+ std::wstring wide_name;
+ wide_name.resize(file_name.size() + 1);
+ char * result_ptr = reinterpret_cast<char *>(&wide_name[0]);
+ const UTF8 *error_ptr = nullptr;
+ if (!llvm::ConvertUTF8toWide(sizeof(wchar_t), file_name, result_ptr, error_ptr)) {
+ error.SetErrorString("cannot convert file name");
+ return false;
+ }
+ HANDLE file_handle = ::CreateFileW(wide_name.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ const auto result = ::MiniDumpWriteDump(process_handle, process_sp->GetID(), file_handle,
+ MiniDumpWithFullMemoryInfo, NULL, NULL, NULL);
+ ::CloseHandle(file_handle);
+ ::CloseHandle(process_handle);
+ if (!result)
+ {
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ return false;
+ }
+ return true;
+#endif
+ return false;
+}
+
+} // namesapce lldb_private
diff --git a/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h b/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h
new file mode 100644
index 000000000000..cbea88af1fb0
--- /dev/null
+++ b/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h
@@ -0,0 +1,24 @@
+//===-- WindowsMiniDump.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_WindowsMiniDump_h_
+#define liblldb_WindowsMiniDump_h_
+
+#include "lldb/Target/Process.h"
+
+namespace lldb_private {
+
+bool
+SaveMiniDump(const lldb::ProcessSP &process_sp,
+ const lldb_private::FileSpec &outfile,
+ lldb_private::Error &error);
+
+} // namespace lldb_private
+
+#endif
diff --git a/source/Plugins/OperatingSystem/CMakeLists.txt b/source/Plugins/OperatingSystem/CMakeLists.txt
new file mode 100644
index 000000000000..1f017adcd02b
--- /dev/null
+++ b/source/Plugins/OperatingSystem/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(Go)
+add_subdirectory(Python)
diff --git a/source/Plugins/OperatingSystem/Go/CMakeLists.txt b/source/Plugins/OperatingSystem/Go/CMakeLists.txt
new file mode 100644
index 000000000000..1ca82c462069
--- /dev/null
+++ b/source/Plugins/OperatingSystem/Go/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginOSGo
+ OperatingSystemGo.cpp
+ )
diff --git a/source/Plugins/OperatingSystem/Go/Makefile b/source/Plugins/OperatingSystem/Go/Makefile
new file mode 100644
index 000000000000..7d06d483d3ae
--- /dev/null
+++ b/source/Plugins/OperatingSystem/Go/Makefile
@@ -0,0 +1,14 @@
+##==- source/Plugins/OperatingSystem/Go/Makefile --------*- Makefile -*-==##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginOSGo
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/OperatingSystem/Python/CMakeLists.txt b/source/Plugins/OperatingSystem/Python/CMakeLists.txt
new file mode 100644
index 000000000000..7188e6f67ba0
--- /dev/null
+++ b/source/Plugins/OperatingSystem/Python/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginOSPython
+ OperatingSystemPython.cpp
+ )
diff --git a/source/Plugins/OperatingSystem/Python/Makefile b/source/Plugins/OperatingSystem/Python/Makefile
new file mode 100644
index 000000000000..67cd0acd7038
--- /dev/null
+++ b/source/Plugins/OperatingSystem/Python/Makefile
@@ -0,0 +1,14 @@
+##==- source/Plugins/OperatingSystem/Python/Makefile --------*- Makefile -*-==##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginOSPython
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Platform/Android/AdbClient.cpp b/source/Plugins/Platform/Android/AdbClient.cpp
new file mode 100644
index 000000000000..736447fd22d2
--- /dev/null
+++ b/source/Plugins/Platform/Android/AdbClient.cpp
@@ -0,0 +1,569 @@
+//===-- AdbClient.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Other libraries and framework includes
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataEncoder.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/FileUtilities.h"
+
+// Project includes
+#include "AdbClient.h"
+
+#include <limits.h>
+
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::platform_android;
+
+namespace {
+
+const uint32_t kReadTimeout = 1000000; // 1 second
+const char * kOKAY = "OKAY";
+const char * kFAIL = "FAIL";
+const char * kDATA = "DATA";
+const char * kDONE = "DONE";
+
+const char * kSEND = "SEND";
+const char * kRECV = "RECV";
+const char * kSTAT = "STAT";
+
+const size_t kSyncPacketLen = 8;
+// Maximum size of a filesync DATA packet.
+const size_t kMaxPushData = 2*1024;
+// Default mode for pushed files.
+const uint32_t kDefaultMode = 0100770; // S_IFREG | S_IRWXU | S_IRWXG
+
+const char * kSocketNamespaceAbstract = "localabstract";
+const char * kSocketNamespaceFileSystem = "localfilesystem";
+
+} // namespace
+
+Error
+AdbClient::CreateByDeviceID(const std::string &device_id, AdbClient &adb)
+{
+ DeviceIDList connect_devices;
+ auto error = adb.GetDevices(connect_devices);
+ if (error.Fail())
+ return error;
+
+ if (device_id.empty())
+ {
+ if (connect_devices.size() != 1)
+ return Error("Expected a single connected device, got instead %" PRIu64,
+ static_cast<uint64_t>(connect_devices.size()));
+
+ adb.SetDeviceID(connect_devices.front());
+ }
+ else
+ {
+ auto find_it = std::find(connect_devices.begin(), connect_devices.end(), device_id);
+ if (find_it == connect_devices.end())
+ return Error("Device \"%s\" not found", device_id.c_str());
+
+ adb.SetDeviceID(*find_it);
+ }
+ return error;
+}
+
+AdbClient::AdbClient (const std::string &device_id)
+ : m_device_id (device_id)
+{
+}
+
+void
+AdbClient::SetDeviceID (const std::string &device_id)
+{
+ m_device_id = device_id;
+}
+
+const std::string&
+AdbClient::GetDeviceID() const
+{
+ return m_device_id;
+}
+
+Error
+AdbClient::Connect ()
+{
+ Error error;
+ m_conn.Connect ("connect://localhost:5037", &error);
+
+ return error;
+}
+
+Error
+AdbClient::GetDevices (DeviceIDList &device_list)
+{
+ device_list.clear ();
+
+ auto error = SendMessage ("host:devices");
+ if (error.Fail ())
+ return error;
+
+ error = ReadResponseStatus ();
+ if (error.Fail ())
+ return error;
+
+ std::vector<char> in_buffer;
+ error = ReadMessage (in_buffer);
+
+ llvm::StringRef response (&in_buffer[0], in_buffer.size ());
+ llvm::SmallVector<llvm::StringRef, 4> devices;
+ response.split (devices, "\n", -1, false);
+
+ for (const auto device: devices)
+ device_list.push_back (device.split ('\t').first);
+
+ return error;
+}
+
+Error
+AdbClient::SetPortForwarding (const uint16_t local_port, const uint16_t remote_port)
+{
+ char message[48];
+ snprintf (message, sizeof (message), "forward:tcp:%d;tcp:%d", local_port, remote_port);
+
+ const auto error = SendDeviceMessage (message);
+ if (error.Fail ())
+ return error;
+
+ return ReadResponseStatus ();
+}
+
+Error
+AdbClient::SetPortForwarding (const uint16_t local_port,
+ const char* remote_socket_name,
+ const UnixSocketNamespace socket_namespace)
+{
+ char message[PATH_MAX];
+ const char * sock_namespace_str = (socket_namespace == UnixSocketNamespaceAbstract) ?
+ kSocketNamespaceAbstract : kSocketNamespaceFileSystem;
+ snprintf (message, sizeof (message), "forward:tcp:%d;%s:%s",
+ local_port,
+ sock_namespace_str,
+ remote_socket_name);
+
+ const auto error = SendDeviceMessage (message);
+ if (error.Fail ())
+ return error;
+
+ return ReadResponseStatus ();
+}
+
+Error
+AdbClient::DeletePortForwarding (const uint16_t local_port)
+{
+ char message[32];
+ snprintf (message, sizeof (message), "killforward:tcp:%d", local_port);
+
+ const auto error = SendDeviceMessage (message);
+ if (error.Fail ())
+ return error;
+
+ return ReadResponseStatus ();
+}
+
+Error
+AdbClient::SendMessage (const std::string &packet, const bool reconnect)
+{
+ Error error;
+ if (reconnect)
+ {
+ error = Connect ();
+ if (error.Fail ())
+ return error;
+ }
+
+ char length_buffer[5];
+ snprintf (length_buffer, sizeof (length_buffer), "%04x", static_cast<int>(packet.size ()));
+
+ ConnectionStatus status;
+
+ m_conn.Write (length_buffer, 4, status, &error);
+ if (error.Fail ())
+ return error;
+
+ m_conn.Write (packet.c_str (), packet.size (), status, &error);
+ return error;
+}
+
+Error
+AdbClient::SendDeviceMessage (const std::string &packet)
+{
+ std::ostringstream msg;
+ msg << "host-serial:" << m_device_id << ":" << packet;
+ return SendMessage (msg.str ());
+}
+
+Error
+AdbClient::ReadMessage (std::vector<char> &message)
+{
+ message.clear ();
+
+ char buffer[5];
+ buffer[4] = 0;
+
+ auto error = ReadAllBytes (buffer, 4);
+ if (error.Fail ())
+ return error;
+
+ unsigned int packet_len = 0;
+ sscanf (buffer, "%x", &packet_len);
+
+ message.resize (packet_len, 0);
+ error = ReadAllBytes (&message[0], packet_len);
+ if (error.Fail ())
+ message.clear ();
+
+ return error;
+}
+
+Error
+AdbClient::ReadMessageStream (std::vector<char>& message, uint32_t timeout_ms)
+{
+ auto start = std::chrono::steady_clock::now();
+ message.clear();
+
+ Error error;
+ lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
+ char buffer[1024];
+ while (error.Success() && status == lldb::eConnectionStatusSuccess)
+ {
+ auto end = std::chrono::steady_clock::now();
+ uint32_t elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
+ if (elapsed_time >= timeout_ms)
+ return Error("Timed out");
+
+ size_t n = m_conn.Read(buffer, sizeof(buffer), 1000 * (timeout_ms - elapsed_time), status, &error);
+ if (n > 0)
+ message.insert(message.end(), &buffer[0], &buffer[n]);
+ }
+ return error;
+}
+
+Error
+AdbClient::ReadResponseStatus()
+{
+ char response_id[5];
+
+ static const size_t packet_len = 4;
+ response_id[packet_len] = 0;
+
+ auto error = ReadAllBytes (response_id, packet_len);
+ if (error.Fail ())
+ return error;
+
+ if (strncmp (response_id, kOKAY, packet_len) != 0)
+ return GetResponseError (response_id);
+
+ return error;
+}
+
+Error
+AdbClient::GetResponseError (const char *response_id)
+{
+ if (strcmp (response_id, kFAIL) != 0)
+ return Error ("Got unexpected response id from adb: \"%s\"", response_id);
+
+ std::vector<char> error_message;
+ auto error = ReadMessage (error_message);
+ if (error.Success ())
+ error.SetErrorString (std::string (&error_message[0], error_message.size ()).c_str ());
+
+ return error;
+}
+
+Error
+AdbClient::SwitchDeviceTransport ()
+{
+ std::ostringstream msg;
+ msg << "host:transport:" << m_device_id;
+
+ auto error = SendMessage (msg.str ());
+ if (error.Fail ())
+ return error;
+
+ return ReadResponseStatus ();
+}
+
+Error
+AdbClient::PullFile (const FileSpec &remote_file, const FileSpec &local_file)
+{
+ auto error = StartSync ();
+ if (error.Fail ())
+ return error;
+
+ const auto local_file_path = local_file.GetPath ();
+ llvm::FileRemover local_file_remover (local_file_path.c_str ());
+
+ std::ofstream dst (local_file_path, std::ios::out | std::ios::binary);
+ if (!dst.is_open ())
+ return Error ("Unable to open local file %s", local_file_path.c_str());
+
+ const auto remote_file_path = remote_file.GetPath (false);
+ error = SendSyncRequest (kRECV, remote_file_path.length (), remote_file_path.c_str ());
+ if (error.Fail ())
+ return error;
+
+ std::vector<char> chunk;
+ bool eof = false;
+ while (!eof)
+ {
+ error = PullFileChunk (chunk, eof);
+ if (error.Fail ())
+ return error;
+ if (!eof)
+ dst.write (&chunk[0], chunk.size ());
+ }
+
+ local_file_remover.releaseFile ();
+ return error;
+}
+
+Error
+AdbClient::PushFile (const FileSpec &local_file, const FileSpec &remote_file)
+{
+ auto error = StartSync ();
+ if (error.Fail ())
+ return error;
+
+ const auto local_file_path (local_file.GetPath ());
+ std::ifstream src (local_file_path.c_str(), std::ios::in | std::ios::binary);
+ if (!src.is_open ())
+ return Error ("Unable to open local file %s", local_file_path.c_str());
+
+ std::stringstream file_description;
+ file_description << remote_file.GetPath(false).c_str() << "," << kDefaultMode;
+ std::string file_description_str = file_description.str();
+ error = SendSyncRequest (kSEND, file_description_str.length(), file_description_str.c_str());
+ if (error.Fail ())
+ return error;
+
+ char chunk[kMaxPushData];
+ while (!src.eof() && !src.read(chunk, kMaxPushData).bad())
+ {
+ size_t chunk_size = src.gcount();
+ error = SendSyncRequest(kDATA, chunk_size, chunk);
+ if (error.Fail ())
+ return Error ("Failed to send file chunk: %s", error.AsCString ());
+ }
+ error = SendSyncRequest(kDONE, local_file.GetModificationTime().seconds(), nullptr);
+ if (error.Fail ())
+ return error;
+
+ std::string response_id;
+ uint32_t data_len;
+ error = ReadSyncHeader (response_id, data_len);
+ if (error.Fail ())
+ return Error ("Failed to read DONE response: %s", error.AsCString ());
+ if (response_id == kFAIL)
+ {
+ std::string error_message (data_len, 0);
+ error = ReadAllBytes (&error_message[0], data_len);
+ if (error.Fail ())
+ return Error ("Failed to read DONE error message: %s", error.AsCString ());
+ return Error ("Failed to push file: %s", error_message.c_str ());
+ }
+ else if (response_id != kOKAY)
+ return Error ("Got unexpected DONE response: %s", response_id.c_str ());
+
+ // If there was an error reading the source file, finish the adb file
+ // transfer first so that adb isn't expecting any more data.
+ if (src.bad())
+ return Error ("Failed read on %s", local_file_path.c_str());
+ return error;
+}
+
+Error
+AdbClient::StartSync ()
+{
+ auto error = SwitchDeviceTransport ();
+ if (error.Fail ())
+ return Error ("Failed to switch to device transport: %s", error.AsCString ());
+
+ error = Sync ();
+ if (error.Fail ())
+ return Error ("Sync failed: %s", error.AsCString ());
+
+ return error;
+}
+
+Error
+AdbClient::Sync ()
+{
+ auto error = SendMessage ("sync:", false);
+ if (error.Fail ())
+ return error;
+
+ return ReadResponseStatus ();
+}
+
+Error
+AdbClient::PullFileChunk (std::vector<char> &buffer, bool &eof)
+{
+ buffer.clear ();
+
+ std::string response_id;
+ uint32_t data_len;
+ auto error = ReadSyncHeader (response_id, data_len);
+ if (error.Fail ())
+ return error;
+
+ if (response_id == kDATA)
+ {
+ buffer.resize (data_len, 0);
+ error = ReadAllBytes (&buffer[0], data_len);
+ if (error.Fail ())
+ buffer.clear ();
+ }
+ else if (response_id == kDONE)
+ {
+ eof = true;
+ }
+ else if (response_id == kFAIL)
+ {
+ std::string error_message (data_len, 0);
+ error = ReadAllBytes (&error_message[0], data_len);
+ if (error.Fail ())
+ return Error ("Failed to read pull error message: %s", error.AsCString ());
+ return Error ("Failed to pull file: %s", error_message.c_str ());
+ }
+ else
+ return Error ("Pull failed with unknown response: %s", response_id.c_str ());
+
+ return Error ();
+}
+
+Error
+AdbClient::SendSyncRequest (const char *request_id, const uint32_t data_len, const void *data)
+{
+ const DataBufferSP data_sp (new DataBufferHeap (kSyncPacketLen, 0));
+ DataEncoder encoder (data_sp, eByteOrderLittle, sizeof (void*));
+ auto offset = encoder.PutData (0, request_id, strlen(request_id));
+ encoder.PutU32 (offset, data_len);
+
+ Error error;
+ ConnectionStatus status;
+ m_conn.Write (data_sp->GetBytes (), kSyncPacketLen, status, &error);
+ if (error.Fail ())
+ return error;
+
+ if (data)
+ m_conn.Write (data, data_len, status, &error);
+ return error;
+}
+
+Error
+AdbClient::ReadSyncHeader (std::string &response_id, uint32_t &data_len)
+{
+ char buffer[kSyncPacketLen];
+
+ auto error = ReadAllBytes (buffer, kSyncPacketLen);
+ if (error.Success ())
+ {
+ response_id.assign (&buffer[0], 4);
+ DataExtractor extractor (&buffer[4], 4, eByteOrderLittle, sizeof (void*));
+ offset_t offset = 0;
+ data_len = extractor.GetU32 (&offset);
+ }
+
+ return error;
+}
+
+Error
+AdbClient::ReadAllBytes (void *buffer, size_t size)
+{
+ Error error;
+ ConnectionStatus status;
+ char *read_buffer = static_cast<char*>(buffer);
+
+ size_t tota_read_bytes = 0;
+ while (tota_read_bytes < size)
+ {
+ auto read_bytes = m_conn.Read (read_buffer + tota_read_bytes, size - tota_read_bytes, kReadTimeout, status, &error);
+ if (error.Fail ())
+ return error;
+ tota_read_bytes += read_bytes;
+ }
+ return error;
+}
+
+Error
+AdbClient::Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime)
+{
+ auto error = StartSync ();
+ if (error.Fail ())
+ return error;
+
+ const std::string remote_file_path (remote_file.GetPath (false));
+ error = SendSyncRequest (kSTAT, remote_file_path.length (), remote_file_path.c_str ());
+ if (error.Fail ())
+ return Error ("Failed to send request: %s", error.AsCString ());
+
+ static const size_t stat_len = strlen (kSTAT);
+ static const size_t response_len = stat_len + (sizeof (uint32_t) * 3);
+
+ std::vector<char> buffer (response_len);
+ error = ReadAllBytes (&buffer[0], buffer.size ());
+ if (error.Fail ())
+ return Error ("Failed to read response: %s", error.AsCString ());
+
+ DataExtractor extractor (&buffer[0], buffer.size (), eByteOrderLittle, sizeof (void*));
+ offset_t offset = 0;
+
+ const void* command = extractor.GetData (&offset, stat_len);
+ if (!command)
+ return Error ("Failed to get response command");
+ const char* command_str = static_cast<const char*> (command);
+ if (strncmp (command_str, kSTAT, stat_len))
+ return Error ("Got invalid stat command: %s", command_str);
+
+ mode = extractor.GetU32 (&offset);
+ size = extractor.GetU32 (&offset);
+ mtime = extractor.GetU32 (&offset);
+ return Error ();
+}
+
+Error
+AdbClient::Shell (const char* command, uint32_t timeout_ms, std::string* output)
+{
+ auto error = SwitchDeviceTransport ();
+ if (error.Fail ())
+ return Error ("Failed to switch to device transport: %s", error.AsCString ());
+
+ StreamString adb_command;
+ adb_command.Printf("shell:%s", command);
+ error = SendMessage (adb_command.GetData(), false);
+ if (error.Fail ())
+ return error;
+
+ error = ReadResponseStatus ();
+ if (error.Fail ())
+ return error;
+
+ std::vector<char> in_buffer;
+ error = ReadMessageStream (in_buffer, timeout_ms);
+ if (error.Fail())
+ return error;
+
+ if (output)
+ output->assign(in_buffer.begin(), in_buffer.end());
+ return error;
+}
diff --git a/source/Plugins/Platform/Android/AdbClient.h b/source/Plugins/Platform/Android/AdbClient.h
new file mode 100644
index 000000000000..4ec411d1411d
--- /dev/null
+++ b/source/Plugins/Platform/Android/AdbClient.h
@@ -0,0 +1,132 @@
+//===-- AdbClient.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_AdbClient_h_
+#define liblldb_AdbClient_h_
+
+// C Includes
+
+// C++ Includes
+
+#include <list>
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+
+namespace lldb_private {
+
+class FileSpec;
+
+namespace platform_android {
+
+class AdbClient
+{
+public:
+ enum UnixSocketNamespace
+ {
+ UnixSocketNamespaceAbstract,
+ UnixSocketNamespaceFileSystem,
+ };
+
+ using DeviceIDList = std::list<std::string>;
+
+ static Error
+ CreateByDeviceID(const std::string &device_id, AdbClient &adb);
+
+ AdbClient () = default;
+ explicit AdbClient (const std::string &device_id);
+
+ const std::string&
+ GetDeviceID() const;
+
+ Error
+ GetDevices (DeviceIDList &device_list);
+
+ Error
+ SetPortForwarding (const uint16_t local_port, const uint16_t remote_port);
+
+ Error
+ SetPortForwarding (const uint16_t local_port,
+ const char* remote_socket_name,
+ const UnixSocketNamespace socket_namespace);
+
+ Error
+ DeletePortForwarding (const uint16_t local_port);
+
+ Error
+ PullFile (const FileSpec &remote_file, const FileSpec &local_file);
+
+ Error
+ PushFile (const FileSpec &local_file, const FileSpec &remote_file);
+
+ Error
+ Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime);
+
+ Error
+ Shell (const char* command, uint32_t timeout_ms, std::string* output);
+
+private:
+ Error
+ Connect ();
+
+ void
+ SetDeviceID (const std::string &device_id);
+
+ Error
+ SendMessage (const std::string &packet, const bool reconnect = true);
+
+ Error
+ SendDeviceMessage (const std::string &packet);
+
+ Error
+ SendSyncRequest (const char *request_id, const uint32_t data_len, const void *data);
+
+ Error
+ ReadSyncHeader (std::string &response_id, uint32_t &data_len);
+
+ Error
+ ReadMessage (std::vector<char> &message);
+
+ Error
+ ReadMessageStream (std::vector<char> &message, uint32_t timeout_ms);
+
+ Error
+ GetResponseError (const char *response_id);
+
+ Error
+ ReadResponseStatus ();
+
+ Error
+ SwitchDeviceTransport ();
+
+ Error
+ Sync ();
+
+ Error
+ StartSync ();
+
+ Error
+ PullFileChunk (std::vector<char> &buffer, bool &eof);
+
+ Error
+ ReadAllBytes (void *buffer, size_t size);
+
+ std::string m_device_id;
+ ConnectionFileDescriptor m_conn;
+};
+
+} // namespace platform_android
+} // namespace lldb_private
+
+#endif // liblldb_AdbClient_h_
diff --git a/source/Plugins/Platform/Android/CMakeLists.txt b/source/Plugins/Platform/Android/CMakeLists.txt
new file mode 100644
index 000000000000..e831a33a4b6d
--- /dev/null
+++ b/source/Plugins/Platform/Android/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_lldb_library(lldbPluginPlatformAndroid
+ AdbClient.cpp
+ PlatformAndroid.cpp
+ PlatformAndroidRemoteGDBServer.cpp
+ )
diff --git a/source/Plugins/Platform/Android/Makefile b/source/Plugins/Platform/Android/Makefile
new file mode 100644
index 000000000000..aa186f924e66
--- /dev/null
+++ b/source/Plugins/Platform/Android/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/Android/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformAndroid
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Platform/Android/PlatformAndroid.cpp b/source/Plugins/Platform/Android/PlatformAndroid.cpp
new file mode 100644
index 000000000000..e842884c046a
--- /dev/null
+++ b/source/Plugins/Platform/Android/PlatformAndroid.cpp
@@ -0,0 +1,389 @@
+//===-- PlatformAndroid.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/StringConvert.h"
+#include "Utility/UriParser.h"
+
+// Project includes
+#include "AdbClient.h"
+#include "PlatformAndroid.h"
+#include "PlatformAndroidRemoteGDBServer.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::platform_android;
+
+static uint32_t g_initialize_count = 0;
+static const unsigned int g_android_default_cache_size = 2048; // Fits inside 4k adb packet.
+
+void
+PlatformAndroid::Initialize ()
+{
+ PlatformLinux::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+#if defined(__ANDROID__)
+ PlatformSP default_platform_sp (new PlatformAndroid(true));
+ default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
+ Platform::SetHostPlatform (default_platform_sp);
+#endif
+ PluginManager::RegisterPlugin (PlatformAndroid::GetPluginNameStatic(false),
+ PlatformAndroid::GetPluginDescriptionStatic(false),
+ PlatformAndroid::CreateInstance);
+ }
+}
+
+void
+PlatformAndroid::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformAndroid::CreateInstance);
+ }
+ }
+
+ PlatformLinux::Terminate ();
+}
+
+PlatformSP
+PlatformAndroid::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::PC:
+ create = true;
+ break;
+
+#if defined(__ANDROID__)
+ // Only accept "unknown" for the vendor if the host is android and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified_
+ case llvm::Triple::VendorType::UnknownVendor:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::Android:
+ break;
+
+#if defined(__ANDROID__)
+ // Only accept "unknown" for the OS if the host is android and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::OSType::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformAndroid::%s() creating remote-android platform", __FUNCTION__);
+ return PlatformSP(new PlatformAndroid(false));
+ }
+
+ if (log)
+ log->Printf ("PlatformAndroid::%s() aborting creation of remote-android platform", __FUNCTION__);
+
+ return PlatformSP();
+}
+
+PlatformAndroid::PlatformAndroid (bool is_host) :
+ PlatformLinux(is_host),
+ m_sdk_version(0)
+{
+}
+
+PlatformAndroid::~PlatformAndroid()
+{
+}
+
+ConstString
+PlatformAndroid::GetPluginNameStatic (bool is_host)
+{
+ if (is_host)
+ {
+ static ConstString g_host_name(Platform::GetHostPlatformName ());
+ return g_host_name;
+ }
+ else
+ {
+ static ConstString g_remote_name("remote-android");
+ return g_remote_name;
+ }
+}
+
+const char *
+PlatformAndroid::GetPluginDescriptionStatic (bool is_host)
+{
+ if (is_host)
+ return "Local Android user platform plug-in.";
+ else
+ return "Remote Android user platform plug-in.";
+}
+
+ConstString
+PlatformAndroid::GetPluginName()
+{
+ return GetPluginNameStatic(IsHost());
+}
+
+Error
+PlatformAndroid::ConnectRemote(Args& args)
+{
+ m_device_id.clear();
+
+ if (IsHost())
+ {
+ return Error ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString());
+ }
+
+ if (!m_remote_platform_sp)
+ m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer());
+
+ int port;
+ std::string scheme, host, path;
+ const char *url = args.GetArgumentAtIndex(0);
+ if (!url)
+ return Error("URL is null.");
+ if (!UriParser::Parse(url, scheme, host, port, path))
+ return Error("Invalid URL: %s", url);
+ if (host != "localhost")
+ m_device_id = host;
+
+ auto error = PlatformLinux::ConnectRemote(args);
+ if (error.Success())
+ {
+ AdbClient adb;
+ error = AdbClient::CreateByDeviceID(m_device_id, adb);
+ if (error.Fail())
+ return error;
+
+ m_device_id = adb.GetDeviceID();
+ }
+ return error;
+}
+
+Error
+PlatformAndroid::GetFile (const FileSpec& source,
+ const FileSpec& destination)
+{
+ if (IsHost() || !m_remote_platform_sp)
+ return PlatformLinux::GetFile(source, destination);
+
+ FileSpec source_spec (source.GetPath (false), false, FileSpec::ePathSyntaxPosix);
+ if (source_spec.IsRelative())
+ source_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (source_spec.GetCString (false));
+
+ AdbClient adb (m_device_id);
+ return adb.PullFile (source_spec, destination);
+}
+
+Error
+PlatformAndroid::PutFile (const FileSpec& source,
+ const FileSpec& destination,
+ uint32_t uid,
+ uint32_t gid)
+{
+ if (IsHost() || !m_remote_platform_sp)
+ return PlatformLinux::PutFile (source, destination, uid, gid);
+
+ FileSpec destination_spec (destination.GetPath (false), false, FileSpec::ePathSyntaxPosix);
+ if (destination_spec.IsRelative())
+ destination_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (destination_spec.GetCString (false));
+
+ AdbClient adb (m_device_id);
+ // TODO: Set correct uid and gid on remote file.
+ return adb.PushFile(source, destination_spec);
+}
+
+const char *
+PlatformAndroid::GetCacheHostname ()
+{
+ return m_device_id.c_str ();
+}
+
+Error
+PlatformAndroid::DownloadModuleSlice (const FileSpec &src_file_spec,
+ const uint64_t src_offset,
+ const uint64_t src_size,
+ const FileSpec &dst_file_spec)
+{
+ if (src_offset != 0)
+ return Error ("Invalid offset - %" PRIu64, src_offset);
+
+ return GetFile (src_file_spec, dst_file_spec);
+}
+
+Error
+PlatformAndroid::DisconnectRemote()
+{
+ Error error = PlatformLinux::DisconnectRemote();
+ if (error.Success())
+ {
+ m_device_id.clear();
+ m_sdk_version = 0;
+ }
+ return error;
+}
+
+uint32_t
+PlatformAndroid::GetDefaultMemoryCacheLineSize()
+{
+ return g_android_default_cache_size;
+}
+
+uint32_t
+PlatformAndroid::GetSdkVersion()
+{
+ if (!IsConnected())
+ return 0;
+
+ if (m_sdk_version != 0)
+ return m_sdk_version;
+
+ std::string version_string;
+ AdbClient adb(m_device_id);
+ Error error = adb.Shell("getprop ro.build.version.sdk", 5000 /* ms */, &version_string);
+ version_string = llvm::StringRef(version_string).trim().str();
+
+ if (error.Fail() || version_string.empty())
+ {
+ Log* log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM);
+ if (log)
+ log->Printf("Get SDK version failed. (error: %s, output: %s)",
+ error.AsCString(), version_string.c_str());
+ return 0;
+ }
+
+ m_sdk_version = StringConvert::ToUInt32(version_string.c_str());
+ return m_sdk_version;
+}
+
+Error
+PlatformAndroid::DownloadSymbolFile (const lldb::ModuleSP& module_sp,
+ const FileSpec& dst_file_spec)
+{
+ // For oat file we can try to fetch additional debug info from the device
+ if (module_sp->GetFileSpec().GetFileNameExtension() != ConstString("oat"))
+ return Error("Symbol file downloading only supported for oat files");
+
+ // If we have no information about the platform file we can't execute oatdump
+ if (!module_sp->GetPlatformFileSpec())
+ return Error("No platform file specified");
+
+ // Symbolizer isn't available before SDK version 23
+ if (GetSdkVersion() < 23)
+ return Error("Symbol file generation only supported on SDK 23+");
+
+ // If we already have symtab then we don't have to try and generate one
+ if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) != nullptr)
+ return Error("Symtab already available in the module");
+
+ AdbClient adb(m_device_id);
+
+ std::string tmpdir;
+ Error error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp", 5000 /* ms */, &tmpdir);
+ if (error.Fail() || tmpdir.empty())
+ return Error("Failed to generate temporary directory on the device (%s)", error.AsCString());
+ tmpdir = llvm::StringRef(tmpdir).trim().str();
+
+ // Create file remover for the temporary directory created on the device
+ std::unique_ptr<std::string, std::function<void(std::string*)>> tmpdir_remover(
+ &tmpdir,
+ [this, &adb](std::string* s) {
+ StreamString command;
+ command.Printf("rm -rf %s", s->c_str());
+ Error error = adb.Shell(command.GetData(), 5000 /* ms */, nullptr);
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (error.Fail())
+ log->Printf("Failed to remove temp directory: %s", error.AsCString());
+ }
+ );
+
+ FileSpec symfile_platform_filespec(tmpdir.c_str(), false);
+ symfile_platform_filespec.AppendPathComponent("symbolized.oat");
+
+ // Execute oatdump on the remote device to generate a file with symtab
+ StreamString command;
+ command.Printf("oatdump --symbolize=%s --output=%s",
+ module_sp->GetPlatformFileSpec().GetCString(false),
+ symfile_platform_filespec.GetCString(false));
+ error = adb.Shell(command.GetData(), 60000 /* ms */, nullptr);
+ if (error.Fail())
+ return Error("Oatdump failed: %s", error.AsCString());
+
+ // Download the symbolfile from the remote device
+ return GetFile(symfile_platform_filespec, dst_file_spec);
+}
+
+bool
+PlatformAndroid::GetRemoteOSVersion ()
+{
+ m_major_os_version = GetSdkVersion();
+ m_minor_os_version = 0;
+ m_update_os_version = 0;
+ return m_major_os_version != 0;
+}
+
+const char*
+PlatformAndroid::GetLibdlFunctionDeclarations() const
+{
+ return R"(
+ extern "C" void* dlopen(const char*, int) asm("__dl_dlopen");
+ extern "C" void* dlsym(void*, const char*) asm("__dl_dlsym");
+ extern "C" int dlclose(void*) asm("__dl_dlclose");
+ extern "C" char* dlerror(void) asm("__dl_dlerror");
+ )";
+}
diff --git a/source/Plugins/Platform/Android/PlatformAndroid.h b/source/Plugins/Platform/Android/PlatformAndroid.h
new file mode 100644
index 000000000000..119d0a0bdf04
--- /dev/null
+++ b/source/Plugins/Platform/Android/PlatformAndroid.h
@@ -0,0 +1,114 @@
+//===-- PlatformAndroid.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_PlatformAndroid_h_
+#define liblldb_PlatformAndroid_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Platform/Linux/PlatformLinux.h"
+
+namespace lldb_private {
+namespace platform_android {
+
+ class PlatformAndroid : public platform_linux::PlatformLinux
+ {
+ public:
+ PlatformAndroid(bool is_host);
+
+ ~PlatformAndroid() override;
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const ArchSpec *arch);
+
+ static ConstString
+ GetPluginNameStatic (bool is_host);
+
+ static const char *
+ GetPluginDescriptionStatic (bool is_host);
+
+ ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+
+ Error
+ ConnectRemote (Args& args) override;
+
+ Error
+ GetFile (const FileSpec& source,
+ const FileSpec& destination) override;
+
+ Error
+ PutFile (const FileSpec& source,
+ const FileSpec& destination,
+ uint32_t uid = UINT32_MAX,
+ uint32_t gid = UINT32_MAX) override;
+
+ uint32_t
+ GetSdkVersion();
+
+ bool
+ GetRemoteOSVersion() override;
+
+ Error
+ DisconnectRemote () override;
+
+ uint32_t
+ GetDefaultMemoryCacheLineSize() override;
+
+ protected:
+ const char *
+ GetCacheHostname () override;
+
+ Error
+ DownloadModuleSlice (const FileSpec &src_file_spec,
+ const uint64_t src_offset,
+ const uint64_t src_size,
+ const FileSpec &dst_file_spec) override;
+
+ Error
+ DownloadSymbolFile (const lldb::ModuleSP& module_sp,
+ const FileSpec& dst_file_spec) override;
+
+ const char*
+ GetLibdlFunctionDeclarations() const override;
+
+ private:
+ std::string m_device_id;
+ uint32_t m_sdk_version;
+
+ DISALLOW_COPY_AND_ASSIGN (PlatformAndroid);
+ };
+
+} // namespace platofor_android
+} // namespace lldb_private
+
+#endif // liblldb_PlatformAndroid_h_
diff --git a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
new file mode 100644
index 000000000000..3d91dd6b7a32
--- /dev/null
+++ b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
@@ -0,0 +1,275 @@
+//===-- PlatformAndroidRemoteGDBServer.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Other libraries and framework includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "PlatformAndroidRemoteGDBServer.h"
+#include "Utility/UriParser.h"
+
+#include <sstream>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace platform_android;
+
+static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform
+
+static Error
+ForwardPortWithAdb (const uint16_t local_port,
+ const uint16_t remote_port,
+ const char* remote_socket_name,
+ const llvm::Optional<AdbClient::UnixSocketNamespace>& socket_namespace,
+ std::string& device_id)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+
+ AdbClient adb;
+ auto error = AdbClient::CreateByDeviceID(device_id, adb);
+ if (error.Fail ())
+ return error;
+
+ device_id = adb.GetDeviceID();
+ if (log)
+ log->Printf("Connected to Android device \"%s\"", device_id.c_str ());
+
+ if (remote_port != 0)
+ {
+ if (log)
+ log->Printf("Forwarding remote TCP port %d to local TCP port %d", remote_port, local_port);
+ return adb.SetPortForwarding(local_port, remote_port);
+ }
+
+ if (log)
+ log->Printf("Forwarding remote socket \"%s\" to local TCP port %d", remote_socket_name, local_port);
+
+ if (!socket_namespace)
+ return Error("Invalid socket namespace");
+
+ return adb.SetPortForwarding(local_port, remote_socket_name, *socket_namespace);
+}
+
+static Error
+DeleteForwardPortWithAdb (uint16_t local_port, const std::string& device_id)
+{
+ AdbClient adb (device_id);
+ return adb.DeletePortForwarding (local_port);
+}
+
+static Error
+FindUnusedPort (uint16_t& port)
+{
+ Error error;
+ std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(false, error));
+ if (error.Fail())
+ return error;
+
+ error = tcp_socket->Listen("127.0.0.1:0", 1);
+ if (error.Success())
+ port = tcp_socket->GetLocalPortNumber();
+
+ return error;
+}
+
+PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer ()
+{
+}
+
+PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer ()
+{
+ for (const auto& it : m_port_forwards)
+ DeleteForwardPortWithAdb(it.second, m_device_id);
+}
+
+bool
+PlatformAndroidRemoteGDBServer::LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url)
+{
+ uint16_t remote_port = 0;
+ std::string socket_name;
+ if (!m_gdb_client.LaunchGDBServer ("127.0.0.1", pid, remote_port, socket_name))
+ return false;
+
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+
+ auto error = MakeConnectURL (pid,
+ remote_port,
+ socket_name.c_str (),
+ connect_url);
+ if (error.Success() && log)
+ log->Printf("gdbserver connect URL: %s", connect_url.c_str());
+
+ return error.Success();
+}
+
+bool
+PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid)
+{
+ DeleteForwardPort (pid);
+ return m_gdb_client.KillSpawnedProcess (pid);
+}
+
+Error
+PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args)
+{
+ m_device_id.clear();
+
+ if (args.GetArgumentCount() != 1)
+ return Error("\"platform connect\" takes a single argument: <connect-url>");
+
+ int remote_port;
+ std::string scheme, host, path;
+ const char *url = args.GetArgumentAtIndex (0);
+ if (!url)
+ return Error("URL is null.");
+ if (!UriParser::Parse (url, scheme, host, remote_port, path))
+ return Error("Invalid URL: %s", url);
+ if (host != "localhost")
+ m_device_id = host;
+
+ m_socket_namespace.reset();
+ if (scheme == ConnectionFileDescriptor::UNIX_CONNECT_SCHEME)
+ m_socket_namespace = AdbClient::UnixSocketNamespaceFileSystem;
+ else if (scheme == ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME)
+ m_socket_namespace = AdbClient::UnixSocketNamespaceAbstract;
+
+ std::string connect_url;
+ auto error = MakeConnectURL (g_remote_platform_pid,
+ (remote_port < 0) ? 0 : remote_port,
+ path.c_str (),
+ connect_url);
+
+ if (error.Fail ())
+ return error;
+
+ args.ReplaceArgumentAtIndex (0, connect_url.c_str ());
+
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("Rewritten platform connect URL: %s", connect_url.c_str());
+
+ error = PlatformRemoteGDBServer::ConnectRemote(args);
+ if (error.Fail ())
+ DeleteForwardPort (g_remote_platform_pid);
+
+ return error;
+}
+
+Error
+PlatformAndroidRemoteGDBServer::DisconnectRemote ()
+{
+ DeleteForwardPort (g_remote_platform_pid);
+ return PlatformRemoteGDBServer::DisconnectRemote ();
+}
+
+void
+PlatformAndroidRemoteGDBServer::DeleteForwardPort (lldb::pid_t pid)
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+
+ auto it = m_port_forwards.find(pid);
+ if (it == m_port_forwards.end())
+ return;
+
+ const auto port = it->second;
+ const auto error = DeleteForwardPortWithAdb(port, m_device_id);
+ if (error.Fail()) {
+ if (log)
+ log->Printf("Failed to delete port forwarding (pid=%" PRIu64 ", port=%d, device=%s): %s",
+ pid, port, m_device_id.c_str(), error.AsCString());
+ }
+ m_port_forwards.erase(it);
+}
+
+Error
+PlatformAndroidRemoteGDBServer::MakeConnectURL(const lldb::pid_t pid,
+ const uint16_t remote_port,
+ const char* remote_socket_name,
+ std::string& connect_url)
+{
+ static const int kAttempsNum = 5;
+
+ Error error;
+ // There is a race possibility that somebody will occupy
+ // a port while we're in between FindUnusedPort and ForwardPortWithAdb -
+ // adding the loop to mitigate such problem.
+ for (auto i = 0; i < kAttempsNum; ++i)
+ {
+ uint16_t local_port = 0;
+ error = FindUnusedPort(local_port);
+ if (error.Fail())
+ return error;
+
+ error = ForwardPortWithAdb(local_port,
+ remote_port,
+ remote_socket_name,
+ m_socket_namespace,
+ m_device_id);
+ if (error.Success())
+ {
+ m_port_forwards[pid] = local_port;
+ std::ostringstream url_str;
+ url_str << "connect://localhost:" << local_port;
+ connect_url = url_str.str();
+ break;
+ }
+ }
+
+ return error;
+}
+
+lldb::ProcessSP
+PlatformAndroidRemoteGDBServer::ConnectProcess(const char* connect_url,
+ const char* plugin_name,
+ lldb_private::Debugger &debugger,
+ lldb_private::Target *target,
+ lldb_private::Error &error)
+{
+ // We don't have the pid of the remote gdbserver when it isn't started by us but we still want
+ // to store the list of port forwards we set up in our port forward map. Generate a fake pid for
+ // these cases what won't collide with any other valid pid on android.
+ static lldb::pid_t s_remote_gdbserver_fake_pid = 0xffffffffffffffffULL;
+
+ int remote_port;
+ std::string scheme, host, path;
+ if (!UriParser::Parse(connect_url, scheme, host, remote_port, path))
+ {
+ error.SetErrorStringWithFormat("Invalid URL: %s", connect_url);
+ return nullptr;
+ }
+
+ std::string new_connect_url;
+ error = MakeConnectURL(s_remote_gdbserver_fake_pid--,
+ (remote_port < 0) ? 0 : remote_port,
+ path.c_str(),
+ new_connect_url);
+ if (error.Fail())
+ return nullptr;
+
+ return PlatformRemoteGDBServer::ConnectProcess(new_connect_url.c_str(),
+ plugin_name,
+ debugger,
+ target,
+ error);
+}
+
+size_t
+PlatformAndroidRemoteGDBServer::ConnectToWaitingProcesses(Debugger& debugger, Error& error)
+{
+ std::vector<std::string> connection_urls;
+ GetPendingGdbServerList(connection_urls);
+
+ for (size_t i = 0; i < connection_urls.size(); ++i)
+ {
+ ConnectProcess(connection_urls[i].c_str(), nullptr, debugger, nullptr, error);
+ if (error.Fail())
+ return i; // We already connected to i process succsessfully
+ }
+ return connection_urls.size();
+}
diff --git a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
new file mode 100644
index 000000000000..3d2653812ded
--- /dev/null
+++ b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
@@ -0,0 +1,79 @@
+//===-- PlatformAndroidRemoteGDBServer.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_PlatformAndroidRemoteGDBServer_h_
+#define liblldb_PlatformAndroidRemoteGDBServer_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <utility>
+
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
+
+#include "llvm/ADT/Optional.h"
+
+#include "AdbClient.h"
+
+namespace lldb_private {
+namespace platform_android {
+
+class PlatformAndroidRemoteGDBServer : public platform_gdb_server::PlatformRemoteGDBServer
+{
+public:
+ PlatformAndroidRemoteGDBServer();
+
+ ~PlatformAndroidRemoteGDBServer() override;
+
+ Error
+ ConnectRemote (Args& args) override;
+
+ Error
+ DisconnectRemote () override;
+
+ lldb::ProcessSP
+ ConnectProcess (const char* connect_url,
+ const char* plugin_name,
+ lldb_private::Debugger &debugger,
+ lldb_private::Target *target,
+ lldb_private::Error &error) override;
+
+ size_t
+ ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) override;
+
+protected:
+ std::string m_device_id;
+ std::map<lldb::pid_t, uint16_t> m_port_forwards;
+ llvm::Optional<AdbClient::UnixSocketNamespace> m_socket_namespace;
+
+ bool
+ LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url) override;
+
+ bool
+ KillSpawnedProcess (lldb::pid_t pid) override;
+
+ void
+ DeleteForwardPort (lldb::pid_t pid);
+
+ Error
+ MakeConnectURL(const lldb::pid_t pid,
+ const uint16_t remote_port,
+ const char* remote_socket_name,
+ std::string& connect_url);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformAndroidRemoteGDBServer);
+};
+
+} // namespace platform_android
+} // namespace lldb_private
+
+#endif // liblldb_PlatformAndroidRemoteGDBServer_h_
diff --git a/source/Plugins/Platform/CMakeLists.txt b/source/Plugins/Platform/CMakeLists.txt
new file mode 100644
index 000000000000..2e3a3f7c1b2e
--- /dev/null
+++ b/source/Plugins/Platform/CMakeLists.txt
@@ -0,0 +1,16 @@
+#if (CMAKE_SYSTEM_NAME MATCHES "Linux")
+ add_subdirectory(Linux)
+#elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ add_subdirectory(FreeBSD)
+#elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
+ add_subdirectory(NetBSD)
+#elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ add_subdirectory(MacOSX)
+#elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ add_subdirectory(Windows)
+#endif()
+
+add_subdirectory(POSIX)
+add_subdirectory(gdb-server)
+add_subdirectory(Kalimba)
+add_subdirectory(Android)
diff --git a/source/Plugins/Platform/FreeBSD/CMakeLists.txt b/source/Plugins/Platform/FreeBSD/CMakeLists.txt
new file mode 100644
index 000000000000..57153969c3b4
--- /dev/null
+++ b/source/Plugins/Platform/FreeBSD/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginPlatformFreeBSD
+ PlatformFreeBSD.cpp
+ )
diff --git a/source/Plugins/Platform/FreeBSD/Makefile b/source/Plugins/Platform/FreeBSD/Makefile
new file mode 100644
index 000000000000..e5c25d8504df
--- /dev/null
+++ b/source/Plugins/Platform/FreeBSD/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/FreeBSD/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformFreeBSD
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Platform/Kalimba/CMakeLists.txt b/source/Plugins/Platform/Kalimba/CMakeLists.txt
new file mode 100644
index 000000000000..df0bf9761a00
--- /dev/null
+++ b/source/Plugins/Platform/Kalimba/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginPlatformKalimba
+ PlatformKalimba.cpp
+ )
diff --git a/source/Plugins/Platform/Kalimba/Makefile b/source/Plugins/Platform/Kalimba/Makefile
new file mode 100644
index 000000000000..c22b7d21c13d
--- /dev/null
+++ b/source/Plugins/Platform/Kalimba/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/Kalimba/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformKalimba
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Platform/Kalimba/PlatformKalimba.cpp b/source/Plugins/Platform/Kalimba/PlatformKalimba.cpp
new file mode 100644
index 000000000000..2f1e4d554320
--- /dev/null
+++ b/source/Plugins/Platform/Kalimba/PlatformKalimba.cpp
@@ -0,0 +1,324 @@
+//===-- PlatformKalimba.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformKalimba.h"
+#include "lldb/Host/Config.h"
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static uint32_t g_initialize_count = 0;
+
+PlatformSP
+PlatformKalimba::CreateInstance (bool force, const ArchSpec *arch)
+{
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::CSR:
+ create = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (create)
+ return PlatformSP(new PlatformKalimba(false));
+ return PlatformSP();
+}
+
+lldb_private::ConstString
+PlatformKalimba::GetPluginNameStatic (bool /*is_host*/)
+{
+ static ConstString g_remote_name("kalimba");
+ return g_remote_name;
+}
+
+const char *
+PlatformKalimba::GetPluginDescriptionStatic (bool /*is_host*/)
+{
+ return "Kalimba user platform plug-in.";
+}
+
+lldb_private::ConstString
+PlatformKalimba::GetPluginName()
+{
+ return GetPluginNameStatic(false);
+}
+
+void
+PlatformKalimba::Initialize ()
+{
+ Platform::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+ PluginManager::RegisterPlugin(PlatformKalimba::GetPluginNameStatic(false),
+ PlatformKalimba::GetPluginDescriptionStatic(false),
+ PlatformKalimba::CreateInstance);
+ }
+}
+
+void
+PlatformKalimba::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformKalimba::CreateInstance);
+ }
+ }
+
+ Platform::Terminate ();
+}
+
+Error
+PlatformKalimba::ResolveExecutable (const ModuleSpec &ms,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ char exe_path[PATH_MAX];
+ ModuleSpec resolved_module_spec(ms);
+
+ if (!resolved_module_spec.GetFileSpec().Exists())
+ {
+ resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path);
+ }
+
+ if (error.Success())
+ {
+ if (resolved_module_spec.GetArchitecture().IsValid())
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+ if (error.Fail())
+ {
+ // If we failed, it may be because the vendor and os aren't known. If that is the
+ // case, try setting them to the host architecture and give it another try.
+ llvm::Triple &module_triple = resolved_module_spec.GetArchitecture().GetTriple();
+ bool is_vendor_specified = (module_triple.getVendor() != llvm::Triple::UnknownVendor);
+ bool is_os_specified = (module_triple.getOS() != llvm::Triple::UnknownOS);
+ if (!is_vendor_specified || !is_os_specified)
+ {
+ const llvm::Triple &host_triple = HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple();
+
+ if (!is_vendor_specified)
+ module_triple.setVendorName (host_triple.getVendorName());
+ if (!is_os_specified)
+ module_triple.setOSName (host_triple.getOSName());
+
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+ }
+ }
+
+ // TODO find out why exe_module_sp might be NULL
+ if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL)
+ {
+ exe_module_sp.reset();
+ error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+ }
+ else
+ {
+ // No valid architecture was specified, ask the platform for
+ // the architectures that we should be using (in the correct order)
+ // and see if we can find a match that way
+ StreamString arch_names;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ if (resolved_module_spec.GetFileSpec().Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
+Error
+PlatformKalimba::GetFileWithUUID (const FileSpec & /*platform_file*/,
+ const UUID * /*uuid_ptr*/, FileSpec & /*local_file*/)
+{
+ return Error();
+}
+
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformKalimba::PlatformKalimba (bool is_host) :
+ Platform(is_host), // This is the local host platform
+ m_remote_platform_sp ()
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformKalimba::~PlatformKalimba()
+{
+}
+
+bool
+PlatformKalimba::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ bool success = false;
+ if (IsHost())
+ {
+ success = false;
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
+ }
+ return success;
+}
+
+bool
+PlatformKalimba::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ if (idx == 0)
+ {
+ arch = ArchSpec("kalimba3-csr-unknown");
+ return true;
+ }
+ if (idx == 1)
+ {
+ arch = ArchSpec("kalimba4-csr-unknown");
+ return true;
+ }
+ if (idx == 2)
+ {
+ arch = ArchSpec("kalimba5-csr-unknown");
+ return true;
+ }
+ return false;
+}
+
+void
+PlatformKalimba::GetStatus (Stream &strm)
+{
+ Platform::GetStatus(strm);
+}
+
+size_t
+PlatformKalimba::GetSoftwareBreakpointTrapOpcode (Target & /*target*/,
+ BreakpointSite * /*bp_site*/)
+{
+ // the target hardware does not support software breakpoints
+ return 0;
+}
+
+Error
+PlatformKalimba::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+
+ if (IsHost())
+ {
+ error.SetErrorString ("native execution is not possible");
+ }
+ else
+ {
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return error;
+}
+
+lldb::ProcessSP
+PlatformKalimba::Attach(ProcessAttachInfo &attach_info,
+ Debugger &debugger,
+ Target *target,
+ Error &error)
+{
+ lldb::ProcessSP process_sp;
+ if (IsHost())
+ {
+ error.SetErrorString ("native execution is not possible");
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return process_sp;
+}
+
+void
+PlatformKalimba::CalculateTrapHandlerSymbolNames ()
+{
+ // TODO Research this sometime.
+}
diff --git a/source/Plugins/Platform/Kalimba/PlatformKalimba.h b/source/Plugins/Platform/Kalimba/PlatformKalimba.h
new file mode 100644
index 000000000000..dd68415838f0
--- /dev/null
+++ b/source/Plugins/Platform/Kalimba/PlatformKalimba.h
@@ -0,0 +1,99 @@
+//===-- PlatformKalimba.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_PlatformKalimba_h_
+#define liblldb_PlatformKalimba_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Platform.h"
+
+namespace lldb_private {
+
+ class PlatformKalimba : public Platform
+ {
+ public:
+ PlatformKalimba(bool is_host);
+
+ ~PlatformKalimba() override;
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic (bool is_host);
+
+ static const char *
+ GetPluginDescriptionStatic (bool is_host);
+
+ lldb_private::ConstString GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ Error ResolveExecutable(const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr) override;
+
+ const char *
+ GetDescription() override
+ {
+ return GetPluginDescriptionStatic(IsHost());
+ }
+
+ void GetStatus(Stream &strm) override;
+
+ Error GetFileWithUUID(const FileSpec &platform_file, const UUID *uuid, FileSpec &local_file) override;
+
+ bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info) override;
+
+ bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override;
+
+ size_t GetSoftwareBreakpointTrapOpcode(Target &target, BreakpointSite *bp_site) override;
+
+ lldb_private::Error LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) override;
+
+ lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, Debugger &debugger, Target *target,
+ Error &error) override;
+
+ // Kalimba processes can not be launched by spawning and attaching.
+ bool
+ CanDebugProcess() override
+ {
+ return false;
+ }
+
+ void CalculateTrapHandlerSymbolNames() override;
+
+ protected:
+ lldb::PlatformSP m_remote_platform_sp;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformKalimba);
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_PlatformKalimba_h_
diff --git a/source/Plugins/Platform/Linux/CMakeLists.txt b/source/Plugins/Platform/Linux/CMakeLists.txt
new file mode 100644
index 000000000000..4a9eb1460e38
--- /dev/null
+++ b/source/Plugins/Platform/Linux/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginPlatformLinux
+ PlatformLinux.cpp
+ )
diff --git a/source/Plugins/Platform/Linux/Makefile b/source/Plugins/Platform/Linux/Makefile
new file mode 100644
index 000000000000..2877fddf0bcd
--- /dev/null
+++ b/source/Plugins/Platform/Linux/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/Linux/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformLinux
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Platform/Linux/PlatformLinux.cpp b/source/Plugins/Platform/Linux/PlatformLinux.cpp
new file mode 100644
index 000000000000..8dc9769844c7
--- /dev/null
+++ b/source/Plugins/Platform/Linux/PlatformLinux.cpp
@@ -0,0 +1,868 @@
+//===-- PlatformLinux.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformLinux.h"
+#include "lldb/Host/Config.h"
+
+// C Includes
+#include <stdio.h>
+#ifndef LLDB_DISABLE_POSIX
+#include <sys/utsname.h>
+#endif
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/Property.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+
+// Define these constants from Linux mman.h for use when targeting
+// remote linux systems even when host has different values.
+#define MAP_PRIVATE 2
+#define MAP_ANON 0x20
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::platform_linux;
+
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+/// Code to handle the PlatformLinux settings
+//------------------------------------------------------------------
+
+namespace
+{
+ class PlatformLinuxProperties : public Properties
+ {
+ public:
+ PlatformLinuxProperties();
+
+ ~PlatformLinuxProperties() override = default;
+
+ static ConstString&
+ GetSettingName ();
+
+ private:
+ static const PropertyDefinition*
+ GetStaticPropertyDefinitions();
+ };
+
+ typedef std::shared_ptr<PlatformLinuxProperties> PlatformLinuxPropertiesSP;
+
+} // anonymous namespace
+
+PlatformLinuxProperties::PlatformLinuxProperties() :
+ Properties ()
+{
+ m_collection_sp.reset (new OptionValueProperties(GetSettingName ()));
+ m_collection_sp->Initialize (GetStaticPropertyDefinitions ());
+}
+
+ConstString&
+PlatformLinuxProperties::GetSettingName ()
+{
+ static ConstString g_setting_name("linux");
+ return g_setting_name;
+}
+
+const PropertyDefinition*
+PlatformLinuxProperties::GetStaticPropertyDefinitions()
+{
+ static PropertyDefinition
+ g_properties[] =
+ {
+ { NULL , OptionValue::eTypeInvalid, false, 0 , NULL, NULL, NULL }
+ };
+
+ return g_properties;
+}
+
+static const PlatformLinuxPropertiesSP &
+GetGlobalProperties()
+{
+ static PlatformLinuxPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ g_settings_sp.reset (new PlatformLinuxProperties ());
+ return g_settings_sp;
+}
+
+void
+PlatformLinux::DebuggerInitialize (Debugger &debugger)
+{
+ if (!PluginManager::GetSettingForPlatformPlugin (debugger, PlatformLinuxProperties::GetSettingName()))
+ {
+ const bool is_global_setting = true;
+ PluginManager::CreateSettingForPlatformPlugin (debugger,
+ GetGlobalProperties()->GetValueProperties(),
+ ConstString ("Properties for the PlatformLinux plug-in."),
+ is_global_setting);
+ }
+}
+
+//------------------------------------------------------------------
+
+PlatformSP
+PlatformLinux::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformLinux::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getOS())
+ {
+ case llvm::Triple::Linux:
+ create = true;
+ break;
+
+#if defined(__linux__)
+ // Only accept "unknown" for the OS if the host is linux and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::OSType::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformLinux::%s() creating remote-linux platform", __FUNCTION__);
+ return PlatformSP(new PlatformLinux(false));
+ }
+
+ if (log)
+ log->Printf ("PlatformLinux::%s() aborting creation of remote-linux platform", __FUNCTION__);
+
+ return PlatformSP();
+}
+
+ConstString
+PlatformLinux::GetPluginNameStatic (bool is_host)
+{
+ if (is_host)
+ {
+ static ConstString g_host_name(Platform::GetHostPlatformName ());
+ return g_host_name;
+ }
+ else
+ {
+ static ConstString g_remote_name("remote-linux");
+ return g_remote_name;
+ }
+}
+
+const char *
+PlatformLinux::GetPluginDescriptionStatic (bool is_host)
+{
+ if (is_host)
+ return "Local Linux user platform plug-in.";
+ else
+ return "Remote Linux user platform plug-in.";
+}
+
+ConstString
+PlatformLinux::GetPluginName()
+{
+ return GetPluginNameStatic(IsHost());
+}
+
+void
+PlatformLinux::Initialize ()
+{
+ PlatformPOSIX::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+#if defined(__linux__) && !defined(__ANDROID__)
+ PlatformSP default_platform_sp (new PlatformLinux(true));
+ default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
+ Platform::SetHostPlatform (default_platform_sp);
+#endif
+ PluginManager::RegisterPlugin(PlatformLinux::GetPluginNameStatic(false),
+ PlatformLinux::GetPluginDescriptionStatic(false),
+ PlatformLinux::CreateInstance,
+ PlatformLinux::DebuggerInitialize);
+ }
+}
+
+void
+PlatformLinux::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformLinux::CreateInstance);
+ }
+ }
+
+ PlatformPOSIX::Terminate ();
+}
+
+Error
+PlatformLinux::ResolveExecutable (const ModuleSpec &ms,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ char exe_path[PATH_MAX];
+ ModuleSpec resolved_module_spec (ms);
+
+ if (IsHost())
+ {
+ // If we have "ls" as the exe_file, resolve the executable location based on
+ // the current path variables
+ if (!resolved_module_spec.GetFileSpec().Exists())
+ {
+ resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
+ resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
+ }
+
+ if (!resolved_module_spec.GetFileSpec().Exists())
+ resolved_module_spec.GetFileSpec().ResolveExecutableLocation ();
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ error.Clear();
+ else
+ {
+ error.SetErrorStringWithFormat("unable to find executable for '%s'", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ {
+ error = GetCachedExecutable (resolved_module_spec, exe_module_sp, module_search_paths_ptr, *m_remote_platform_sp);
+ }
+ else
+ {
+ // We may connect to a process and use the provided executable (Don't use local $PATH).
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ error.Clear();
+ else
+ error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path);
+ }
+ }
+
+ if (error.Success())
+ {
+ if (resolved_module_spec.GetArchitecture().IsValid())
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+ if (error.Fail())
+ {
+ // If we failed, it may be because the vendor and os aren't known. If that is the
+ // case, try setting them to the host architecture and give it another try.
+ llvm::Triple &module_triple = resolved_module_spec.GetArchitecture().GetTriple();
+ bool is_vendor_specified = (module_triple.getVendor() != llvm::Triple::UnknownVendor);
+ bool is_os_specified = (module_triple.getOS() != llvm::Triple::UnknownOS);
+ if (!is_vendor_specified || !is_os_specified)
+ {
+ const llvm::Triple &host_triple = HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple();
+
+ if (!is_vendor_specified)
+ module_triple.setVendorName (host_triple.getVendorName());
+ if (!is_os_specified)
+ module_triple.setOSName (host_triple.getOSName());
+
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+ }
+ }
+
+ // TODO find out why exe_module_sp might be NULL
+ if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL)
+ {
+ exe_module_sp.reset();
+ error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+ }
+ else
+ {
+ // No valid architecture was specified, ask the platform for
+ // the architectures that we should be using (in the correct order)
+ // and see if we can find a match that way
+ StreamString arch_names;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ if (resolved_module_spec.GetFileSpec().Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
+Error
+PlatformLinux::GetFileWithUUID (const FileSpec &platform_file,
+ const UUID *uuid_ptr, FileSpec &local_file)
+{
+ if (IsRemote())
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file);
+ }
+
+ // Default to the local case
+ local_file = platform_file;
+ return Error();
+}
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformLinux::PlatformLinux (bool is_host) :
+ PlatformPOSIX(is_host) // This is the local host platform
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformLinux::~PlatformLinux() = default;
+
+bool
+PlatformLinux::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ bool success = false;
+ if (IsHost())
+ {
+ success = Platform::GetProcessInfo (pid, process_info);
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
+ }
+ return success;
+}
+
+uint32_t
+PlatformLinux::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ uint32_t match_count = 0;
+ if (IsHost())
+ {
+ // Let the base class figure out the host details
+ match_count = Platform::FindProcesses (match_info, process_infos);
+ }
+ else
+ {
+ // If we are remote, we can only return results if we are connected
+ if (m_remote_platform_sp)
+ match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos);
+ }
+ return match_count;
+}
+
+bool
+PlatformLinux::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ if (IsHost())
+ {
+ ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
+ if (hostArch.GetTriple().isOSLinux())
+ {
+ if (idx == 0)
+ {
+ arch = hostArch;
+ return arch.IsValid();
+ }
+ else if (idx == 1)
+ {
+ // If the default host architecture is 64-bit, look for a 32-bit variant
+ if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit())
+ {
+ arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
+ return arch.IsValid();
+ }
+ }
+ }
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetSupportedArchitectureAtIndex(idx, arch);
+
+ llvm::Triple triple;
+ // Set the OS to linux
+ triple.setOS(llvm::Triple::Linux);
+ // Set the architecture
+ switch (idx)
+ {
+ case 0: triple.setArchName("x86_64"); break;
+ case 1: triple.setArchName("i386"); break;
+ case 2: triple.setArchName("arm"); break;
+ case 3: triple.setArchName("aarch64"); break;
+ case 4: triple.setArchName("mips64"); break;
+ case 5: triple.setArchName("hexagon"); break;
+ case 6: triple.setArchName("mips"); break;
+ case 7: triple.setArchName("mips64el"); break;
+ case 8: triple.setArchName("mipsel"); break;
+ default: return false;
+ }
+ // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the vendor by
+ // calling triple.SetVendorName("unknown") so that it is a "unspecified unknown".
+ // This means when someone calls triple.GetVendorName() it will return an empty string
+ // which indicates that the vendor can be set when two architectures are merged
+
+ // Now set the triple into "arch" and return true
+ arch.SetTriple(triple);
+ return true;
+ }
+ return false;
+}
+
+void
+PlatformLinux::GetStatus (Stream &strm)
+{
+ Platform::GetStatus(strm);
+
+#ifndef LLDB_DISABLE_POSIX
+ // Display local kernel information only when we are running in host mode.
+ // Otherwise, we would end up printing non-Linux information (when running
+ // on Mac OS for example).
+ if (IsHost())
+ {
+ struct utsname un;
+
+ if (uname(&un))
+ return;
+
+ strm.Printf (" Kernel: %s\n", un.sysname);
+ strm.Printf (" Release: %s\n", un.release);
+ strm.Printf (" Version: %s\n", un.version);
+ }
+#endif
+}
+
+size_t
+PlatformLinux::GetSoftwareBreakpointTrapOpcode (Target &target,
+ BreakpointSite *bp_site)
+{
+ ArchSpec arch = target.GetArchitecture();
+ const uint8_t *trap_opcode = NULL;
+ size_t trap_opcode_size = 0;
+
+ switch (arch.GetMachine())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case llvm::Triple::aarch64:
+ {
+ static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xd4 };
+ trap_opcode = g_aarch64_opcode;
+ trap_opcode_size = sizeof(g_aarch64_opcode);
+ }
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ {
+ static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
+ trap_opcode = g_i386_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
+ }
+ break;
+ case llvm::Triple::hexagon:
+ {
+ static const uint8_t g_hex_opcode[] = { 0x0c, 0xdb, 0x00, 0x54 };
+ trap_opcode = g_hex_opcode;
+ trap_opcode_size = sizeof(g_hex_opcode);
+ }
+ break;
+ case llvm::Triple::arm:
+ {
+ // The ARM reference recommends the use of 0xe7fddefe and 0xdefe
+ // but the linux kernel does otherwise.
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 };
+ static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde };
+
+ lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0));
+ AddressClass addr_class = eAddressClassUnknown;
+
+ if (bp_loc_sp)
+ {
+ addr_class = bp_loc_sp->GetAddress ().GetAddressClass ();
+
+ if (addr_class == eAddressClassUnknown &&
+ (bp_loc_sp->GetAddress ().GetFileAddress () & 1))
+ {
+ addr_class = eAddressClassCodeAlternateISA;
+ }
+ }
+
+ if (addr_class == eAddressClassCodeAlternateISA)
+ {
+ trap_opcode = g_thumb_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_thumb_breakpoint_opcode);
+ }
+ else
+ {
+ trap_opcode = g_arm_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ }
+ }
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mips64:
+ {
+ static const uint8_t g_hex_opcode[] = { 0x00, 0x00, 0x00, 0x0d };
+ trap_opcode = g_hex_opcode;
+ trap_opcode_size = sizeof(g_hex_opcode);
+ }
+ break;
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64el:
+ {
+ static const uint8_t g_hex_opcode[] = { 0x0d, 0x00, 0x00, 0x00 };
+ trap_opcode = g_hex_opcode;
+ trap_opcode_size = sizeof(g_hex_opcode);
+ }
+ break;
+ }
+
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+ return 0;
+}
+
+int32_t
+PlatformLinux::GetResumeCountForLaunchInfo (ProcessLaunchInfo &launch_info)
+{
+ int32_t resume_count = 0;
+
+ // Always resume past the initial stop when we use eLaunchFlagDebug
+ if (launch_info.GetFlags ().Test (eLaunchFlagDebug))
+ {
+ // Resume past the stop for the final exec into the true inferior.
+ ++resume_count;
+ }
+
+ // If we're not launching a shell, we're done.
+ const FileSpec &shell = launch_info.GetShell();
+ if (!shell)
+ return resume_count;
+
+ std::string shell_string = shell.GetPath();
+ // We're in a shell, so for sure we have to resume past the shell exec.
+ ++resume_count;
+
+ // Figure out what shell we're planning on using.
+ const char *shell_name = strrchr (shell_string.c_str(), '/');
+ if (shell_name == NULL)
+ shell_name = shell_string.c_str();
+ else
+ shell_name++;
+
+ if (strcmp (shell_name, "csh") == 0
+ || strcmp (shell_name, "tcsh") == 0
+ || strcmp (shell_name, "zsh") == 0
+ || strcmp (shell_name, "sh") == 0)
+ {
+ // These shells seem to re-exec themselves. Add another resume.
+ ++resume_count;
+ }
+
+ return resume_count;
+}
+
+bool
+PlatformLinux::CanDebugProcess ()
+{
+ if (IsHost ())
+ {
+ return true;
+ }
+ else
+ {
+ // If we're connected, we can debug.
+ return IsConnected ();
+ }
+}
+
+// For local debugging, Linux will override the debug logic to use llgs-launch rather than
+// lldb-launch, llgs-attach. This differs from current lldb-launch, debugserver-attach
+// approach on MacOSX.
+lldb::ProcessSP
+PlatformLinux::DebugProcess (ProcessLaunchInfo &launch_info,
+ Debugger &debugger,
+ Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ Error &error)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf ("PlatformLinux::%s entered (target %p)", __FUNCTION__, static_cast<void*>(target));
+
+ // If we're a remote host, use standard behavior from parent class.
+ if (!IsHost ())
+ return PlatformPOSIX::DebugProcess (launch_info, debugger, target, error);
+
+ //
+ // For local debugging, we'll insist on having ProcessGDBRemote create the process.
+ //
+
+ ProcessSP process_sp;
+
+ // Make sure we stop at the entry point
+ launch_info.GetFlags ().Set (eLaunchFlagDebug);
+
+ // We always launch the process we are going to debug in a separate process
+ // group, since then we can handle ^C interrupts ourselves w/o having to worry
+ // about the target getting them as well.
+ launch_info.SetLaunchInSeparateProcessGroup(true);
+
+ // Ensure we have a target.
+ if (target == nullptr)
+ {
+ if (log)
+ log->Printf ("PlatformLinux::%s creating new target", __FUNCTION__);
+
+ TargetSP new_target_sp;
+ error = debugger.GetTargetList().CreateTarget (debugger,
+ nullptr,
+ nullptr,
+ false,
+ nullptr,
+ new_target_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("PlatformLinux::%s failed to create new target: %s", __FUNCTION__, error.AsCString ());
+ return process_sp;
+ }
+
+ target = new_target_sp.get();
+ if (!target)
+ {
+ error.SetErrorString ("CreateTarget() returned nullptr");
+ if (log)
+ log->Printf ("PlatformLinux::%s failed: %s", __FUNCTION__, error.AsCString ());
+ return process_sp;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("PlatformLinux::%s using provided target", __FUNCTION__);
+ }
+
+ // Mark target as currently selected target.
+ debugger.GetTargetList().SetSelectedTarget(target);
+
+ // Now create the gdb-remote process.
+ if (log)
+ log->Printf ("PlatformLinux::%s having target create process with gdb-remote plugin", __FUNCTION__);
+ process_sp = target->CreateProcess (launch_info.GetListenerForProcess(debugger), "gdb-remote", nullptr);
+
+ if (!process_sp)
+ {
+ error.SetErrorString ("CreateProcess() failed for gdb-remote process");
+ if (log)
+ log->Printf ("PlatformLinux::%s failed: %s", __FUNCTION__, error.AsCString ());
+ return process_sp;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("PlatformLinux::%s successfully created process", __FUNCTION__);
+ }
+
+ // Adjust launch for a hijacker.
+ ListenerSP listener_sp;
+ if (!launch_info.GetHijackListener ())
+ {
+ if (log)
+ log->Printf ("PlatformLinux::%s setting up hijacker", __FUNCTION__);
+
+ listener_sp.reset (new Listener("lldb.PlatformLinux.DebugProcess.hijack"));
+ launch_info.SetHijackListener (listener_sp);
+ process_sp->HijackProcessEvents (listener_sp.get ());
+ }
+
+ // Log file actions.
+ if (log)
+ {
+ log->Printf ("PlatformLinux::%s launching process with the following file actions:", __FUNCTION__);
+
+ StreamString stream;
+ size_t i = 0;
+ const FileAction *file_action;
+ while ((file_action = launch_info.GetFileActionAtIndex (i++)) != nullptr)
+ {
+ file_action->Dump (stream);
+ log->PutCString (stream.GetString().c_str ());
+ stream.Clear();
+ }
+ }
+
+ // Do the launch.
+ error = process_sp->Launch(launch_info);
+ if (error.Success ())
+ {
+ // Handle the hijacking of process events.
+ if (listener_sp)
+ {
+ const StateType state = process_sp->WaitForProcessToStop (NULL, NULL, false, listener_sp.get());
+
+ if (state == eStateStopped)
+ {
+ if (log)
+ log->Printf ("PlatformLinux::%s pid %" PRIu64 " state %s\n",
+ __FUNCTION__, process_sp->GetID (), StateAsCString (state));
+ }
+ else
+ {
+ if (log)
+ log->Printf ("PlatformLinux::%s pid %" PRIu64 " state is not stopped - %s\n",
+ __FUNCTION__, process_sp->GetID (), StateAsCString (state));
+ }
+ }
+
+ // Hook up process PTY if we have one (which we should for local debugging with llgs).
+ int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
+ if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd)
+ {
+ process_sp->SetSTDIOFileDescriptor(pty_fd);
+ if (log)
+ log->Printf ("PlatformLinux::%s pid %" PRIu64 " hooked up STDIO pty to process", __FUNCTION__, process_sp->GetID ());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("PlatformLinux::%s pid %" PRIu64 " not using process STDIO pty", __FUNCTION__, process_sp->GetID ());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("PlatformLinux::%s process launch failed: %s", __FUNCTION__, error.AsCString ());
+ // FIXME figure out appropriate cleanup here. Do we delete the target? Do we delete the process? Does our caller do that?
+ }
+
+ return process_sp;
+}
+
+void
+PlatformLinux::CalculateTrapHandlerSymbolNames ()
+{
+ m_trap_handlers.push_back (ConstString ("_sigtramp"));
+}
+
+uint64_t
+PlatformLinux::ConvertMmapFlagsToPlatform(const ArchSpec &arch, unsigned flags)
+{
+ uint64_t flags_platform = 0;
+ uint64_t map_anon = MAP_ANON;
+
+ // To get correct flags for MIPS Architecture
+ if (arch.GetTriple ().getArch () == llvm::Triple::mips64
+ || arch.GetTriple ().getArch () == llvm::Triple::mips64el
+ || arch.GetTriple ().getArch () == llvm::Triple::mips
+ || arch.GetTriple ().getArch () == llvm::Triple::mipsel)
+ map_anon = 0x800;
+
+ if (flags & eMmapFlagsPrivate)
+ flags_platform |= MAP_PRIVATE;
+ if (flags & eMmapFlagsAnon)
+ flags_platform |= map_anon;
+ return flags_platform;
+}
+
+ConstString
+PlatformLinux::GetFullNameForDylib (ConstString basename)
+{
+ if (basename.IsEmpty())
+ return basename;
+
+ StreamString stream;
+ stream.Printf("lib%s.so", basename.GetCString());
+ return ConstString(stream.GetData());
+}
diff --git a/source/Plugins/Platform/Linux/PlatformLinux.h b/source/Plugins/Platform/Linux/PlatformLinux.h
new file mode 100644
index 000000000000..770a20c90cce
--- /dev/null
+++ b/source/Plugins/Platform/Linux/PlatformLinux.h
@@ -0,0 +1,122 @@
+//===-- PlatformLinux.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_PlatformLinux_h_
+#define liblldb_PlatformLinux_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
+
+namespace lldb_private {
+namespace platform_linux {
+
+ class PlatformLinux : public PlatformPOSIX
+ {
+ public:
+ PlatformLinux(bool is_host);
+
+ ~PlatformLinux() override;
+
+ static void
+ DebuggerInitialize (Debugger &debugger);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const ArchSpec *arch);
+
+ static ConstString
+ GetPluginNameStatic (bool is_host);
+
+ static const char *
+ GetPluginDescriptionStatic (bool is_host);
+
+ ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ Error
+ ResolveExecutable (const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr) override;
+
+ const char *
+ GetDescription () override
+ {
+ return GetPluginDescriptionStatic(IsHost());
+ }
+
+ void
+ GetStatus (Stream &strm) override;
+
+ Error
+ GetFileWithUUID (const FileSpec &platform_file,
+ const UUID* uuid, FileSpec &local_file) override;
+
+ bool
+ GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info) override;
+
+ uint32_t
+ FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos) override;
+
+ bool
+ GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) override;
+
+ size_t
+ GetSoftwareBreakpointTrapOpcode (Target &target,
+ BreakpointSite *bp_site) override;
+
+ int32_t
+ GetResumeCountForLaunchInfo (ProcessLaunchInfo &launch_info) override;
+
+ bool
+ CanDebugProcess () override;
+
+ lldb::ProcessSP
+ DebugProcess (ProcessLaunchInfo &launch_info,
+ Debugger &debugger,
+ Target *target,
+ Error &error) override;
+
+ void
+ CalculateTrapHandlerSymbolNames () override;
+
+ uint64_t
+ ConvertMmapFlagsToPlatform(const ArchSpec &arch, unsigned flags) override;
+
+ ConstString
+ GetFullNameForDylib (ConstString basename) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformLinux);
+ };
+
+} // namespace platform_linux
+} // namespace lldb_private
+
+#endif // liblldb_PlatformLinux_h_
diff --git a/source/Plugins/Platform/MacOSX/CMakeLists.txt b/source/Plugins/Platform/MacOSX/CMakeLists.txt
new file mode 100644
index 000000000000..02566ab3db06
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/CMakeLists.txt
@@ -0,0 +1,27 @@
+list(APPEND PLUGIN_PLATFORM_MACOSX_SOURCES
+ PlatformDarwin.cpp
+ PlatformDarwinKernel.cpp
+ PlatformMacOSX.cpp
+ PlatformRemoteiOS.cpp
+ PlatformRemoteAppleTV.cpp
+ PlatformRemoteAppleWatch.cpp
+ )
+
+list(APPEND PLUGIN_PLATFORM_MACOSX_DARWIN_ONLY_SOURCES
+ PlatformAppleSimulator.cpp
+ PlatformiOSSimulator.cpp
+ PlatformiOSSimulatorCoreSimulatorSupport.mm
+ PlatformAppleTVSimulator.cpp
+ PlatformAppleWatchSimulator.cpp
+ )
+
+if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ include_directories(${LIBXML2_INCLUDE_DIR})
+ list(APPEND PLUGIN_PLATFORM_MACOSX_SOURCES
+ ${PLUGIN_PLATFORM_MACOSX_DARWIN_ONLY_SOURCES})
+else()
+ list(APPEND LLVM_OPTIONAL_SOURCES
+ ${PLUGIN_PLATFORM_MACOSX_DARWIN_ONLY_SOURCES})
+endif()
+
+add_lldb_library(lldbPluginPlatformMacOSX ${PLUGIN_PLATFORM_MACOSX_SOURCES})
diff --git a/source/Plugins/Platform/MacOSX/Makefile b/source/Plugins/Platform/MacOSX/Makefile
new file mode 100644
index 000000000000..3e61dc982bd6
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/Makefile
@@ -0,0 +1,15 @@
+##===- source/Plugins/Platform/MacOSX/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformMacOSX
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
+
diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
new file mode 100644
index 000000000000..eea2844d5649
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
@@ -0,0 +1,303 @@
+//===-- PlatformAppleSimulator.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformAppleSimulator.h"
+
+// C Includes
+#if defined(__APPLE__)
+#include <dlfcn.h>
+#endif
+
+// C++ Includes
+#include <mutex>
+#include <thread>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#if !defined(__APPLE__)
+#define UNSUPPORTED_ERROR ("Apple simulators aren't supported on this platform")
+#endif
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+void
+PlatformAppleSimulator::Initialize ()
+{
+ PlatformDarwin::Initialize ();
+}
+
+void
+PlatformAppleSimulator::Terminate ()
+{
+ PlatformDarwin::Terminate ();
+}
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformAppleSimulator::PlatformAppleSimulator () :
+ PlatformDarwin (true),
+ m_core_simulator_framework_path()
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformAppleSimulator::~PlatformAppleSimulator()
+{
+}
+
+lldb_private::Error
+PlatformAppleSimulator::LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info)
+{
+#if defined(__APPLE__)
+ LoadCoreSimulator();
+ CoreSimulatorSupport::Device device(GetSimulatorDevice());
+
+ if (device.GetState() != CoreSimulatorSupport::Device::State::Booted)
+ {
+ Error boot_err;
+ device.Boot(boot_err);
+ if (boot_err.Fail())
+ return boot_err;
+ }
+
+ auto spawned = device.Spawn(launch_info);
+
+ if (spawned)
+ {
+ launch_info.SetProcessID(spawned.GetPID());
+ return Error();
+ }
+ else
+ return spawned.GetError();
+#else
+ Error err;
+ err.SetErrorString(UNSUPPORTED_ERROR);
+ return err;
+#endif
+}
+
+void
+PlatformAppleSimulator::GetStatus (Stream &strm)
+{
+#if defined(__APPLE__)
+ // This will get called by subclasses, so just output status on the
+ // current simulator
+ PlatformAppleSimulator::LoadCoreSimulator();
+
+ CoreSimulatorSupport::DeviceSet devices = CoreSimulatorSupport::DeviceSet::GetAvailableDevices();
+ const size_t num_devices = devices.GetNumDevices();
+ if (num_devices)
+ {
+ strm.Printf("Available devices:\n");
+ for (size_t i=0; i<num_devices; ++i)
+ {
+ CoreSimulatorSupport::Device device = devices.GetDeviceAtIndex(i);
+ strm.Printf(" %s: %s\n", device.GetUDID().c_str(), device.GetName().c_str());
+ }
+
+ if (m_device.hasValue() && m_device->operator bool())
+ {
+ strm.Printf("Current device: %s: %s", m_device->GetUDID().c_str(), m_device->GetName().c_str());
+ if (m_device->GetState() == CoreSimulatorSupport::Device::State::Booted)
+ {
+ strm.Printf(" state = booted");
+ }
+ strm.Printf("\nType \"platform connect <ARG>\" where <ARG> is a device UDID or a device name to disconnect and connect to a different device.\n");
+
+ }
+ else
+ {
+ strm.Printf("No current device is selected, \"platform connect <ARG>\" where <ARG> is a device UDID or a device name to connect to a specific device.\n");
+ }
+
+ }
+ else
+ {
+ strm.Printf("No devices are available.\n");
+ }
+#else
+ strm.Printf(UNSUPPORTED_ERROR);
+#endif
+}
+
+Error
+PlatformAppleSimulator::ConnectRemote (Args& args)
+{
+#if defined(__APPLE__)
+ Error error;
+ if (args.GetArgumentCount() == 1)
+ {
+ if (m_device)
+ DisconnectRemote ();
+ PlatformAppleSimulator::LoadCoreSimulator();
+ const char *arg_cstr = args.GetArgumentAtIndex(0);
+ if (arg_cstr)
+ {
+ std::string arg_str(arg_cstr);
+ CoreSimulatorSupport::DeviceSet devices = CoreSimulatorSupport::DeviceSet::GetAvailableDevices();
+ devices.ForEach([this, &arg_str](const CoreSimulatorSupport::Device &device) -> bool {
+ if (arg_str == device.GetUDID() || arg_str == device.GetName())
+ {
+ m_device = device;
+ return false; // Stop iterating
+ }
+ else
+ {
+ return true; // Keep iterating
+ }
+ });
+ if (!m_device)
+ error.SetErrorStringWithFormat("no device with UDID or name '%s' was found", arg_cstr);
+ }
+ }
+ else
+ {
+ error.SetErrorString("this command take a single UDID argument of the device you want to connect to.");
+ }
+ return error;
+#else
+ Error err;
+ err.SetErrorString(UNSUPPORTED_ERROR);
+ return err;
+#endif
+}
+
+Error
+PlatformAppleSimulator::DisconnectRemote ()
+{
+#if defined(__APPLE__)
+ m_device.reset();
+ return Error();
+#else
+ Error err;
+ err.SetErrorString(UNSUPPORTED_ERROR);
+ return err;
+#endif
+}
+
+
+lldb::ProcessSP
+PlatformAppleSimulator::DebugProcess (ProcessLaunchInfo &launch_info,
+ Debugger &debugger,
+ Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ Error &error)
+{
+#if defined(__APPLE__)
+ ProcessSP process_sp;
+ // Make sure we stop at the entry point
+ launch_info.GetFlags ().Set (eLaunchFlagDebug);
+ // We always launch the process we are going to debug in a separate process
+ // group, since then we can handle ^C interrupts ourselves w/o having to worry
+ // about the target getting them as well.
+ launch_info.SetLaunchInSeparateProcessGroup(true);
+
+ error = LaunchProcess (launch_info);
+ if (error.Success())
+ {
+ if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ {
+ ProcessAttachInfo attach_info (launch_info);
+ process_sp = Attach (attach_info, debugger, target, error);
+ if (process_sp)
+ {
+ launch_info.SetHijackListener(attach_info.GetHijackListener());
+
+ // Since we attached to the process, it will think it needs to detach
+ // if the process object just goes away without an explicit call to
+ // Process::Kill() or Process::Detach(), so let it know to kill the
+ // process if this happens.
+ process_sp->SetShouldDetach (false);
+
+ // If we didn't have any file actions, the pseudo terminal might
+ // have been used where the slave side was given as the file to
+ // open for stdin/out/err after we have already opened the master
+ // so we can read/write stdin/out/err.
+ int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
+ if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd)
+ {
+ process_sp->SetSTDIOFileDescriptor(pty_fd);
+ }
+ }
+ }
+ }
+
+ return process_sp;
+#else
+ return ProcessSP();
+#endif
+}
+
+FileSpec
+PlatformAppleSimulator::GetCoreSimulatorPath()
+{
+#if defined(__APPLE__)
+ Mutex::Locker locker (m_mutex);
+ if (!m_core_simulator_framework_path.hasValue())
+ {
+ const char *developer_dir = GetDeveloperDirectory();
+ if (developer_dir)
+ {
+ StreamString cs_path;
+ cs_path.Printf("%s/Library/PrivateFrameworks/CoreSimulator.framework/CoreSimulator", developer_dir);
+ const bool resolve_path = true;
+ m_core_simulator_framework_path = FileSpec(cs_path.GetData(), resolve_path);
+ }
+ }
+
+ return m_core_simulator_framework_path.getValue();
+#else
+ return FileSpec();
+#endif
+}
+
+void
+PlatformAppleSimulator::LoadCoreSimulator ()
+{
+#if defined(__APPLE__)
+ static std::once_flag g_load_core_sim_flag;
+ std::call_once(g_load_core_sim_flag, [this] {
+ const std::string core_sim_path(GetCoreSimulatorPath().GetPath());
+ if (core_sim_path.size())
+ dlopen(core_sim_path.c_str(), RTLD_LAZY);
+ });
+#endif
+}
+
+#if defined(__APPLE__)
+CoreSimulatorSupport::Device
+PlatformAppleSimulator::GetSimulatorDevice ()
+{
+ if (!m_device.hasValue())
+ {
+ const CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id = CoreSimulatorSupport::DeviceType::ProductFamilyID::iPhone;
+ m_device = CoreSimulatorSupport::DeviceSet::GetAvailableDevices().GetFanciest(dev_id);
+ }
+
+ if (m_device.hasValue())
+ return m_device.getValue();
+ else
+ return CoreSimulatorSupport::Device();
+}
+#endif
+
diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
new file mode 100644
index 000000000000..de8673b2a2af
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
@@ -0,0 +1,81 @@
+//===-- PlatformAppleSimulator.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_PlatformAppleSimulator_h_
+#define liblldb_PlatformAppleSimulator_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/FileSpec.h"
+#include "PlatformDarwin.h"
+#include "PlatformiOSSimulatorCoreSimulatorSupport.h"
+
+#include "llvm/ADT/Optional.h"
+
+class PlatformAppleSimulator : public PlatformDarwin
+{
+public:
+ //------------------------------------------------------------
+ // Class Functions
+ //------------------------------------------------------------
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ //------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------
+ PlatformAppleSimulator ();
+
+ virtual
+ ~PlatformAppleSimulator();
+
+ lldb_private::Error
+ LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info) override;
+
+ void
+ GetStatus (lldb_private::Stream &strm) override;
+
+ lldb_private::Error
+ ConnectRemote (lldb_private::Args& args) override;
+
+ lldb_private::Error
+ DisconnectRemote () override;
+
+ lldb::ProcessSP
+ DebugProcess (lldb_private::ProcessLaunchInfo &launch_info,
+ lldb_private::Debugger &debugger,
+ lldb_private::Target *target,
+ lldb_private::Error &error) override;
+
+protected:
+ llvm::Optional<lldb_private::FileSpec> m_core_simulator_framework_path;
+ llvm::Optional<CoreSimulatorSupport::Device> m_device;
+
+ lldb_private::FileSpec
+ GetCoreSimulatorPath();
+
+ void
+ LoadCoreSimulator ();
+
+#if defined(__APPLE__)
+ CoreSimulatorSupport::Device
+ GetSimulatorDevice ();
+#endif
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformAppleSimulator);
+
+};
+
+#endif // liblldb_PlatformAppleSimulator_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp
new file mode 100644
index 000000000000..f537934a9172
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp
@@ -0,0 +1,466 @@
+//===-- PlatformAppleTVSimulator.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformAppleTVSimulator.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+// Static Variables
+//------------------------------------------------------------------
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+void
+PlatformAppleTVSimulator::Initialize ()
+{
+ PlatformDarwin::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+ PluginManager::RegisterPlugin (PlatformAppleTVSimulator::GetPluginNameStatic(),
+ PlatformAppleTVSimulator::GetDescriptionStatic(),
+ PlatformAppleTVSimulator::CreateInstance);
+ }
+}
+
+void
+PlatformAppleTVSimulator::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformAppleTVSimulator::CreateInstance);
+ }
+ }
+
+ PlatformDarwin::Terminate ();
+}
+
+PlatformSP
+PlatformAppleTVSimulator::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformAppleTVSimulator::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ switch (arch->GetMachine())
+ {
+ case llvm::Triple::x86_64:
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::Apple:
+ create = true;
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the vendor if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::TvOS:
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the OS if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformAppleTVSimulator::%s() creating platform", __FUNCTION__);
+
+ return PlatformSP(new PlatformAppleTVSimulator ());
+ }
+
+ if (log)
+ log->Printf ("PlatformAppleTVSimulator::%s() aborting creation of platform", __FUNCTION__);
+
+ return PlatformSP();
+}
+
+
+lldb_private::ConstString
+PlatformAppleTVSimulator::GetPluginNameStatic ()
+{
+ static ConstString g_name("tvos-simulator");
+ return g_name;
+}
+
+const char *
+PlatformAppleTVSimulator::GetDescriptionStatic()
+{
+ return "Apple TV simulator platform plug-in.";
+}
+
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformAppleTVSimulator::PlatformAppleTVSimulator () :
+ PlatformDarwin (true),
+ m_sdk_directory ()
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformAppleTVSimulator::~PlatformAppleTVSimulator()
+{
+}
+
+
+void
+PlatformAppleTVSimulator::GetStatus (Stream &strm)
+{
+ Platform::GetStatus (strm);
+ const char *sdk_directory = GetSDKDirectoryAsCString();
+ if (sdk_directory)
+ strm.Printf (" SDK Path: \"%s\"\n", sdk_directory);
+ else
+ strm.PutCString (" SDK Path: error: unable to locate SDK\n");
+}
+
+
+Error
+PlatformAppleTVSimulator::ResolveExecutable (const ModuleSpec &module_spec,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ ModuleSpec resolved_module_spec(module_spec);
+
+ // If we have "ls" as the exe_file, resolve the executable loation based on
+ // the current path variables
+ // TODO: resolve bare executables in the Platform SDK
+// if (!resolved_exe_file.Exists())
+// resolved_exe_file.ResolveExecutableLocation ();
+
+ // Resolve any executable within a bundle on MacOSX
+ // TODO: verify that this handles shallow bundles, if not then implement one ourselves
+ Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ {
+ if (resolved_module_spec.GetArchitecture().IsValid())
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ return error;
+ exe_module_sp.reset();
+ }
+ // No valid architecture was specified or the exact ARM slice wasn't
+ // found so ask the platform for the architectures that we should be
+ // using (in the correct order) and see if we can find a match that way
+ StreamString arch_names;
+ ArchSpec platform_arch;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
+ {
+ // Only match x86 with x86 and x86_64 with x86_64...
+ if (!module_spec.GetArchitecture().IsValid() || module_spec.GetArchitecture().GetCore() == resolved_module_spec.GetArchitecture().GetCore())
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (platform_arch.GetArchitectureName());
+ }
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ if (resolved_module_spec.GetFileSpec().Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("'%s' does not exist",
+ module_spec.GetFileSpec().GetPath().c_str());
+ }
+
+ return error;
+}
+
+static FileSpec::EnumerateDirectoryResult
+EnumerateDirectoryCallback (void *baton, FileSpec::FileType file_type, const FileSpec &file_spec)
+{
+ if (file_type == FileSpec::eFileTypeDirectory)
+ {
+ const char *filename = file_spec.GetFilename().GetCString();
+ if (filename && strncmp(filename, "AppleTVSimulator", strlen ("AppleTVSimulator")) == 0)
+ {
+ ::snprintf ((char *)baton, PATH_MAX, "%s", filename);
+ return FileSpec::eEnumerateDirectoryResultQuit;
+ }
+ }
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+
+
+const char *
+PlatformAppleTVSimulator::GetSDKDirectoryAsCString()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_sdk_directory.empty())
+ {
+ const char *developer_dir = GetDeveloperDirectory();
+ if (developer_dir)
+ {
+ char sdks_directory[PATH_MAX];
+ char sdk_dirname[PATH_MAX];
+ sdk_dirname[0] = '\0';
+ snprintf (sdks_directory,
+ sizeof(sdks_directory),
+ "%s/Platforms/AppleTVSimulator.platform/Developer/SDKs",
+ developer_dir);
+ FileSpec simulator_sdk_spec;
+ bool find_directories = true;
+ bool find_files = false;
+ bool find_other = false;
+ FileSpec::EnumerateDirectory (sdks_directory,
+ find_directories,
+ find_files,
+ find_other,
+ EnumerateDirectoryCallback,
+ sdk_dirname);
+
+ if (sdk_dirname[0])
+ {
+ m_sdk_directory = sdks_directory;
+ m_sdk_directory.append (1, '/');
+ m_sdk_directory.append (sdk_dirname);
+ return m_sdk_directory.c_str();
+ }
+ }
+ // Assign a single NULL character so we know we tried to find the device
+ // support directory and we don't keep trying to find it over and over.
+ m_sdk_directory.assign (1, '\0');
+ }
+
+ // We should have put a single NULL character into m_sdk_directory
+ // or it should have a valid path if the code gets here
+ assert (m_sdk_directory.empty() == false);
+ if (m_sdk_directory[0])
+ return m_sdk_directory.c_str();
+ return NULL;
+}
+
+Error
+PlatformAppleTVSimulator::GetSymbolFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ Error error;
+ char platform_file_path[PATH_MAX];
+ if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
+ {
+ char resolved_path[PATH_MAX];
+
+ const char * sdk_dir = GetSDKDirectoryAsCString();
+ if (sdk_dir)
+ {
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/%s",
+ sdk_dir,
+ platform_file_path);
+
+ // First try in the SDK and see if the file is in there
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return error;
+
+ // Else fall back to the actual path itself
+ local_file.SetFile(platform_file_path, true);
+ if (local_file.Exists())
+ return error;
+
+ }
+ error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'",
+ platform_file_path,
+ GetPluginName().GetCString());
+ }
+ else
+ {
+ error.SetErrorString ("invalid platform file argument");
+ }
+ return error;
+}
+
+Error
+PlatformAppleTVSimulator::GetSharedModule (const ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ // For AppleTV, the SDK files are all cached locally on the host
+ // system. So first we ask for the file in the cached SDK,
+ // then we attempt to get a shared module for the right architecture
+ // with the right UUID.
+ Error error;
+ ModuleSpec platform_module_spec (module_spec);
+ const FileSpec &platform_file = module_spec.GetFileSpec();
+ error = GetSymbolFile (platform_file, module_spec.GetUUIDPtr(), platform_module_spec.GetFileSpec());
+ if (error.Success())
+ {
+ error = ResolveExecutable (platform_module_spec, module_sp, module_search_paths_ptr);
+ }
+ else
+ {
+ const bool always_create = false;
+ error = ModuleList::GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr,
+ always_create);
+
+ }
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(platform_file);
+
+ return error;
+}
+
+
+uint32_t
+PlatformAppleTVSimulator::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ ProcessInstanceInfoList all_osx_process_infos;
+ // First we get all OSX processes
+ const uint32_t n = Host::FindProcesses (match_info, all_osx_process_infos);
+
+ // Now we filter them down to only the TvOS triples
+ for (uint32_t i=0; i<n; ++i)
+ {
+ const ProcessInstanceInfo &proc_info = all_osx_process_infos.GetProcessInfoAtIndex(i);
+ if (proc_info.GetArchitecture().GetTriple().getOS() == llvm::Triple::TvOS) {
+ process_infos.Append(proc_info);
+ }
+ }
+ return process_infos.GetSize();
+}
+
+bool
+PlatformAppleTVSimulator::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ static const ArchSpec platform_arch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
+
+ if (idx == 0)
+ {
+ arch = platform_arch;
+ if (arch.IsValid())
+ {
+ arch.GetTriple().setOS (llvm::Triple::TvOS);
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h b/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h
new file mode 100644
index 000000000000..0990f0729203
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h
@@ -0,0 +1,121 @@
+//===-- PlatformAppleTVSimulator.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_PlatformAppleTVSimulator_h_
+#define liblldb_PlatformAppleTVSimulator_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "PlatformDarwin.h"
+
+class PlatformAppleTVSimulator : public PlatformDarwin
+{
+public:
+
+ //------------------------------------------------------------
+ // Class Functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ static const char *
+ GetDescriptionStatic();
+
+ //------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------
+ PlatformAppleTVSimulator ();
+
+ virtual
+ ~PlatformAppleTVSimulator();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override
+ {
+ return GetPluginNameStatic();
+ }
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ lldb_private::Error
+ ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr) override;
+
+ const char *
+ GetDescription () override
+ {
+ return GetDescriptionStatic();
+ }
+
+ void
+ GetStatus (lldb_private::Stream &strm) override;
+
+ virtual lldb_private::Error
+ GetSymbolFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ uint32_t
+ FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos) override;
+
+ bool
+ GetSupportedArchitectureAtIndex (uint32_t idx,
+ lldb_private::ArchSpec &arch) override;
+
+ void
+ AddClangModuleCompilationOptions (lldb_private::Target *target, std::vector<std::string> &options) override
+ {
+ return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(target, options, PlatformDarwin::SDKType::iPhoneSimulator);
+ }
+
+protected:
+ std::string m_sdk_directory;
+ std::string m_build_update;
+
+ const char *
+ GetSDKDirectoryAsCString();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformAppleTVSimulator);
+
+};
+
+
+#endif // liblldb_PlatformAppleTVSimulator_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp
new file mode 100644
index 000000000000..ea8e789b2920
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp
@@ -0,0 +1,466 @@
+//===-- PlatformAppleWatchSimulator.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformAppleWatchSimulator.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+// Static Variables
+//------------------------------------------------------------------
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+void
+PlatformAppleWatchSimulator::Initialize ()
+{
+ PlatformDarwin::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+ PluginManager::RegisterPlugin (PlatformAppleWatchSimulator::GetPluginNameStatic(),
+ PlatformAppleWatchSimulator::GetDescriptionStatic(),
+ PlatformAppleWatchSimulator::CreateInstance);
+ }
+}
+
+void
+PlatformAppleWatchSimulator::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformAppleWatchSimulator::CreateInstance);
+ }
+ }
+
+ PlatformDarwin::Terminate ();
+}
+
+PlatformSP
+PlatformAppleWatchSimulator::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformAppleWatchSimulator::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ switch (arch->GetMachine())
+ {
+ case llvm::Triple::x86_64:
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::Apple:
+ create = true;
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the vendor if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::WatchOS:
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the OS if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformAppleWatchSimulator::%s() creating platform", __FUNCTION__);
+
+ return PlatformSP(new PlatformAppleWatchSimulator ());
+ }
+
+ if (log)
+ log->Printf ("PlatformAppleWatchSimulator::%s() aborting creation of platform", __FUNCTION__);
+
+ return PlatformSP();
+}
+
+
+lldb_private::ConstString
+PlatformAppleWatchSimulator::GetPluginNameStatic ()
+{
+ static ConstString g_name("watchos-simulator");
+ return g_name;
+}
+
+const char *
+PlatformAppleWatchSimulator::GetDescriptionStatic()
+{
+ return "Apple Watch simulator platform plug-in.";
+}
+
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformAppleWatchSimulator::PlatformAppleWatchSimulator () :
+ PlatformDarwin (true),
+ m_sdk_directory ()
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformAppleWatchSimulator::~PlatformAppleWatchSimulator()
+{
+}
+
+
+void
+PlatformAppleWatchSimulator::GetStatus (Stream &strm)
+{
+ Platform::GetStatus (strm);
+ const char *sdk_directory = GetSDKDirectoryAsCString();
+ if (sdk_directory)
+ strm.Printf (" SDK Path: \"%s\"\n", sdk_directory);
+ else
+ strm.PutCString (" SDK Path: error: unable to locate SDK\n");
+}
+
+
+Error
+PlatformAppleWatchSimulator::ResolveExecutable (const ModuleSpec &module_spec,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ ModuleSpec resolved_module_spec(module_spec);
+
+ // If we have "ls" as the exe_file, resolve the executable loation based on
+ // the current path variables
+ // TODO: resolve bare executables in the Platform SDK
+// if (!resolved_exe_file.Exists())
+// resolved_exe_file.ResolveExecutableLocation ();
+
+ // Resolve any executable within a bundle on MacOSX
+ // TODO: verify that this handles shallow bundles, if not then implement one ourselves
+ Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ {
+ if (resolved_module_spec.GetArchitecture().IsValid())
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ return error;
+ exe_module_sp.reset();
+ }
+ // No valid architecture was specified or the exact ARM slice wasn't
+ // found so ask the platform for the architectures that we should be
+ // using (in the correct order) and see if we can find a match that way
+ StreamString arch_names;
+ ArchSpec platform_arch;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
+ {
+ // Only match x86 with x86 and x86_64 with x86_64...
+ if (!module_spec.GetArchitecture().IsValid() || module_spec.GetArchitecture().GetCore() == resolved_module_spec.GetArchitecture().GetCore())
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (platform_arch.GetArchitectureName());
+ }
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ if (resolved_module_spec.GetFileSpec().Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("'%s' does not exist",
+ module_spec.GetFileSpec().GetPath().c_str());
+ }
+
+ return error;
+}
+
+static FileSpec::EnumerateDirectoryResult
+EnumerateDirectoryCallback (void *baton, FileSpec::FileType file_type, const FileSpec &file_spec)
+{
+ if (file_type == FileSpec::eFileTypeDirectory)
+ {
+ const char *filename = file_spec.GetFilename().GetCString();
+ if (filename && strncmp(filename, "AppleWatchSimulator", strlen ("AppleWatchSimulator")) == 0)
+ {
+ ::snprintf ((char *)baton, PATH_MAX, "%s", filename);
+ return FileSpec::eEnumerateDirectoryResultQuit;
+ }
+ }
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+
+
+const char *
+PlatformAppleWatchSimulator::GetSDKDirectoryAsCString()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_sdk_directory.empty())
+ {
+ const char *developer_dir = GetDeveloperDirectory();
+ if (developer_dir)
+ {
+ char sdks_directory[PATH_MAX];
+ char sdk_dirname[PATH_MAX];
+ sdk_dirname[0] = '\0';
+ snprintf (sdks_directory,
+ sizeof(sdks_directory),
+ "%s/Platforms/AppleWatchSimulator.platform/Developer/SDKs",
+ developer_dir);
+ FileSpec simulator_sdk_spec;
+ bool find_directories = true;
+ bool find_files = false;
+ bool find_other = false;
+ FileSpec::EnumerateDirectory (sdks_directory,
+ find_directories,
+ find_files,
+ find_other,
+ EnumerateDirectoryCallback,
+ sdk_dirname);
+
+ if (sdk_dirname[0])
+ {
+ m_sdk_directory = sdks_directory;
+ m_sdk_directory.append (1, '/');
+ m_sdk_directory.append (sdk_dirname);
+ return m_sdk_directory.c_str();
+ }
+ }
+ // Assign a single NULL character so we know we tried to find the device
+ // support directory and we don't keep trying to find it over and over.
+ m_sdk_directory.assign (1, '\0');
+ }
+
+ // We should have put a single NULL character into m_sdk_directory
+ // or it should have a valid path if the code gets here
+ assert (m_sdk_directory.empty() == false);
+ if (m_sdk_directory[0])
+ return m_sdk_directory.c_str();
+ return NULL;
+}
+
+Error
+PlatformAppleWatchSimulator::GetSymbolFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ Error error;
+ char platform_file_path[PATH_MAX];
+ if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
+ {
+ char resolved_path[PATH_MAX];
+
+ const char * sdk_dir = GetSDKDirectoryAsCString();
+ if (sdk_dir)
+ {
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/%s",
+ sdk_dir,
+ platform_file_path);
+
+ // First try in the SDK and see if the file is in there
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return error;
+
+ // Else fall back to the actual path itself
+ local_file.SetFile(platform_file_path, true);
+ if (local_file.Exists())
+ return error;
+
+ }
+ error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'",
+ platform_file_path,
+ GetPluginName().GetCString());
+ }
+ else
+ {
+ error.SetErrorString ("invalid platform file argument");
+ }
+ return error;
+}
+
+Error
+PlatformAppleWatchSimulator::GetSharedModule (const ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ // For AppleWatch, the SDK files are all cached locally on the host
+ // system. So first we ask for the file in the cached SDK,
+ // then we attempt to get a shared module for the right architecture
+ // with the right UUID.
+ Error error;
+ ModuleSpec platform_module_spec (module_spec);
+ const FileSpec &platform_file = module_spec.GetFileSpec();
+ error = GetSymbolFile (platform_file, module_spec.GetUUIDPtr(), platform_module_spec.GetFileSpec());
+ if (error.Success())
+ {
+ error = ResolveExecutable (platform_module_spec, module_sp, module_search_paths_ptr);
+ }
+ else
+ {
+ const bool always_create = false;
+ error = ModuleList::GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr,
+ always_create);
+
+ }
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(platform_file);
+
+ return error;
+}
+
+
+uint32_t
+PlatformAppleWatchSimulator::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ ProcessInstanceInfoList all_osx_process_infos;
+ // First we get all OSX processes
+ const uint32_t n = Host::FindProcesses (match_info, all_osx_process_infos);
+
+ // Now we filter them down to only the WatchOS triples
+ for (uint32_t i=0; i<n; ++i)
+ {
+ const ProcessInstanceInfo &proc_info = all_osx_process_infos.GetProcessInfoAtIndex(i);
+ if (proc_info.GetArchitecture().GetTriple().getOS() == llvm::Triple::WatchOS) {
+ process_infos.Append(proc_info);
+ }
+ }
+ return process_infos.GetSize();
+}
+
+bool
+PlatformAppleWatchSimulator::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ static const ArchSpec platform_arch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
+
+ if (idx == 0)
+ {
+ arch = platform_arch;
+ if (arch.IsValid())
+ {
+ arch.GetTriple().setOS (llvm::Triple::WatchOS);
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h b/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h
new file mode 100644
index 000000000000..8bcc0d4784fc
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h
@@ -0,0 +1,120 @@
+//===-- PlatformAppleWatchSimulator.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_PlatformAppleWatchSimulator_h_
+#define liblldb_PlatformAppleWatchSimulator_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "PlatformDarwin.h"
+
+class PlatformAppleWatchSimulator : public PlatformDarwin
+{
+public:
+
+ //------------------------------------------------------------
+ // Class Functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ static const char *
+ GetDescriptionStatic();
+
+ //------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------
+ PlatformAppleWatchSimulator ();
+
+ virtual
+ ~PlatformAppleWatchSimulator();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override
+ {
+ return GetPluginNameStatic();
+ }
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ lldb_private::Error
+ ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr) override;
+
+ const char *
+ GetDescription () override
+ {
+ return GetDescriptionStatic();
+ }
+
+ void
+ GetStatus (lldb_private::Stream &strm) override;
+
+ virtual lldb_private::Error
+ GetSymbolFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ uint32_t
+ FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos) override;
+
+ bool
+ GetSupportedArchitectureAtIndex (uint32_t idx,
+ lldb_private::ArchSpec &arch) override;
+
+ void
+ AddClangModuleCompilationOptions (lldb_private::Target *target, std::vector<std::string> &options) override
+ {
+ return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(target, options, PlatformDarwin::SDKType::iPhoneSimulator);
+ }
+
+protected:
+ std::string m_sdk_directory;
+ std::string m_build_update;
+
+ const char *
+ GetSDKDirectoryAsCString();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformAppleWatchSimulator);
+
+};
+
+#endif // liblldb_PlatformAppleWatchSimulator_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
new file mode 100644
index 000000000000..fb38630710a1
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -0,0 +1,1705 @@
+//===-- PlatformDarwin.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformDarwin.h"
+
+// C Includes
+#include <string.h>
+
+// C++ Includes
+#include <algorithm>
+#include <mutex>
+
+// Other libraries and framework includes
+#include "clang/Basic/VersionTuple.h"
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/XML.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "llvm/ADT/STLExtras.h"
+
+#if defined (__APPLE__)
+#include <TargetConditionals.h> // for TARGET_OS_TV, TARGET_OS_WATCH
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformDarwin::PlatformDarwin (bool is_host) :
+ PlatformPOSIX(is_host), // This is the local host platform
+ m_developer_directory ()
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformDarwin::~PlatformDarwin()
+{
+}
+
+FileSpecList
+PlatformDarwin::LocateExecutableScriptingResources (Target *target,
+ Module &module,
+ Stream* feedback_stream)
+{
+ FileSpecList file_list;
+ if (target && target->GetDebugger().GetScriptLanguage() == eScriptLanguagePython)
+ {
+ // NB some extensions might be meaningful and should not be stripped - "this.binary.file"
+ // should not lose ".file" but GetFileNameStrippingExtension() will do precisely that.
+ // Ideally, we should have a per-platform list of extensions (".exe", ".app", ".dSYM", ".framework")
+ // which should be stripped while leaving "this.binary.file" as-is.
+ ScriptInterpreter *script_interpreter = target->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+
+ FileSpec module_spec = module.GetFileSpec();
+
+ if (module_spec)
+ {
+ SymbolVendor *symbols = module.GetSymbolVendor ();
+ if (symbols)
+ {
+ SymbolFile *symfile = symbols->GetSymbolFile();
+ if (symfile)
+ {
+ ObjectFile *objfile = symfile->GetObjectFile();
+ if (objfile)
+ {
+ FileSpec symfile_spec (objfile->GetFileSpec());
+ if (symfile_spec && symfile_spec.Exists())
+ {
+ while (module_spec.GetFilename())
+ {
+ std::string module_basename (module_spec.GetFilename().GetCString());
+ std::string original_module_basename (module_basename);
+
+ bool was_keyword = false;
+
+ // FIXME: for Python, we cannot allow certain characters in module
+ // filenames we import. Theoretically, different scripting languages may
+ // have different sets of forbidden tokens in filenames, and that should
+ // be dealt with by each ScriptInterpreter. For now, we just replace dots
+ // with underscores, but if we ever support anything other than Python
+ // we will need to rework this
+ std::replace(module_basename.begin(), module_basename.end(), '.', '_');
+ std::replace(module_basename.begin(), module_basename.end(), ' ', '_');
+ std::replace(module_basename.begin(), module_basename.end(), '-', '_');
+ if (script_interpreter && script_interpreter->IsReservedWord(module_basename.c_str()))
+ {
+ module_basename.insert(module_basename.begin(), '_');
+ was_keyword = true;
+ }
+
+ StreamString path_string;
+ StreamString original_path_string;
+ // for OSX we are going to be in .dSYM/Contents/Resources/DWARF/<basename>
+ // let us go to .dSYM/Contents/Resources/Python/<basename>.py and see if the file exists
+ path_string.Printf("%s/../Python/%s.py",symfile_spec.GetDirectory().GetCString(), module_basename.c_str());
+ original_path_string.Printf("%s/../Python/%s.py",symfile_spec.GetDirectory().GetCString(), original_module_basename.c_str());
+ FileSpec script_fspec(path_string.GetData(), true);
+ FileSpec orig_script_fspec(original_path_string.GetData(), true);
+
+ // if we did some replacements of reserved characters, and a file with the untampered name
+ // exists, then warn the user that the file as-is shall not be loaded
+ if (feedback_stream)
+ {
+ if (module_basename != original_module_basename
+ && orig_script_fspec.Exists())
+ {
+ const char* reason_for_complaint = was_keyword ? "conflicts with a keyword" : "contains reserved characters";
+ if (script_fspec.Exists())
+ feedback_stream->Printf("warning: the symbol file '%s' contains a debug script. However, its name"
+ " '%s' %s and as such cannot be loaded. LLDB will"
+ " load '%s' instead. Consider removing the file with the malformed name to"
+ " eliminate this warning.\n",
+ symfile_spec.GetPath().c_str(),
+ original_path_string.GetData(),
+ reason_for_complaint,
+ path_string.GetData());
+ else
+ feedback_stream->Printf("warning: the symbol file '%s' contains a debug script. However, its name"
+ " %s and as such cannot be loaded. If you intend"
+ " to have this script loaded, please rename '%s' to '%s' and retry.\n",
+ symfile_spec.GetPath().c_str(),
+ reason_for_complaint,
+ original_path_string.GetData(),
+ path_string.GetData());
+ }
+ }
+
+ if (script_fspec.Exists())
+ {
+ file_list.Append (script_fspec);
+ break;
+ }
+
+ // If we didn't find the python file, then keep
+ // stripping the extensions and try again
+ ConstString filename_no_extension (module_spec.GetFileNameStrippingExtension());
+ if (module_spec.GetFilename() == filename_no_extension)
+ break;
+
+ module_spec.GetFilename() = filename_no_extension;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return file_list;
+}
+
+Error
+PlatformDarwin::ResolveExecutable (const ModuleSpec &module_spec,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ char exe_path[PATH_MAX];
+ ModuleSpec resolved_module_spec(module_spec);
+
+ if (IsHost())
+ {
+ // If we have "ls" as the exe_file, resolve the executable loation based on
+ // the current path variables
+ if (!resolved_module_spec.GetFileSpec().Exists())
+ {
+ module_spec.GetFileSpec().GetPath (exe_path, sizeof(exe_path));
+ resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
+ }
+
+ if (!resolved_module_spec.GetFileSpec().Exists())
+ resolved_module_spec.GetFileSpec().ResolveExecutableLocation ();
+
+ // Resolve any executable within a bundle on MacOSX
+ Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ error.Clear();
+ else
+ {
+ const uint32_t permissions = resolved_module_spec.GetFileSpec().GetPermissions();
+ if (permissions && (permissions & eFilePermissionsEveryoneR) == 0)
+ error.SetErrorStringWithFormat ("executable '%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ else
+ error.SetErrorStringWithFormat ("unable to find executable for '%s'", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ {
+ error = GetCachedExecutable (resolved_module_spec, exe_module_sp, module_search_paths_ptr, *m_remote_platform_sp);
+ }
+ else
+ {
+ // We may connect to a process and use the provided executable (Don't use local $PATH).
+
+ // Resolve any executable within a bundle on MacOSX
+ Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ error.Clear();
+ else
+ error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", resolved_module_spec.GetFileSpec().GetFilename().AsCString(""));
+ }
+ }
+
+
+ if (error.Success())
+ {
+ if (resolved_module_spec.GetArchitecture().IsValid())
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ module_search_paths_ptr,
+ NULL,
+ NULL);
+
+ if (error.Fail() || exe_module_sp.get() == NULL || exe_module_sp->GetObjectFile() == NULL)
+ {
+ exe_module_sp.reset();
+ error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+ }
+ else
+ {
+ // No valid architecture was specified, ask the platform for
+ // the architectures that we should be using (in the correct order)
+ // and see if we can find a match that way
+ StreamString arch_names;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
+ {
+ error = GetSharedModule (resolved_module_spec,
+ NULL,
+ exe_module_sp,
+ module_search_paths_ptr,
+ NULL,
+ NULL);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ if (resolved_module_spec.GetFileSpec().Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
+Error
+PlatformDarwin::ResolveSymbolFile (Target &target,
+ const ModuleSpec &sym_spec,
+ FileSpec &sym_file)
+{
+ Error error;
+ sym_file = sym_spec.GetSymbolFileSpec();
+ if (sym_file.Exists())
+ {
+ if (sym_file.GetFileType() == FileSpec::eFileTypeDirectory)
+ {
+ sym_file = Symbols::FindSymbolFileInBundle (sym_file,
+ sym_spec.GetUUIDPtr(),
+ sym_spec.GetArchitecturePtr());
+ }
+ }
+ else
+ {
+ if (sym_spec.GetUUID().IsValid())
+ {
+
+ }
+ }
+ return error;
+
+}
+
+static lldb_private::Error
+MakeCacheFolderForFile (const FileSpec& module_cache_spec)
+{
+ FileSpec module_cache_folder = module_cache_spec.CopyByRemovingLastPathComponent();
+ return FileSystem::MakeDirectory(module_cache_folder, eFilePermissionsDirectoryDefault);
+}
+
+static lldb_private::Error
+BringInRemoteFile (Platform* platform,
+ const lldb_private::ModuleSpec &module_spec,
+ const FileSpec& module_cache_spec)
+{
+ MakeCacheFolderForFile(module_cache_spec);
+ Error err = platform->GetFile(module_spec.GetFileSpec(), module_cache_spec);
+ return err;
+}
+
+lldb_private::Error
+PlatformDarwin::GetSharedModuleWithLocalCache (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[%s] Trying to find module %s/%s - platform path %s/%s symbol path %s/%s",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString(),
+ module_spec.GetPlatformFileSpec().GetDirectory().AsCString(),
+ module_spec.GetPlatformFileSpec().GetFilename().AsCString(),
+ module_spec.GetSymbolFileSpec().GetDirectory().AsCString(),
+ module_spec.GetSymbolFileSpec().GetFilename().AsCString());
+
+ Error err;
+
+ err = ModuleList::GetSharedModule(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
+ if (module_sp)
+ return err;
+
+ if (!IsHost())
+ {
+ std::string cache_path(GetLocalCacheDirectory());
+ // Only search for a locally cached file if we have a valid cache path
+ if (!cache_path.empty())
+ {
+ std::string module_path (module_spec.GetFileSpec().GetPath());
+ cache_path.append(module_path);
+ FileSpec module_cache_spec(cache_path.c_str(),false);
+
+ // if rsync is supported, always bring in the file - rsync will be very efficient
+ // when files are the same on the local and remote end of the connection
+ if (this->GetSupportsRSync())
+ {
+ err = BringInRemoteFile (this, module_spec, module_cache_spec);
+ if (err.Fail())
+ return err;
+ if (module_cache_spec.Exists())
+ {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[%s] module %s/%s was rsynced and is now there",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString());
+ ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
+ module_sp.reset(new Module(local_spec));
+ module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+ return Error();
+ }
+ }
+
+ // try to find the module in the cache
+ if (module_cache_spec.Exists())
+ {
+ // get the local and remote MD5 and compare
+ if (m_remote_platform_sp)
+ {
+ // when going over the *slow* GDB remote transfer mechanism we first check
+ // the hashes of the files - and only do the actual transfer if they differ
+ uint64_t high_local,high_remote,low_local,low_remote;
+ FileSystem::CalculateMD5(module_cache_spec, low_local, high_local);
+ m_remote_platform_sp->CalculateMD5(module_spec.GetFileSpec(), low_remote, high_remote);
+ if (low_local != low_remote || high_local != high_remote)
+ {
+ // bring in the remote file
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[%s] module %s/%s needs to be replaced from remote copy",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString());
+ Error err = BringInRemoteFile (this, module_spec, module_cache_spec);
+ if (err.Fail())
+ return err;
+ }
+ }
+
+ ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
+ module_sp.reset(new Module(local_spec));
+ module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[%s] module %s/%s was found in the cache",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString());
+ return Error();
+ }
+
+ // bring in the remote module file
+ if (log)
+ log->Printf("[%s] module %s/%s needs to come in remotely",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString());
+ Error err = BringInRemoteFile (this, module_spec, module_cache_spec);
+ if (err.Fail())
+ return err;
+ if (module_cache_spec.Exists())
+ {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("[%s] module %s/%s is now cached and fine",
+ (IsHost() ? "host" : "remote"),
+ module_spec.GetFileSpec().GetDirectory().AsCString(),
+ module_spec.GetFileSpec().GetFilename().AsCString());
+ ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
+ module_sp.reset(new Module(local_spec));
+ module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+ return Error();
+ }
+ else
+ return Error("unable to obtain valid module file");
+ }
+ else
+ return Error("no cache path");
+ }
+ else
+ return Error ("unable to resolve module");
+}
+
+Error
+PlatformDarwin::GetSharedModule (const ModuleSpec &module_spec,
+ Process* process,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ Error error;
+ module_sp.reset();
+
+ if (IsRemote())
+ {
+ // If we have a remote platform always, let it try and locate
+ // the shared module first.
+ if (m_remote_platform_sp)
+ {
+ error = m_remote_platform_sp->GetSharedModule (module_spec,
+ process,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr);
+ }
+ }
+
+ if (!module_sp)
+ {
+ // Fall back to the local platform and find the file locally
+ error = Platform::GetSharedModule (module_spec,
+ process,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr);
+
+ const FileSpec &platform_file = module_spec.GetFileSpec();
+ if (!module_sp && module_search_paths_ptr && platform_file)
+ {
+ // We can try to pull off part of the file path up to the bundle
+ // directory level and try any module search paths...
+ FileSpec bundle_directory;
+ if (Host::GetBundleDirectory (platform_file, bundle_directory))
+ {
+ if (platform_file == bundle_directory)
+ {
+ ModuleSpec new_module_spec (module_spec);
+ new_module_spec.GetFileSpec() = bundle_directory;
+ if (Host::ResolveExecutableInBundle (new_module_spec.GetFileSpec()))
+ {
+ Error new_error (Platform::GetSharedModule (new_module_spec,
+ process,
+ module_sp,
+ NULL,
+ old_module_sp_ptr,
+ did_create_ptr));
+
+ if (module_sp)
+ return new_error;
+ }
+ }
+ else
+ {
+ char platform_path[PATH_MAX];
+ char bundle_dir[PATH_MAX];
+ platform_file.GetPath (platform_path, sizeof(platform_path));
+ const size_t bundle_directory_len = bundle_directory.GetPath (bundle_dir, sizeof(bundle_dir));
+ char new_path[PATH_MAX];
+ size_t num_module_search_paths = module_search_paths_ptr->GetSize();
+ for (size_t i=0; i<num_module_search_paths; ++i)
+ {
+ const size_t search_path_len = module_search_paths_ptr->GetFileSpecAtIndex(i).GetPath(new_path, sizeof(new_path));
+ if (search_path_len < sizeof(new_path))
+ {
+ snprintf (new_path + search_path_len, sizeof(new_path) - search_path_len, "/%s", platform_path + bundle_directory_len);
+ FileSpec new_file_spec (new_path, false);
+ if (new_file_spec.Exists())
+ {
+ ModuleSpec new_module_spec (module_spec);
+ new_module_spec.GetFileSpec() = new_file_spec;
+ Error new_error (Platform::GetSharedModule (new_module_spec,
+ process,
+ module_sp,
+ NULL,
+ old_module_sp_ptr,
+ did_create_ptr));
+
+ if (module_sp)
+ {
+ module_sp->SetPlatformFileSpec(new_file_spec);
+ return new_error;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+ return error;
+}
+
+size_t
+PlatformDarwin::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
+{
+ const uint8_t *trap_opcode = NULL;
+ uint32_t trap_opcode_size = 0;
+ bool bp_is_thumb = false;
+
+ llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine();
+ switch (machine)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ {
+ static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
+ trap_opcode = g_i386_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
+ }
+ break;
+
+ case llvm::Triple::aarch64:
+ {
+ // TODO: fix this with actual darwin breakpoint opcode for arm64.
+ // right now debugging uses the Z packets with GDB remote so this
+ // is not needed, but the size needs to be correct...
+ static const uint8_t g_arm64_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+ trap_opcode = g_arm64_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_arm64_breakpoint_opcode);
+ }
+ break;
+
+ case llvm::Triple::thumb:
+ bp_is_thumb = true; // Fall through...
+ case llvm::Triple::arm:
+ {
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 };
+ static const uint8_t g_thumb_breakpooint_opcode[] = { 0xFE, 0xDE };
+
+ // Auto detect arm/thumb if it wasn't explicitly specified
+ if (!bp_is_thumb)
+ {
+ lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0));
+ if (bp_loc_sp)
+ bp_is_thumb = bp_loc_sp->GetAddress().GetAddressClass () == eAddressClassCodeAlternateISA;
+ }
+ if (bp_is_thumb)
+ {
+ trap_opcode = g_thumb_breakpooint_opcode;
+ trap_opcode_size = sizeof(g_thumb_breakpooint_opcode);
+ break;
+ }
+ trap_opcode = g_arm_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ {
+ static const uint8_t g_ppc_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 };
+ trap_opcode = g_ppc_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_ppc_breakpoint_opcode);
+ }
+ break;
+
+ default:
+ assert(!"Unhandled architecture in PlatformDarwin::GetSoftwareBreakpointTrapOpcode()");
+ break;
+ }
+
+ if (trap_opcode && trap_opcode_size)
+ {
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+ }
+ return 0;
+
+}
+
+bool
+PlatformDarwin::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ bool success = false;
+ if (IsHost())
+ {
+ success = Platform::GetProcessInfo (pid, process_info);
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
+ }
+ return success;
+}
+
+uint32_t
+PlatformDarwin::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ uint32_t match_count = 0;
+ if (IsHost())
+ {
+ // Let the base class figure out the host details
+ match_count = Platform::FindProcesses (match_info, process_infos);
+ }
+ else
+ {
+ // If we are remote, we can only return results if we are connected
+ if (m_remote_platform_sp)
+ match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos);
+ }
+ return match_count;
+}
+
+bool
+PlatformDarwin::ModuleIsExcludedForUnconstrainedSearches (lldb_private::Target &target, const lldb::ModuleSP &module_sp)
+{
+ if (!module_sp)
+ return false;
+
+ ObjectFile *obj_file = module_sp->GetObjectFile();
+ if (!obj_file)
+ return false;
+
+ ObjectFile::Type obj_type = obj_file->GetType();
+ if (obj_type == ObjectFile::eTypeDynamicLinker)
+ return true;
+ else
+ return false;
+}
+
+bool
+PlatformDarwin::x86GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ ArchSpec host_arch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
+ if (host_arch.GetCore() == ArchSpec::eCore_x86_64_x86_64h)
+ {
+ switch (idx)
+ {
+ case 0:
+ arch = host_arch;
+ return true;
+
+ case 1:
+ arch.SetTriple("x86_64-apple-macosx");
+ return true;
+
+ case 2:
+ arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
+ return true;
+
+ default: return false;
+ }
+ }
+ else
+ {
+ if (idx == 0)
+ {
+ arch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
+ return arch.IsValid();
+ }
+ else if (idx == 1)
+ {
+ ArchSpec platform_arch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
+ ArchSpec platform_arch64(HostInfo::GetArchitecture(HostInfo::eArchKind64));
+ if (platform_arch.IsExactMatch(platform_arch64))
+ {
+ // This macosx platform supports both 32 and 64 bit. Since we already
+ // returned the 64 bit arch for idx == 0, return the 32 bit arch
+ // for idx == 1
+ arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
+ return arch.IsValid();
+ }
+ }
+ }
+ return false;
+}
+
+// The architecture selection rules for arm processors
+// These cpu subtypes have distinct names (e.g. armv7f) but armv7 binaries run fine on an armv7f processor.
+
+bool
+PlatformDarwin::ARMGetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ ArchSpec system_arch (GetSystemArchitecture());
+
+ // When lldb is running on a watch or tv, set the arch OS name appropriately.
+#if defined (TARGET_OS_TV) && TARGET_OS_TV == 1
+#define OSNAME "tvos"
+#elif defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
+#define OSNAME "watchos"
+#else
+#define OSNAME "ios"
+#endif
+
+ const ArchSpec::Core system_core = system_arch.GetCore();
+ switch (system_core)
+ {
+ default:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("arm64-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv7-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("armv7f-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("armv7k-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("armv7s-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("armv7m-apple-" OSNAME); return true;
+ case 6: arch.SetTriple ("armv7em-apple-" OSNAME); return true;
+ case 7: arch.SetTriple ("armv6m-apple-" OSNAME); return true;
+ case 8: arch.SetTriple ("armv6-apple-" OSNAME); return true;
+ case 9: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 10: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 11: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 12: arch.SetTriple ("thumbv7-apple-" OSNAME); return true;
+ case 13: arch.SetTriple ("thumbv7f-apple-" OSNAME); return true;
+ case 14: arch.SetTriple ("thumbv7k-apple-" OSNAME); return true;
+ case 15: arch.SetTriple ("thumbv7s-apple-" OSNAME); return true;
+ case 16: arch.SetTriple ("thumbv7m-apple-" OSNAME); return true;
+ case 17: arch.SetTriple ("thumbv7em-apple-" OSNAME); return true;
+ case 18: arch.SetTriple ("thumbv6m-apple-" OSNAME); return true;
+ case 19: arch.SetTriple ("thumbv6-apple-" OSNAME); return true;
+ case 20: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 21: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 22: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_arm64:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("arm64-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv7s-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("armv7f-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("armv7m-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("armv7em-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("armv7-apple-" OSNAME); return true;
+ case 6: arch.SetTriple ("armv6m-apple-" OSNAME); return true;
+ case 7: arch.SetTriple ("armv6-apple-" OSNAME); return true;
+ case 8: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 9: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 10: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 11: arch.SetTriple ("thumbv7-apple-" OSNAME); return true;
+ case 12: arch.SetTriple ("thumbv7f-apple-" OSNAME); return true;
+ case 13: arch.SetTriple ("thumbv7k-apple-" OSNAME); return true;
+ case 14: arch.SetTriple ("thumbv7s-apple-" OSNAME); return true;
+ case 15: arch.SetTriple ("thumbv7m-apple-" OSNAME); return true;
+ case 16: arch.SetTriple ("thumbv7em-apple-" OSNAME); return true;
+ case 17: arch.SetTriple ("thumbv6m-apple-" OSNAME); return true;
+ case 18: arch.SetTriple ("thumbv6-apple-" OSNAME); return true;
+ case 19: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 20: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 21: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7f:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7f-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv7-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("armv6m-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("armv6-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 6: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 7: arch.SetTriple ("thumbv7f-apple-" OSNAME); return true;
+ case 8: arch.SetTriple ("thumbv7-apple-" OSNAME); return true;
+ case 9: arch.SetTriple ("thumbv6m-apple-" OSNAME); return true;
+ case 10: arch.SetTriple ("thumbv6-apple-" OSNAME); return true;
+ case 11: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 12: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 13: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7k:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7k-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv7-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("armv6m-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("armv6-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 6: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 7: arch.SetTriple ("thumbv7k-apple-" OSNAME); return true;
+ case 8: arch.SetTriple ("thumbv7-apple-" OSNAME); return true;
+ case 9: arch.SetTriple ("thumbv6m-apple-" OSNAME); return true;
+ case 10: arch.SetTriple ("thumbv6-apple-" OSNAME); return true;
+ case 11: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 12: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 13: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7s:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7s-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv7-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("armv6m-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("armv6-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 6: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 7: arch.SetTriple ("thumbv7s-apple-" OSNAME); return true;
+ case 8: arch.SetTriple ("thumbv7-apple-" OSNAME); return true;
+ case 9: arch.SetTriple ("thumbv6m-apple-" OSNAME); return true;
+ case 10: arch.SetTriple ("thumbv6-apple-" OSNAME); return true;
+ case 11: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 12: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 13: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7m:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7m-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv7-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("armv6m-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("armv6-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 6: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 7: arch.SetTriple ("thumbv7m-apple-" OSNAME); return true;
+ case 8: arch.SetTriple ("thumbv7-apple-" OSNAME); return true;
+ case 9: arch.SetTriple ("thumbv6m-apple-" OSNAME); return true;
+ case 10: arch.SetTriple ("thumbv6-apple-" OSNAME); return true;
+ case 11: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 12: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 13: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7em:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7em-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv7-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("armv6m-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("armv6-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 6: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 7: arch.SetTriple ("thumbv7em-apple-" OSNAME); return true;
+ case 8: arch.SetTriple ("thumbv7-apple-" OSNAME); return true;
+ case 9: arch.SetTriple ("thumbv6m-apple-" OSNAME); return true;
+ case 10: arch.SetTriple ("thumbv6-apple-" OSNAME); return true;
+ case 11: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 12: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 13: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv6m-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("armv6-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 6: arch.SetTriple ("thumbv7-apple-" OSNAME); return true;
+ case 7: arch.SetTriple ("thumbv6m-apple-" OSNAME); return true;
+ case 8: arch.SetTriple ("thumbv6-apple-" OSNAME); return true;
+ case 9: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 10: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 11: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv6m:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv6m-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv6-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("thumbv6m-apple-" OSNAME); return true;
+ case 6: arch.SetTriple ("thumbv6-apple-" OSNAME); return true;
+ case 7: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 8: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 9: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv6:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv6-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("thumbv6-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 6: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 7: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv5:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv5-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("thumbv5-apple-" OSNAME); return true;
+ case 4: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 5: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv4:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv4-apple-" OSNAME); return true;
+ case 1: arch.SetTriple ("arm-apple-" OSNAME); return true;
+ case 2: arch.SetTriple ("thumbv4t-apple-" OSNAME); return true;
+ case 3: arch.SetTriple ("thumb-apple-" OSNAME); return true;
+ default: break;
+ }
+ break;
+ }
+ arch.Clear();
+ return false;
+}
+
+
+const char *
+PlatformDarwin::GetDeveloperDirectory()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_developer_directory.empty())
+ {
+ bool developer_dir_path_valid = false;
+ char developer_dir_path[PATH_MAX];
+ FileSpec temp_file_spec;
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, temp_file_spec))
+ {
+ if (temp_file_spec.GetPath (developer_dir_path, sizeof(developer_dir_path)))
+ {
+ char *shared_frameworks = strstr (developer_dir_path, "/SharedFrameworks/LLDB.framework");
+ if (shared_frameworks)
+ {
+ ::snprintf (shared_frameworks,
+ sizeof(developer_dir_path) - (shared_frameworks - developer_dir_path),
+ "/Developer");
+ developer_dir_path_valid = true;
+ }
+ else
+ {
+ char *lib_priv_frameworks = strstr (developer_dir_path, "/Library/PrivateFrameworks/LLDB.framework");
+ if (lib_priv_frameworks)
+ {
+ *lib_priv_frameworks = '\0';
+ developer_dir_path_valid = true;
+ }
+ }
+ }
+ }
+
+ if (!developer_dir_path_valid)
+ {
+ std::string xcode_dir_path;
+ const char *xcode_select_prefix_dir = getenv ("XCODE_SELECT_PREFIX_DIR");
+ if (xcode_select_prefix_dir)
+ xcode_dir_path.append (xcode_select_prefix_dir);
+ xcode_dir_path.append ("/usr/share/xcode-select/xcode_dir_path");
+ temp_file_spec.SetFile(xcode_dir_path.c_str(), false);
+ size_t bytes_read = temp_file_spec.ReadFileContents(0, developer_dir_path, sizeof(developer_dir_path), NULL);
+ if (bytes_read > 0)
+ {
+ developer_dir_path[bytes_read] = '\0';
+ while (developer_dir_path[bytes_read-1] == '\r' ||
+ developer_dir_path[bytes_read-1] == '\n')
+ developer_dir_path[--bytes_read] = '\0';
+ developer_dir_path_valid = true;
+ }
+ }
+
+ if (!developer_dir_path_valid)
+ {
+ FileSpec xcode_select_cmd ("/usr/bin/xcode-select", false);
+ if (xcode_select_cmd.Exists())
+ {
+ int exit_status = -1;
+ int signo = -1;
+ std::string command_output;
+ Error error = Host::RunShellCommand ("/usr/bin/xcode-select --print-path",
+ NULL, // current working directory
+ &exit_status,
+ &signo,
+ &command_output,
+ 2, // short timeout
+ false); // don't run in a shell
+ if (error.Success() && exit_status == 0 && !command_output.empty())
+ {
+ const char *cmd_output_ptr = command_output.c_str();
+ developer_dir_path[sizeof (developer_dir_path) - 1] = '\0';
+ size_t i;
+ for (i = 0; i < sizeof (developer_dir_path) - 1; i++)
+ {
+ if (cmd_output_ptr[i] == '\r' || cmd_output_ptr[i] == '\n' || cmd_output_ptr[i] == '\0')
+ break;
+ developer_dir_path[i] = cmd_output_ptr[i];
+ }
+ developer_dir_path[i] = '\0';
+
+ FileSpec devel_dir (developer_dir_path, false);
+ if (devel_dir.Exists() && devel_dir.IsDirectory())
+ {
+ developer_dir_path_valid = true;
+ }
+ }
+ }
+ }
+
+ if (developer_dir_path_valid)
+ {
+ temp_file_spec.SetFile (developer_dir_path, false);
+ if (temp_file_spec.Exists())
+ {
+ m_developer_directory.assign (developer_dir_path);
+ return m_developer_directory.c_str();
+ }
+ }
+ // Assign a single NULL character so we know we tried to find the device
+ // support directory and we don't keep trying to find it over and over.
+ m_developer_directory.assign (1, '\0');
+ }
+
+ // We should have put a single NULL character into m_developer_directory
+ // or it should have a valid path if the code gets here
+ assert (m_developer_directory.empty() == false);
+ if (m_developer_directory[0])
+ return m_developer_directory.c_str();
+ return NULL;
+}
+
+
+BreakpointSP
+PlatformDarwin::SetThreadCreationBreakpoint (Target &target)
+{
+ BreakpointSP bp_sp;
+ static const char *g_bp_names[] =
+ {
+ "start_wqthread",
+ "_pthread_wqthread",
+ "_pthread_start",
+ };
+
+ static const char *g_bp_modules[] =
+ {
+ "libsystem_c.dylib",
+ "libSystem.B.dylib"
+ };
+
+ FileSpecList bp_modules;
+ for (size_t i = 0; i < llvm::array_lengthof(g_bp_modules); i++)
+ {
+ const char *bp_module = g_bp_modules[i];
+ bp_modules.Append(FileSpec(bp_module, false));
+ }
+
+ bool internal = true;
+ bool hardware = false;
+ LazyBool skip_prologue = eLazyBoolNo;
+ bp_sp = target.CreateBreakpoint (&bp_modules,
+ NULL,
+ g_bp_names,
+ llvm::array_lengthof(g_bp_names),
+ eFunctionNameTypeFull,
+ eLanguageTypeUnknown,
+ skip_prologue,
+ internal,
+ hardware);
+ bp_sp->SetBreakpointKind("thread-creation");
+
+ return bp_sp;
+}
+
+
+int32_t
+PlatformDarwin::GetResumeCountForLaunchInfo (ProcessLaunchInfo &launch_info)
+{
+ const FileSpec &shell = launch_info.GetShell();
+ if (!shell)
+ return 1;
+
+ std::string shell_string = shell.GetPath();
+ const char *shell_name = strrchr (shell_string.c_str(), '/');
+ if (shell_name == NULL)
+ shell_name = shell_string.c_str();
+ else
+ shell_name++;
+
+ if (strcmp (shell_name, "sh") == 0)
+ {
+ // /bin/sh re-exec's itself as /bin/bash requiring another resume.
+ // But it only does this if the COMMAND_MODE environment variable
+ // is set to "legacy".
+ const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector();
+ if (envp != NULL)
+ {
+ for (int i = 0; envp[i] != NULL; i++)
+ {
+ if (strcmp (envp[i], "COMMAND_MODE=legacy" ) == 0)
+ return 2;
+ }
+ }
+ return 1;
+ }
+ else if (strcmp (shell_name, "csh") == 0
+ || strcmp (shell_name, "tcsh") == 0
+ || strcmp (shell_name, "zsh") == 0)
+ {
+ // csh and tcsh always seem to re-exec themselves.
+ return 2;
+ }
+ else
+ return 1;
+}
+
+void
+PlatformDarwin::CalculateTrapHandlerSymbolNames ()
+{
+ m_trap_handlers.push_back (ConstString ("_sigtramp"));
+}
+
+
+static const char *const sdk_strings[] = {
+ "MacOSX",
+ "iPhoneSimulator",
+ "iPhoneOS",
+};
+
+static FileSpec
+CheckPathForXcode(const FileSpec &fspec)
+{
+ if (fspec.Exists())
+ {
+ const char substr[] = ".app/Contents/";
+
+ std::string path_to_shlib = fspec.GetPath();
+ size_t pos = path_to_shlib.rfind(substr);
+ if (pos != std::string::npos)
+ {
+ path_to_shlib.erase(pos + strlen(substr));
+ FileSpec ret (path_to_shlib.c_str(), false);
+
+ FileSpec xcode_binary_path = ret;
+ xcode_binary_path.AppendPathComponent("MacOS");
+ xcode_binary_path.AppendPathComponent("Xcode");
+
+ if (xcode_binary_path.Exists())
+ {
+ return ret;
+ }
+ }
+ }
+ return FileSpec();
+}
+
+static FileSpec
+GetXcodeContentsPath ()
+{
+ static FileSpec g_xcode_filespec;
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+
+
+ FileSpec fspec;
+
+ // First get the program file spec. If lldb.so or LLDB.framework is running
+ // in a program and that program is Xcode, the path returned with be the path
+ // to Xcode.app/Contents/MacOS/Xcode, so this will be the correct Xcode to use.
+ fspec = HostInfo::GetProgramFileSpec();
+
+ if (fspec)
+ {
+ // Ignore the current binary if it is python.
+ std::string basename_lower = fspec.GetFilename ().GetCString ();
+ std::transform(basename_lower.begin (), basename_lower.end (), basename_lower.begin (), tolower);
+ if (basename_lower != "python")
+ {
+ g_xcode_filespec = CheckPathForXcode(fspec);
+ }
+ }
+
+ // Next check DEVELOPER_DIR environment variable
+ if (!g_xcode_filespec)
+ {
+ const char *developer_dir_env_var = getenv("DEVELOPER_DIR");
+ if (developer_dir_env_var && developer_dir_env_var[0])
+ {
+ g_xcode_filespec = CheckPathForXcode(FileSpec(developer_dir_env_var, true));
+ }
+
+ // Fall back to using "xcrun" to find the selected Xcode
+ if (!g_xcode_filespec)
+ {
+ int status = 0;
+ int signo = 0;
+ std::string output;
+ const char *command = "/usr/bin/xcode-select -p";
+ lldb_private::Error error = Host::RunShellCommand (command, // shell command to run
+ NULL, // current working directory
+ &status, // Put the exit status of the process in here
+ &signo, // Put the signal that caused the process to exit in here
+ &output, // Get the output from the command and place it in this string
+ 3); // Timeout in seconds to wait for shell program to finish
+ if (status == 0 && !output.empty())
+ {
+ size_t first_non_newline = output.find_last_not_of("\r\n");
+ if (first_non_newline != std::string::npos)
+ {
+ output.erase(first_non_newline+1);
+ }
+ output.append("/..");
+
+ g_xcode_filespec = CheckPathForXcode(FileSpec(output.c_str(), false));
+ }
+ }
+ }
+ });
+
+ return g_xcode_filespec;
+}
+
+bool
+PlatformDarwin::SDKSupportsModules (SDKType sdk_type, uint32_t major, uint32_t minor, uint32_t micro)
+{
+ switch (sdk_type)
+ {
+ case SDKType::MacOSX:
+ if (major > 10 || (major == 10 && minor >= 10))
+ return true;
+ break;
+ case SDKType::iPhoneOS:
+ case SDKType::iPhoneSimulator:
+ if (major >= 8)
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+bool
+PlatformDarwin::SDKSupportsModules (SDKType desired_type, const FileSpec &sdk_path)
+{
+ ConstString last_path_component = sdk_path.GetLastPathComponent();
+
+ if (last_path_component)
+ {
+ const llvm::StringRef sdk_name = last_path_component.GetStringRef();
+
+ llvm::StringRef version_part;
+
+ if (sdk_name.startswith(sdk_strings[(int)desired_type]))
+ {
+ version_part = sdk_name.drop_front(strlen(sdk_strings[(int)desired_type]));
+ }
+ else
+ {
+ return false;
+ }
+
+ const size_t major_dot_offset = version_part.find('.');
+ if (major_dot_offset == llvm::StringRef::npos)
+ return false;
+
+ const llvm::StringRef major_version = version_part.slice(0, major_dot_offset);
+ const llvm::StringRef minor_part = version_part.drop_front(major_dot_offset + 1);
+
+ const size_t minor_dot_offset = minor_part.find('.');
+ if (minor_dot_offset == llvm::StringRef::npos)
+ return false;
+
+ const llvm::StringRef minor_version = minor_part.slice(0, minor_dot_offset);
+
+ unsigned int major = 0;
+ unsigned int minor = 0;
+ unsigned int micro = 0;
+
+ if (major_version.getAsInteger(10, major))
+ return false;
+
+ if (minor_version.getAsInteger(10, minor))
+ return false;
+
+ return SDKSupportsModules(desired_type, major, minor, micro);
+ }
+
+ return false;
+}
+
+FileSpec::EnumerateDirectoryResult
+PlatformDarwin::DirectoryEnumerator(void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &spec)
+{
+ SDKEnumeratorInfo *enumerator_info = static_cast<SDKEnumeratorInfo*>(baton);
+
+ if (SDKSupportsModules(enumerator_info->sdk_type, spec))
+ {
+ enumerator_info->found_path = spec;
+ return FileSpec::EnumerateDirectoryResult::eEnumerateDirectoryResultNext;
+ }
+
+ return FileSpec::EnumerateDirectoryResult::eEnumerateDirectoryResultNext;
+}
+
+FileSpec
+PlatformDarwin::FindSDKInXcodeForModules (SDKType sdk_type,
+ const FileSpec &sdks_spec)
+{
+ // Look inside Xcode for the required installed iOS SDK version
+
+ if (!sdks_spec.IsDirectory())
+ return FileSpec();
+
+ const bool find_directories = true;
+ const bool find_files = false;
+ const bool find_other = true; // include symlinks
+
+ SDKEnumeratorInfo enumerator_info;
+
+ enumerator_info.sdk_type = sdk_type;
+
+ FileSpec::EnumerateDirectory(sdks_spec.GetPath().c_str(),
+ find_directories,
+ find_files,
+ find_other,
+ DirectoryEnumerator,
+ &enumerator_info);
+
+ if (enumerator_info.found_path.IsDirectory())
+ return enumerator_info.found_path;
+ else
+ return FileSpec();
+}
+
+FileSpec
+PlatformDarwin::GetSDKDirectoryForModules (SDKType sdk_type)
+{
+ switch (sdk_type)
+ {
+ case SDKType::MacOSX:
+ case SDKType::iPhoneSimulator:
+ case SDKType::iPhoneOS:
+ break;
+ }
+
+ FileSpec sdks_spec = GetXcodeContentsPath();
+ sdks_spec.AppendPathComponent("Developer");
+ sdks_spec.AppendPathComponent("Platforms");
+
+ switch (sdk_type)
+ {
+ case SDKType::MacOSX:
+ sdks_spec.AppendPathComponent("MacOSX.platform");
+ break;
+ case SDKType::iPhoneSimulator:
+ sdks_spec.AppendPathComponent("iPhoneSimulator.platform");
+ break;
+ case SDKType::iPhoneOS:
+ sdks_spec.AppendPathComponent("iPhoneOS.platform");
+ break;
+ }
+
+ sdks_spec.AppendPathComponent("Developer");
+ sdks_spec.AppendPathComponent("SDKs");
+
+ if (sdk_type == SDKType::MacOSX)
+ {
+ uint32_t major = 0;
+ uint32_t minor = 0;
+ uint32_t micro = 0;
+
+ if (HostInfo::GetOSVersion(major, minor, micro))
+ {
+ if (SDKSupportsModules(SDKType::MacOSX, major, minor, micro))
+ {
+ // We slightly prefer the exact SDK for this machine. See if it is there.
+
+ FileSpec native_sdk_spec = sdks_spec;
+ StreamString native_sdk_name;
+ native_sdk_name.Printf("MacOSX%u.%u.sdk", major, minor);
+ native_sdk_spec.AppendPathComponent(native_sdk_name.GetString().c_str());
+
+ if (native_sdk_spec.Exists())
+ {
+ return native_sdk_spec;
+ }
+ }
+ }
+ }
+
+ return FindSDKInXcodeForModules(sdk_type, sdks_spec);
+}
+
+void
+PlatformDarwin::AddClangModuleCompilationOptionsForSDKType (Target *target, std::vector<std::string> &options, SDKType sdk_type)
+{
+ const std::vector<std::string> apple_arguments =
+ {
+ "-x", "objective-c++",
+ "-fobjc-arc",
+ "-fblocks",
+ "-D_ISO646_H",
+ "-D__ISO646_H"
+ };
+
+ options.insert(options.end(),
+ apple_arguments.begin(),
+ apple_arguments.end());
+
+ StreamString minimum_version_option;
+ uint32_t versions[3] = { 0, 0, 0 };
+ bool use_current_os_version = false;
+ switch (sdk_type)
+ {
+ case SDKType::iPhoneOS:
+#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
+ use_current_os_version = true;
+#else
+ use_current_os_version = false;
+#endif
+ break;
+
+ case SDKType::iPhoneSimulator:
+ use_current_os_version = false;
+ break;
+
+ case SDKType::MacOSX:
+#if defined (__i386__) || defined (__x86_64__)
+ use_current_os_version = true;
+#else
+ use_current_os_version = false;
+#endif
+ break;
+ }
+
+ bool versions_valid = false;
+ if (use_current_os_version)
+ versions_valid = GetOSVersion(versions[0], versions[1], versions[2]);
+ else if (target)
+ {
+ // Our OS doesn't match our executable so we need to get the min OS version from the object file
+ ModuleSP exe_module_sp = target->GetExecutableModule();
+ if (exe_module_sp)
+ {
+ ObjectFile *object_file = exe_module_sp->GetObjectFile();
+ if (object_file)
+ versions_valid = object_file->GetMinimumOSVersion(versions, 3) > 0;
+ }
+ }
+ // Only add the version-min options if we got a version from somewhere
+ if (versions_valid && versions[0] != UINT32_MAX)
+ {
+ // Make any invalid versions be zero if needed
+ if (versions[1] == UINT32_MAX)
+ versions[1] = 0;
+ if (versions[2] == UINT32_MAX)
+ versions[2] = 0;
+
+ switch (sdk_type)
+ {
+ case SDKType::iPhoneOS:
+ minimum_version_option.PutCString("-mios-version-min=");
+ minimum_version_option.PutCString(clang::VersionTuple(versions[0], versions[1], versions[2]).getAsString().c_str());
+ break;
+ case SDKType::iPhoneSimulator:
+ minimum_version_option.PutCString("-mios-simulator-version-min=");
+ minimum_version_option.PutCString(clang::VersionTuple(versions[0], versions[1], versions[2]).getAsString().c_str());
+ break;
+ case SDKType::MacOSX:
+ minimum_version_option.PutCString("-mmacosx-version-min=");
+ minimum_version_option.PutCString(clang::VersionTuple(versions[0], versions[1], versions[2]).getAsString().c_str());
+ }
+ options.push_back(minimum_version_option.GetString());
+ }
+
+ FileSpec sysroot_spec;
+ // Scope for mutex locker below
+ {
+ Mutex::Locker locker (m_mutex);
+ sysroot_spec = GetSDKDirectoryForModules(sdk_type);
+ }
+
+ if (sysroot_spec.IsDirectory())
+ {
+ options.push_back("-isysroot");
+ options.push_back(sysroot_spec.GetPath());
+ }
+}
+
+ConstString
+PlatformDarwin::GetFullNameForDylib (ConstString basename)
+{
+ if (basename.IsEmpty())
+ return basename;
+
+ StreamString stream;
+ stream.Printf("lib%s.dylib", basename.GetCString());
+ return ConstString(stream.GetData());
+}
+
+bool
+PlatformDarwin::GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update,
+ Process *process)
+{
+ if (process && strstr(GetPluginName().GetCString(), "-simulator"))
+ {
+ lldb_private::ProcessInstanceInfo proc_info;
+ if (Host::GetProcessInfo(process->GetID(), proc_info))
+ {
+ Args &env = proc_info.GetEnvironmentEntries();
+ const size_t n = env.GetArgumentCount();
+ const llvm::StringRef k_runtime_version("SIMULATOR_RUNTIME_VERSION=");
+ const llvm::StringRef k_dyld_root_path("DYLD_ROOT_PATH=");
+ std::string dyld_root_path;
+
+ for (size_t i=0; i<n; ++i)
+ {
+ const char *env_cstr = env.GetArgumentAtIndex(i);
+ if (env_cstr)
+ {
+ llvm::StringRef env_str(env_cstr);
+ if (env_str.startswith(k_runtime_version))
+ {
+ llvm::StringRef version_str(env_str.substr(k_runtime_version.size()));
+ Args::StringToVersion (version_str.data(), major, minor, update);
+ if (major != UINT32_MAX)
+ return true;
+ }
+ else if (env_str.startswith(k_dyld_root_path))
+ {
+ dyld_root_path = env_str.substr(k_dyld_root_path.size()).str();
+ }
+ }
+ }
+
+ if (!dyld_root_path.empty())
+ {
+ dyld_root_path += "/System/Library/CoreServices/SystemVersion.plist";
+ ApplePropertyList system_version_plist(dyld_root_path.c_str());
+ std::string product_version;
+ if (system_version_plist.GetValueAsString("ProductVersion", product_version))
+ {
+ Args::StringToVersion (product_version.c_str(), major, minor, update);
+ return major != UINT32_MAX;
+ }
+ }
+
+ }
+ // For simulator platforms, do NOT call back through Platform::GetOSVersion()
+ // as it might call Process::GetHostOSVersion() which we don't want as it will be
+ // incorrect
+ return false;
+ }
+
+ return Platform::GetOSVersion(major, minor, update, process);
+}
+
+lldb_private::FileSpec
+PlatformDarwin::LocateExecutable (const char *basename)
+{
+ // A collection of SBFileSpec whose SBFileSpec.m_directory members are filled in with
+ // any executable directories that should be searched.
+ static std::vector<FileSpec> g_executable_dirs;
+
+ // Find the global list of directories that we will search for
+ // executables once so we don't keep doing the work over and over.
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+
+ // When locating executables, trust the DEVELOPER_DIR first if it is set
+ FileSpec xcode_contents_dir = GetXcodeContentsPath();
+ if (xcode_contents_dir)
+ {
+ FileSpec xcode_lldb_resources = xcode_contents_dir;
+ xcode_lldb_resources.AppendPathComponent("SharedFrameworks");
+ xcode_lldb_resources.AppendPathComponent("LLDB.framework");
+ xcode_lldb_resources.AppendPathComponent("Resources");
+ if (xcode_lldb_resources.Exists())
+ {
+ FileSpec dir;
+ dir.GetDirectory().SetCString(xcode_lldb_resources.GetPath().c_str());
+ g_executable_dirs.push_back(dir);
+ }
+ }
+ });
+
+ // Now search the global list of executable directories for the executable we
+ // are looking for
+ for (const auto &executable_dir : g_executable_dirs)
+ {
+ FileSpec executable_file;
+ executable_file.GetDirectory() = executable_dir.GetDirectory();
+ executable_file.GetFilename().SetCString(basename);
+ if (executable_file.Exists())
+ return executable_file;
+ }
+
+ return FileSpec();
+}
diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/source/Plugins/Platform/MacOSX/PlatformDarwin.h
new file mode 100644
index 000000000000..b280b35da655
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformDarwin.h
@@ -0,0 +1,156 @@
+//===-- PlatformDarwin.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_PlatformDarwin_h_
+#define liblldb_PlatformDarwin_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/FileSpec.h"
+#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
+
+class PlatformDarwin : public PlatformPOSIX
+{
+public:
+ PlatformDarwin(bool is_host);
+
+ ~PlatformDarwin() override;
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ lldb_private::Error
+ ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr) override;
+
+ lldb_private::Error
+ ResolveSymbolFile (lldb_private::Target &target,
+ const lldb_private::ModuleSpec &sym_spec,
+ lldb_private::FileSpec &sym_file) override;
+
+ lldb_private::FileSpecList
+ LocateExecutableScriptingResources (lldb_private::Target *target,
+ lldb_private::Module &module,
+ lldb_private::Stream* feedback_stream) override;
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ size_t
+ GetSoftwareBreakpointTrapOpcode (lldb_private::Target &target,
+ lldb_private::BreakpointSite *bp_site) override;
+
+ bool
+ GetProcessInfo (lldb::pid_t pid,
+ lldb_private::ProcessInstanceInfo &proc_info) override;
+
+ lldb::BreakpointSP
+ SetThreadCreationBreakpoint (lldb_private::Target &target) override;
+
+ uint32_t
+ FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos) override;
+
+ bool
+ ModuleIsExcludedForUnconstrainedSearches(lldb_private::Target &target,
+ const lldb::ModuleSP &module_sp) override;
+
+ bool
+ ARMGetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
+
+ bool
+ x86GetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
+
+ int32_t
+ GetResumeCountForLaunchInfo (lldb_private::ProcessLaunchInfo &launch_info) override;
+
+ void
+ CalculateTrapHandlerSymbolNames () override;
+
+ bool
+ GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update,
+ lldb_private::Process *process = nullptr) override;
+
+ bool
+ SupportsModules () override { return true; }
+
+ lldb_private::ConstString
+ GetFullNameForDylib (lldb_private::ConstString basename) override;
+
+ lldb_private::FileSpec
+ LocateExecutable (const char *basename) override;
+
+protected:
+ void
+ ReadLibdispatchOffsetsAddress (lldb_private::Process *process);
+
+ void
+ ReadLibdispatchOffsets (lldb_private::Process *process);
+
+ virtual lldb_private::Error
+ GetSharedModuleWithLocalCache (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr);
+
+ enum class SDKType {
+ MacOSX = 0,
+ iPhoneSimulator,
+ iPhoneOS,
+ };
+
+ static bool
+ SDKSupportsModules (SDKType sdk_type, uint32_t major, uint32_t minor, uint32_t micro);
+
+ static bool
+ SDKSupportsModules (SDKType desired_type, const lldb_private::FileSpec &sdk_path);
+
+ struct SDKEnumeratorInfo {
+ lldb_private::FileSpec found_path;
+ SDKType sdk_type;
+ };
+
+ static lldb_private::FileSpec::EnumerateDirectoryResult
+ DirectoryEnumerator(void *baton,
+ lldb_private::FileSpec::FileType file_type,
+ const lldb_private::FileSpec &spec);
+
+ static lldb_private::FileSpec
+ FindSDKInXcodeForModules (SDKType sdk_type,
+ const lldb_private::FileSpec &sdks_spec);
+
+ static lldb_private::FileSpec
+ GetSDKDirectoryForModules (PlatformDarwin::SDKType sdk_type);
+
+ void
+ AddClangModuleCompilationOptionsForSDKType (lldb_private::Target *target, std::vector<std::string> &options, SDKType sdk_type);
+
+ std::string m_developer_directory;
+
+ const char *
+ GetDeveloperDirectory();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformDarwin);
+};
+
+#endif // liblldb_PlatformDarwin_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp
new file mode 100644
index 000000000000..a502aa03eb26
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp
@@ -0,0 +1,979 @@
+//===-- PlatformDarwinKernel.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformDarwinKernel.h"
+
+#if defined (__APPLE__) // This Plugin uses the Mac-specific source/Host/macosx/cfcpp utilities
+
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/OptionValueFileSpecList.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/Property.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "Host/macosx/cfcpp/CFCBundle.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+// Static Variables
+//------------------------------------------------------------------
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+void
+PlatformDarwinKernel::Initialize ()
+{
+ PlatformDarwin::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+ PluginManager::RegisterPlugin (PlatformDarwinKernel::GetPluginNameStatic(),
+ PlatformDarwinKernel::GetDescriptionStatic(),
+ PlatformDarwinKernel::CreateInstance,
+ PlatformDarwinKernel::DebuggerInitialize);
+ }
+}
+
+void
+PlatformDarwinKernel::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformDarwinKernel::CreateInstance);
+ }
+ }
+
+ PlatformDarwin::Terminate ();
+}
+
+PlatformSP
+PlatformDarwinKernel::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformDarwinKernel::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ // This is a special plugin that we don't want to activate just based on an ArchSpec for normal
+ // userland debugging. It is only useful in kernel debug sessions and the DynamicLoaderDarwinPlugin
+ // (or a user doing 'platform select') will force the creation of this Platform plugin.
+ if (force == false)
+ {
+ if (log)
+ log->Printf ("PlatformDarwinKernel::%s() aborting creation of platform because force == false", __FUNCTION__);
+ return PlatformSP();
+ }
+
+ bool create = force;
+ LazyBool is_ios_debug_session = eLazyBoolCalculate;
+
+ if (create == false && arch && arch->IsValid())
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::Apple:
+ create = true;
+ break;
+
+ // Only accept "unknown" for vendor if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+ default:
+ break;
+ }
+
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
+ case llvm::Triple::WatchOS:
+ case llvm::Triple::TvOS:
+ break;
+ // Only accept "vendor" for vendor if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ if (arch && arch->IsValid())
+ {
+ switch (arch->GetMachine())
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ is_ios_debug_session = eLazyBoolNo;
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::thumb:
+ is_ios_debug_session = eLazyBoolYes;
+ break;
+ default:
+ is_ios_debug_session = eLazyBoolCalculate;
+ break;
+ }
+ }
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformDarwinKernel::%s() creating platform", __FUNCTION__);
+
+ return PlatformSP(new PlatformDarwinKernel (is_ios_debug_session));
+ }
+
+ if (log)
+ log->Printf ("PlatformDarwinKernel::%s() aborting creation of platform", __FUNCTION__);
+
+ return PlatformSP();
+}
+
+
+lldb_private::ConstString
+PlatformDarwinKernel::GetPluginNameStatic ()
+{
+ static ConstString g_name("darwin-kernel");
+ return g_name;
+}
+
+const char *
+PlatformDarwinKernel::GetDescriptionStatic()
+{
+ return "Darwin Kernel platform plug-in.";
+}
+
+//------------------------------------------------------------------
+/// Code to handle the PlatformDarwinKernel settings
+//------------------------------------------------------------------
+
+static PropertyDefinition
+g_properties[] =
+{
+ { "search-locally-for-kexts" , OptionValue::eTypeBoolean, true, true, NULL, NULL, "Automatically search for kexts on the local system when doing kernel debugging." },
+ { "kext-directories", OptionValue::eTypeFileSpecList, false, 0, NULL, NULL, "Directories/KDKs to search for kexts in when starting a kernel debug session." },
+ { NULL , OptionValue::eTypeInvalid, false, 0 , NULL, NULL, NULL }
+};
+
+enum {
+ ePropertySearchForKexts = 0,
+ ePropertyKextDirectories
+};
+
+
+
+class PlatformDarwinKernelProperties : public Properties
+{
+public:
+
+ static ConstString &
+ GetSettingName ()
+ {
+ static ConstString g_setting_name("darwin-kernel");
+ return g_setting_name;
+ }
+
+ PlatformDarwinKernelProperties() :
+ Properties ()
+ {
+ m_collection_sp.reset (new OptionValueProperties(GetSettingName()));
+ m_collection_sp->Initialize(g_properties);
+ }
+
+ virtual
+ ~PlatformDarwinKernelProperties()
+ {
+ }
+
+ bool
+ GetSearchForKexts() const
+ {
+ const uint32_t idx = ePropertySearchForKexts;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+ }
+
+ FileSpecList &
+ GetKextDirectories() const
+ {
+ const uint32_t idx = ePropertyKextDirectories;
+ OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList (NULL, false, idx);
+ assert(option_value);
+ return option_value->GetCurrentValue();
+ }
+};
+
+typedef std::shared_ptr<PlatformDarwinKernelProperties> PlatformDarwinKernelPropertiesSP;
+
+static const PlatformDarwinKernelPropertiesSP &
+GetGlobalProperties()
+{
+ static PlatformDarwinKernelPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ g_settings_sp.reset (new PlatformDarwinKernelProperties ());
+ return g_settings_sp;
+}
+
+void
+PlatformDarwinKernel::DebuggerInitialize (lldb_private::Debugger &debugger)
+{
+ if (!PluginManager::GetSettingForPlatformPlugin (debugger, PlatformDarwinKernelProperties::GetSettingName()))
+ {
+ const bool is_global_setting = true;
+ PluginManager::CreateSettingForPlatformPlugin (debugger,
+ GetGlobalProperties()->GetValueProperties(),
+ ConstString ("Properties for the PlatformDarwinKernel plug-in."),
+ is_global_setting);
+ }
+}
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformDarwinKernel::PlatformDarwinKernel (lldb_private::LazyBool is_ios_debug_session) :
+ PlatformDarwin (false), // This is a remote platform
+ m_name_to_kext_path_map(),
+ m_search_directories(),
+ m_kernel_binaries(),
+ m_ios_debug_session(is_ios_debug_session)
+
+{
+ if (GetGlobalProperties()->GetSearchForKexts())
+ {
+ CollectKextAndKernelDirectories ();
+ IndexKextsInDirectories ();
+ IndexKernelsInDirectories ();
+ }
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformDarwinKernel::~PlatformDarwinKernel()
+{
+}
+
+
+void
+PlatformDarwinKernel::GetStatus (Stream &strm)
+{
+ Platform::GetStatus (strm);
+ strm.Printf (" Debug session type: ");
+ if (m_ios_debug_session == eLazyBoolYes)
+ strm.Printf ("iOS kernel debugging\n");
+ else if (m_ios_debug_session == eLazyBoolNo)
+ strm.Printf ("Mac OS X kernel debugging\n");
+ else
+ strm.Printf ("unknown kernel debugging\n");
+ const uint32_t num_kext_dirs = m_search_directories.size();
+ for (uint32_t i=0; i<num_kext_dirs; ++i)
+ {
+ const FileSpec &kext_dir = m_search_directories[i];
+ strm.Printf (" Kext directories: [%2u] \"%s\"\n", i, kext_dir.GetPath().c_str());
+ }
+ strm.Printf (" Total number of kexts indexed: %d\n", (int) m_name_to_kext_path_map.size());
+}
+
+// Populate the m_search_directories vector with directories we should search
+// for kernel & kext binaries.
+
+void
+PlatformDarwinKernel::CollectKextAndKernelDirectories ()
+{
+ // Differentiate between "ios debug session" and "mac debug session" so we don't index
+ // kext bundles that won't be used in this debug session. If this is an ios kext debug
+ // session, looking in /System/Library/Extensions is a waste of stat()s, for example.
+
+ // Build up a list of all SDKs we'll be searching for directories of kexts/kernels
+ // e.g. /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk
+ std::vector<FileSpec> sdk_dirs;
+ if (m_ios_debug_session != eLazyBoolNo)
+ {
+ GetiOSSDKDirectoriesToSearch (sdk_dirs);
+ GetAppleTVOSSDKDirectoriesToSearch (sdk_dirs);
+ GetWatchOSSDKDirectoriesToSearch (sdk_dirs);
+ }
+ if (m_ios_debug_session != eLazyBoolYes)
+ GetMacSDKDirectoriesToSearch (sdk_dirs);
+
+ GetGenericSDKDirectoriesToSearch (sdk_dirs);
+
+ // Build up a list of directories that hold may kext bundles & kernels
+ //
+ // e.g. given /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
+ // find
+ // /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk/
+ // and
+ // /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk/System/Library/Extensions
+
+ std::vector<FileSpec> kext_dirs;
+ SearchSDKsForKextDirectories (sdk_dirs, kext_dirs);
+
+ if (m_ios_debug_session != eLazyBoolNo)
+ GetiOSDirectoriesToSearch (kext_dirs);
+ if (m_ios_debug_session != eLazyBoolYes)
+ GetMacDirectoriesToSearch (kext_dirs);
+
+ GetGenericDirectoriesToSearch (kext_dirs);
+
+ GetUserSpecifiedDirectoriesToSearch (kext_dirs);
+
+ GetKernelDirectoriesToSearch (kext_dirs);
+
+ GetCurrentDirectoryToSearch (kext_dirs);
+
+ // We now have a complete list of directories that we will search for kext bundles
+ m_search_directories = kext_dirs;
+}
+
+void
+PlatformDarwinKernel::GetiOSSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+ // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer"
+ const char *developer_dir = GetDeveloperDirectory();
+ if (developer_dir == NULL)
+ developer_dir = "/Applications/Xcode.app/Contents/Developer";
+
+ char pathbuf[PATH_MAX];
+ ::snprintf (pathbuf, sizeof (pathbuf), "%s/Platforms/iPhoneOS.platform/Developer/SDKs", developer_dir);
+ FileSpec ios_sdk(pathbuf, true);
+ if (ios_sdk.Exists() && ios_sdk.IsDirectory())
+ {
+ directories.push_back (ios_sdk);
+ }
+}
+
+void
+PlatformDarwinKernel::GetAppleTVOSSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+ // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer"
+ const char *developer_dir = GetDeveloperDirectory();
+ if (developer_dir == NULL)
+ developer_dir = "/Applications/Xcode.app/Contents/Developer";
+
+ char pathbuf[PATH_MAX];
+ ::snprintf (pathbuf, sizeof (pathbuf), "%s/Platforms/AppleTVOS.platform/Developer/SDKs", developer_dir);
+ FileSpec ios_sdk(pathbuf, true);
+ if (ios_sdk.Exists() && ios_sdk.IsDirectory())
+ {
+ directories.push_back (ios_sdk);
+ }
+}
+
+void
+PlatformDarwinKernel::GetWatchOSSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+ // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer"
+ const char *developer_dir = GetDeveloperDirectory();
+ if (developer_dir == NULL)
+ developer_dir = "/Applications/Xcode.app/Contents/Developer";
+
+ char pathbuf[PATH_MAX];
+ ::snprintf (pathbuf, sizeof (pathbuf), "%s/Platforms/watchOS.platform/Developer/SDKs", developer_dir);
+ FileSpec ios_sdk(pathbuf, true);
+ if (ios_sdk.Exists() && ios_sdk.IsDirectory())
+ {
+ directories.push_back (ios_sdk);
+ }
+ else
+ {
+ ::snprintf (pathbuf, sizeof (pathbuf), "%s/Platforms/WatchOS.platform/Developer/SDKs", developer_dir);
+ FileSpec alt_watch_sdk(pathbuf, true);
+ if (ios_sdk.Exists() && ios_sdk.IsDirectory())
+ {
+ directories.push_back (ios_sdk);
+ }
+ }
+}
+
+
+void
+PlatformDarwinKernel::GetMacSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+ // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer"
+ const char *developer_dir = GetDeveloperDirectory();
+ if (developer_dir == NULL)
+ developer_dir = "/Applications/Xcode.app/Contents/Developer";
+
+ char pathbuf[PATH_MAX];
+ ::snprintf (pathbuf, sizeof (pathbuf), "%s/Platforms/MacOSX.platform/Developer/SDKs", developer_dir);
+ FileSpec mac_sdk(pathbuf, true);
+ if (mac_sdk.Exists() && mac_sdk.IsDirectory())
+ {
+ directories.push_back (mac_sdk);
+ }
+}
+
+void
+PlatformDarwinKernel::GetGenericSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+ FileSpec generic_sdk("/AppleInternal/Developer/KDKs", true);
+ if (generic_sdk.Exists() && generic_sdk.IsDirectory())
+ {
+ directories.push_back (generic_sdk);
+ }
+
+ // The KDKs distributed from Apple installed on external
+ // developer systems may be in directories like
+ // /Library/Developer/KDKs/KDK_10.10_14A298i.kdk
+ FileSpec installed_kdks("/Library/Developer/KDKs", true);
+ if (installed_kdks.Exists() && installed_kdks.IsDirectory())
+ {
+ directories.push_back (installed_kdks);
+ }
+}
+
+void
+PlatformDarwinKernel::GetiOSDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+}
+
+void
+PlatformDarwinKernel::GetMacDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+ FileSpec sle("/System/Library/Extensions", true);
+ if (sle.Exists() && sle.IsDirectory())
+ {
+ directories.push_back(sle);
+ }
+
+ FileSpec le("/Library/Extensions", true);
+ if (le.Exists() && le.IsDirectory())
+ {
+ directories.push_back(le);
+ }
+
+ FileSpec kdk("/Volumes/KernelDebugKit", true);
+ if (kdk.Exists() && kdk.IsDirectory())
+ {
+ directories.push_back(kdk);
+ }
+}
+
+void
+PlatformDarwinKernel::GetGenericDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+ // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer"
+ const char *developer_dir = GetDeveloperDirectory();
+ if (developer_dir == NULL)
+ developer_dir = "/Applications/Xcode.app/Contents/Developer";
+
+ char pathbuf[PATH_MAX];
+ ::snprintf (pathbuf, sizeof (pathbuf), "%s/../Symbols", developer_dir);
+ FileSpec symbols_dir (pathbuf, true);
+ if (symbols_dir.Exists() && symbols_dir.IsDirectory())
+ {
+ directories.push_back (symbols_dir);
+ }
+}
+
+void
+PlatformDarwinKernel::GetKernelDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+ FileSpec system_library_kernels ("/System/Library/Kernels", true);
+ if (system_library_kernels.Exists() && system_library_kernels.IsDirectory())
+ {
+ directories.push_back (system_library_kernels);
+ }
+ FileSpec slek("/System/Library/Extensions/KDK", true);
+ if (slek.Exists() && slek.IsDirectory())
+ {
+ directories.push_back(slek);
+ }
+}
+
+void
+PlatformDarwinKernel::GetCurrentDirectoryToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+ directories.push_back (FileSpec (".", true));
+
+ FileSpec sle_directory ("System/Library/Extensions", true);
+ if (sle_directory.Exists() && sle_directory.IsDirectory())
+ {
+ directories.push_back (sle_directory);
+ }
+
+ FileSpec le_directory ("Library/Extensions", true);
+ if (le_directory.Exists() && le_directory.IsDirectory())
+ {
+ directories.push_back (le_directory);
+ }
+
+ FileSpec slk_directory ("System/Library/Kernels", true);
+ if (slk_directory.Exists() && slk_directory.IsDirectory())
+ {
+ directories.push_back (slk_directory);
+ }
+ FileSpec slek("System/Library/Extensions/KDK", true);
+ if (slek.Exists() && slek.IsDirectory())
+ {
+ directories.push_back(slek);
+ }
+}
+
+void
+PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+ FileSpecList user_dirs(GetGlobalProperties()->GetKextDirectories());
+ std::vector<FileSpec> possible_sdk_dirs;
+
+ const uint32_t user_dirs_count = user_dirs.GetSize();
+ for (uint32_t i = 0; i < user_dirs_count; i++)
+ {
+ FileSpec dir = user_dirs.GetFileSpecAtIndex (i);
+ dir.ResolvePath();
+ if (dir.Exists() && dir.IsDirectory())
+ {
+ directories.push_back (dir);
+ possible_sdk_dirs.push_back (dir); // does this directory have a *.sdk or *.kdk that we should look in?
+
+ // Is there a "System/Library/Extensions" subdir of this directory?
+ std::string dir_sle_path = dir.GetPath();
+ dir_sle_path.append ("/System/Library/Extensions");
+ FileSpec dir_sle(dir_sle_path.c_str(), true);
+ if (dir_sle.Exists() && dir_sle.IsDirectory())
+ {
+ directories.push_back (dir_sle);
+ }
+
+ // Is there a "System/Library/Kernels" subdir of this directory?
+ std::string dir_slk_path = dir.GetPath();
+ dir_slk_path.append ("/System/Library/Kernels");
+ FileSpec dir_slk(dir_slk_path.c_str(), true);
+ if (dir_slk.Exists() && dir_slk.IsDirectory())
+ {
+ directories.push_back (dir_slk);
+ }
+
+ // Is there a "System/Library/Extensions/KDK" subdir of this directory?
+ std::string dir_slek_path = dir.GetPath();
+ dir_slek_path.append ("/System/Library/Kernels");
+ FileSpec dir_slek(dir_slek_path.c_str(), true);
+ if (dir_slek.Exists() && dir_slek.IsDirectory())
+ {
+ directories.push_back (dir_slek);
+ }
+ }
+ }
+
+ SearchSDKsForKextDirectories (possible_sdk_dirs, directories);
+}
+
+// Scan through the SDK directories, looking for directories where kexts are likely.
+// Add those directories to kext_dirs.
+void
+PlatformDarwinKernel::SearchSDKsForKextDirectories (std::vector<lldb_private::FileSpec> sdk_dirs, std::vector<lldb_private::FileSpec> &kext_dirs)
+{
+ const uint32_t num_sdks = sdk_dirs.size();
+ for (uint32_t i = 0; i < num_sdks; i++)
+ {
+ const FileSpec &sdk_dir = sdk_dirs[i];
+ std::string sdk_dir_path = sdk_dir.GetPath();
+ if (!sdk_dir_path.empty())
+ {
+ const bool find_directories = true;
+ const bool find_files = false;
+ const bool find_other = false;
+ FileSpec::EnumerateDirectory (sdk_dir_path.c_str(),
+ find_directories,
+ find_files,
+ find_other,
+ GetKextDirectoriesInSDK,
+ &kext_dirs);
+ }
+ }
+}
+
+// Callback for FileSpec::EnumerateDirectory().
+// Step through the entries in a directory like
+// /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs
+// looking for any subdirectories of the form MacOSX10.8.Internal.sdk/System/Library/Extensions
+// Adds these to the vector of FileSpec's.
+
+FileSpec::EnumerateDirectoryResult
+PlatformDarwinKernel::GetKextDirectoriesInSDK (void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &file_spec)
+{
+ if (file_type == FileSpec::eFileTypeDirectory
+ && (file_spec.GetFileNameExtension() == ConstString("sdk")
+ || file_spec.GetFileNameExtension() == ConstString("kdk")))
+ {
+ std::string kext_directory_path = file_spec.GetPath();
+
+ // Append the raw directory path, e.g. /Library/Developer/KDKs/KDK_10.10_14A298i.kdk
+ // to the directory search list -- there may be kexts sitting directly
+ // in that directory instead of being in a System/Library/Extensions subdir.
+ ((std::vector<lldb_private::FileSpec> *)baton)->push_back(file_spec);
+
+ // Check to see if there is a System/Library/Extensions subdir & add it if it exists
+
+ std::string sle_kext_directory_path (kext_directory_path);
+ sle_kext_directory_path.append ("/System/Library/Extensions");
+ FileSpec sle_kext_directory (sle_kext_directory_path.c_str(), true);
+ if (sle_kext_directory.Exists() && sle_kext_directory.IsDirectory())
+ {
+ ((std::vector<lldb_private::FileSpec> *)baton)->push_back(sle_kext_directory);
+ }
+
+ // Check to see if there is a Library/Extensions subdir & add it if it exists
+
+ std::string le_kext_directory_path (kext_directory_path);
+ le_kext_directory_path.append ("/Library/Extensions");
+ FileSpec le_kext_directory (le_kext_directory_path.c_str(), true);
+ if (le_kext_directory.Exists() && le_kext_directory.IsDirectory())
+ {
+ ((std::vector<lldb_private::FileSpec> *)baton)->push_back(le_kext_directory);
+ }
+
+ // Check to see if there is a System/Library/Kernels subdir & add it if it exists
+ std::string slk_kernel_path (kext_directory_path);
+ slk_kernel_path.append ("/System/Library/Kernels");
+ FileSpec slk_kernel_directory (slk_kernel_path.c_str(), true);
+ if (slk_kernel_directory.Exists() && slk_kernel_directory.IsDirectory())
+ {
+ ((std::vector<lldb_private::FileSpec> *)baton)->push_back(slk_kernel_directory);
+ }
+
+ // Check to see if there is a System/Library/Extensions/KDK subdir & add it if it exists
+ std::string slek_kernel_path (kext_directory_path);
+ slek_kernel_path.append ("/System/Library/Extensions/KDK");
+ FileSpec slek_kernel_directory (slek_kernel_path.c_str(), true);
+ if (slek_kernel_directory.Exists() && slek_kernel_directory.IsDirectory())
+ {
+ ((std::vector<lldb_private::FileSpec> *)baton)->push_back(slek_kernel_directory);
+ }
+ }
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+void
+PlatformDarwinKernel::IndexKextsInDirectories ()
+{
+ std::vector<FileSpec> kext_bundles;
+
+ const uint32_t num_dirs = m_search_directories.size();
+ for (uint32_t i = 0; i < num_dirs; i++)
+ {
+ const FileSpec &dir = m_search_directories[i];
+ const bool find_directories = true;
+ const bool find_files = false;
+ const bool find_other = false;
+ FileSpec::EnumerateDirectory (dir.GetPath().c_str(),
+ find_directories,
+ find_files,
+ find_other,
+ GetKextsInDirectory,
+ &kext_bundles);
+ }
+
+ const uint32_t num_kexts = kext_bundles.size();
+ for (uint32_t i = 0; i < num_kexts; i++)
+ {
+ const FileSpec &kext = kext_bundles[i];
+ CFCBundle bundle (kext.GetPath().c_str());
+ CFStringRef bundle_id (bundle.GetIdentifier());
+ if (bundle_id && CFGetTypeID (bundle_id) == CFStringGetTypeID ())
+ {
+ char bundle_id_buf[PATH_MAX];
+ if (CFStringGetCString (bundle_id, bundle_id_buf, sizeof (bundle_id_buf), kCFStringEncodingUTF8))
+ {
+ ConstString bundle_conststr(bundle_id_buf);
+ m_name_to_kext_path_map.insert(std::pair<ConstString, FileSpec>(bundle_conststr, kext));
+ }
+ }
+ }
+}
+
+// Callback for FileSpec::EnumerateDirectory().
+// Step through the entries in a directory like /System/Library/Extensions, find .kext bundles, add them
+// to the vector of FileSpecs.
+// If a .kext bundle has a Contents/PlugIns or PlugIns subdir, search for kexts in there too.
+
+FileSpec::EnumerateDirectoryResult
+PlatformDarwinKernel::GetKextsInDirectory (void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &file_spec)
+{
+ if (file_type == FileSpec::eFileTypeDirectory && file_spec.GetFileNameExtension() == ConstString("kext"))
+ {
+ ((std::vector<lldb_private::FileSpec> *)baton)->push_back(file_spec);
+ std::string kext_bundle_path = file_spec.GetPath();
+ std::string search_here_too;
+ std::string contents_plugins_path = kext_bundle_path + "/Contents/PlugIns";
+ FileSpec contents_plugins (contents_plugins_path.c_str(), false);
+ if (contents_plugins.Exists() && contents_plugins.IsDirectory())
+ {
+ search_here_too = contents_plugins_path;
+ }
+ else
+ {
+ std::string plugins_path = kext_bundle_path + "/PlugIns";
+ FileSpec plugins (plugins_path.c_str(), false);
+ if (plugins.Exists() && plugins.IsDirectory())
+ {
+ search_here_too = plugins_path;
+ }
+ }
+
+ if (!search_here_too.empty())
+ {
+ const bool find_directories = true;
+ const bool find_files = false;
+ const bool find_other = false;
+ FileSpec::EnumerateDirectory (search_here_too.c_str(),
+ find_directories,
+ find_files,
+ find_other,
+ GetKextsInDirectory,
+ baton);
+ }
+ }
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+void
+PlatformDarwinKernel::IndexKernelsInDirectories ()
+{
+ std::vector<FileSpec> kernels;
+
+
+ const uint32_t num_dirs = m_search_directories.size();
+ for (uint32_t i = 0; i < num_dirs; i++)
+ {
+ const FileSpec &dir = m_search_directories[i];
+ const bool find_directories = false;
+ const bool find_files = true;
+ const bool find_other = true; // I think eFileTypeSymbolicLink are "other"s.
+ FileSpec::EnumerateDirectory (dir.GetPath().c_str(),
+ find_directories,
+ find_files,
+ find_other,
+ GetKernelsInDirectory,
+ &m_kernel_binaries);
+ }
+}
+
+// Callback for FileSpec::EnumerateDirectory().
+// Step through the entries in a directory like /System/Library/Kernels/, find kernel binaries,
+// add them to m_kernel_binaries.
+
+// We're only doing a filename match here. We won't try opening the file to see if it's really
+// a kernel or not until we need to find a kernel of a given UUID. There's no cheap way to find
+// the UUID of a file (or if it's a Mach-O binary at all) without creating a whole Module for
+// the file and throwing it away if it's not wanted.
+
+FileSpec::EnumerateDirectoryResult
+PlatformDarwinKernel::GetKernelsInDirectory (void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &file_spec)
+{
+ if (file_type == FileSpec::eFileTypeRegular || file_type == FileSpec::eFileTypeSymbolicLink)
+ {
+ ConstString filename = file_spec.GetFilename();
+ if (strncmp (filename.GetCString(), "kernel", 6) == 0
+ || strncmp (filename.GetCString(), "mach", 4) == 0)
+ {
+ // This is m_kernel_binaries but we're in a class method here
+ ((std::vector<lldb_private::FileSpec> *)baton)->push_back(file_spec);
+ }
+ }
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+
+Error
+PlatformDarwinKernel::GetSharedModule (const ModuleSpec &module_spec,
+ Process *process,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ Error error;
+ module_sp.reset();
+ const FileSpec &platform_file = module_spec.GetFileSpec();
+
+ // Treat the file's path as a kext bundle ID (e.g. "com.apple.driver.AppleIRController") and search our kext index.
+ std::string kext_bundle_id = platform_file.GetPath();
+ if (!kext_bundle_id.empty())
+ {
+ ConstString kext_bundle_cs(kext_bundle_id.c_str());
+ if (m_name_to_kext_path_map.count(kext_bundle_cs) > 0)
+ {
+ for (BundleIDToKextIterator it = m_name_to_kext_path_map.begin (); it != m_name_to_kext_path_map.end (); ++it)
+ {
+ if (it->first == kext_bundle_cs)
+ {
+ error = ExamineKextForMatchingUUID (it->second, module_spec.GetUUID(), module_spec.GetArchitecture(), module_sp);
+ if (module_sp.get())
+ {
+ return error;
+ }
+ }
+ }
+ }
+ }
+
+ if (kext_bundle_id.compare("mach_kernel") == 0 && module_spec.GetUUID().IsValid())
+ {
+ for (auto possible_kernel : m_kernel_binaries)
+ {
+ if (possible_kernel.Exists())
+ {
+ ModuleSpec kern_spec (possible_kernel);
+ kern_spec.GetUUID() = module_spec.GetUUID();
+ ModuleSP module_sp (new Module (kern_spec));
+ if (module_sp && module_sp->GetObjectFile() && module_sp->MatchesModuleSpec (kern_spec))
+ {
+ Error error;
+ error = ModuleList::GetSharedModule (kern_spec, module_sp, NULL, NULL, NULL);
+ if (module_sp && module_sp->GetObjectFile())
+ {
+ return error;
+ }
+ }
+ }
+ }
+ }
+
+ // Else fall back to treating the file's path as an actual file path - defer to PlatformDarwin's GetSharedModule.
+ return PlatformDarwin::GetSharedModule (module_spec, process, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
+}
+
+Error
+PlatformDarwinKernel::ExamineKextForMatchingUUID (const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid, const ArchSpec &arch, ModuleSP &exe_module_sp)
+{
+ Error error;
+ FileSpec exe_file = kext_bundle_path;
+ Host::ResolveExecutableInBundle (exe_file);
+ if (exe_file.Exists())
+ {
+ ModuleSpec exe_spec (exe_file);
+ exe_spec.GetUUID() = uuid;
+ if (!uuid.IsValid())
+ {
+ exe_spec.GetArchitecture() = arch;
+ }
+
+ // First try to create a ModuleSP with the file / arch and see if the UUID matches.
+ // If that fails (this exec file doesn't have the correct uuid), don't call GetSharedModule
+ // (which may call in to the DebugSymbols framework and therefore can be slow.)
+ ModuleSP module_sp (new Module (exe_spec));
+ if (module_sp && module_sp->GetObjectFile() && module_sp->MatchesModuleSpec (exe_spec))
+ {
+ error = ModuleList::GetSharedModule (exe_spec, exe_module_sp, NULL, NULL, NULL);
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ {
+ return error;
+ }
+ }
+ exe_module_sp.reset();
+ }
+ return error;
+}
+
+bool
+PlatformDarwinKernel::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
+ return ARMGetSupportedArchitectureAtIndex (idx, arch);
+#else
+ return x86GetSupportedArchitectureAtIndex (idx, arch);
+#endif
+}
+
+void
+PlatformDarwinKernel::CalculateTrapHandlerSymbolNames ()
+{
+ m_trap_handlers.push_back(ConstString ("trap_from_kernel"));
+ m_trap_handlers.push_back(ConstString ("hndl_machine_check"));
+ m_trap_handlers.push_back(ConstString ("hndl_double_fault"));
+ m_trap_handlers.push_back(ConstString ("hndl_allintrs"));
+ m_trap_handlers.push_back(ConstString ("hndl_alltraps"));
+ m_trap_handlers.push_back(ConstString ("interrupt"));
+ m_trap_handlers.push_back(ConstString ("fleh_prefabt"));
+ m_trap_handlers.push_back(ConstString ("ExceptionVectorsBase"));
+ m_trap_handlers.push_back(ConstString ("ExceptionVectorsTable"));
+ m_trap_handlers.push_back(ConstString ("fleh_undef"));
+ m_trap_handlers.push_back(ConstString ("fleh_dataabt"));
+ m_trap_handlers.push_back(ConstString ("fleh_irq"));
+ m_trap_handlers.push_back(ConstString ("fleh_decirq"));
+ m_trap_handlers.push_back(ConstString ("fleh_fiq_generic"));
+ m_trap_handlers.push_back(ConstString ("fleh_dec"));
+
+}
+
+#else // __APPLE__
+
+// Since DynamicLoaderDarwinKernel is compiled in for all systems, and relies on
+// PlatformDarwinKernel for the plug-in name, we compile just the plug-in name in
+// here to avoid issues. We are tracking an internal bug to resolve this issue by
+// either not compiling in DynamicLoaderDarwinKernel for non-apple builds, or to make
+// PlatformDarwinKernel build on all systems. PlatformDarwinKernel is currently not
+// compiled on other platforms due to the use of the Mac-specific
+// source/Host/macosx/cfcpp utilities.
+
+lldb_private::ConstString
+PlatformDarwinKernel::GetPluginNameStatic ()
+{
+ static lldb_private::ConstString g_name("darwin-kernel");
+ return g_name;
+}
+
+#endif // __APPLE__
diff --git a/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h
new file mode 100644
index 000000000000..c1fe23178bf4
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h
@@ -0,0 +1,228 @@
+//===-- PlatformDarwinKernel.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_PlatformDarwinKernel_h_
+#define liblldb_PlatformDarwinKernel_h_
+
+#include "lldb/Core/ConstString.h"
+
+#if defined (__APPLE__) // This Plugin uses the Mac-specific source/Host/macosx/cfcpp utilities
+
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Host/FileSpec.h"
+
+// Project includes
+#include "PlatformDarwin.h"
+
+class PlatformDarwinKernel : public PlatformDarwin
+{
+public:
+
+ //------------------------------------------------------------
+ // Class Functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static void
+ DebuggerInitialize (lldb_private::Debugger &debugger);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ static const char *
+ GetDescriptionStatic();
+
+ //------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------
+ PlatformDarwinKernel (lldb_private::LazyBool is_ios_debug_session);
+
+ virtual
+ ~PlatformDarwinKernel();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override
+ {
+ return GetPluginNameStatic();
+ }
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ const char *
+ GetDescription () override
+ {
+ return GetDescriptionStatic();
+ }
+
+ void
+ GetStatus (lldb_private::Stream &strm) override;
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb_private::Process *process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ bool
+ GetSupportedArchitectureAtIndex (uint32_t idx,
+ lldb_private::ArchSpec &arch) override;
+
+ bool
+ SupportsModules() override { return false; }
+
+ void
+ CalculateTrapHandlerSymbolNames () override;
+
+protected:
+
+ // Map from kext bundle ID ("com.apple.filesystems.exfat") to FileSpec for the kext bundle on
+ // the host ("/System/Library/Extensions/exfat.kext/Contents/Info.plist").
+ typedef std::multimap<lldb_private::ConstString, lldb_private::FileSpec> BundleIDToKextMap;
+ typedef BundleIDToKextMap::iterator BundleIDToKextIterator;
+
+ typedef std::vector<lldb_private::FileSpec> KernelBinaryCollection;
+
+ // Array of directories that were searched for kext bundles (used only for reporting to user)
+ typedef std::vector<lldb_private::FileSpec> DirectoriesSearchedCollection;
+ typedef DirectoriesSearchedCollection::iterator DirectoriesSearchedIterator;
+
+
+ static lldb_private::FileSpec::EnumerateDirectoryResult
+ GetKextDirectoriesInSDK (void *baton,
+ lldb_private::FileSpec::FileType file_type,
+ const lldb_private::FileSpec &file_spec);
+
+ static lldb_private::FileSpec::EnumerateDirectoryResult
+ GetKextsInDirectory (void *baton,
+ lldb_private::FileSpec::FileType file_type,
+ const lldb_private::FileSpec &file_spec);
+
+ // Populate m_search_directories vector of directories
+ void
+ CollectKextAndKernelDirectories ();
+
+ // Directories where we may find iOS SDKs with kext bundles in them
+ void
+ GetiOSSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ // Directories where we may find AppleTVOS SDKs with kext bundles in them
+ void
+ GetAppleTVOSSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ // Directories where we may find WatchOS SDKs with kext bundles in them
+ void
+ GetWatchOSSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ // Directories where we may find Mac OS X SDKs with kext bundles in them
+ void
+ GetMacSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ // Directories where we may find Mac OS X or iOS SDKs with kext bundles in them
+ void
+ GetGenericSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ // Directories where we may find iOS kext bundles
+ void
+ GetiOSDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ // Directories where we may find MacOSX kext bundles
+ void
+ GetMacDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ // Directories where we may find iOS or MacOSX kext bundles
+ void
+ GetGenericDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ // Directories specified via the "kext-directories" setting - maybe KDK/SDKs, may be plain directories
+ void
+ GetUserSpecifiedDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ void
+ GetCurrentDirectoryToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ // Directories where we may find kernels exclusively
+ void
+ GetKernelDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+ // Search through a vector of SDK FileSpecs, add any directories that may contain kexts
+ // to the vector of kext dir FileSpecs
+ void
+ SearchSDKsForKextDirectories (std::vector<lldb_private::FileSpec> sdk_dirs, std::vector<lldb_private::FileSpec> &kext_dirs);
+
+ // Search through all of the directories passed in, find all .kext bundles in those directories,
+ // get the CFBundleIDs out of the Info.plists and add the bundle ID and kext path to m_name_to_kext_path_map.
+ void
+ IndexKextsInDirectories ();
+
+ // Search through all of the directories passed in, find all kernel binaries in those directories
+ // (look for "kernel*", "mach.*", assume those are kernels. False positives aren't a huge problem.)
+ void
+ IndexKernelsInDirectories ();
+
+ // Callback which iterates over all the files in a given directory, looking for kernel binaries
+ static lldb_private::FileSpec::EnumerateDirectoryResult
+ GetKernelsInDirectory (void *baton,
+ lldb_private::FileSpec::FileType file_type,
+ const lldb_private::FileSpec &file_spec);
+
+ lldb_private::Error
+ ExamineKextForMatchingUUID (const lldb_private::FileSpec &kext_bundle_path, const lldb_private::UUID &uuid, const lldb_private::ArchSpec &arch, lldb::ModuleSP &exe_module_sp);
+
+private:
+
+ BundleIDToKextMap m_name_to_kext_path_map; // multimap of CFBundleID to FileSpec on local filesystem
+ DirectoriesSearchedCollection m_search_directories; // list of directories we search for kexts/kernels
+ KernelBinaryCollection m_kernel_binaries; // list of kernel binaries we found on local filesystem
+ lldb_private::LazyBool m_ios_debug_session;
+
+ DISALLOW_COPY_AND_ASSIGN (PlatformDarwinKernel);
+
+};
+
+#else // __APPLE__
+
+// Since DynamicLoaderDarwinKernel is compiled in for all systems, and relies on
+// PlatformDarwinKernel for the plug-in name, we compile just the plug-in name in
+// here to avoid issues. We are tracking an internal bug to resolve this issue by
+// either not compiling in DynamicLoaderDarwinKernel for non-apple builds, or to make
+// PlatformDarwinKernel build on all systems. PlatformDarwinKernel is currently not
+// compiled on other platforms due to the use of the Mac-specific
+// source/Host/macosx/cfcpp utilities.
+
+class PlatformDarwinKernel
+{
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+};
+
+#endif // __APPLE__
+
+#endif // liblldb_PlatformDarwinKernel_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
new file mode 100644
index 000000000000..7e15facc1b03
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
@@ -0,0 +1,386 @@
+//===-- PlatformMacOSX.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformMacOSX.h"
+#include "lldb/Host/Config.h"
+
+// C++ Includes
+
+#include <sstream>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static uint32_t g_initialize_count = 0;
+
+void
+PlatformMacOSX::Initialize ()
+{
+ PlatformDarwin::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+#if defined (__APPLE__)
+ PlatformSP default_platform_sp (new PlatformMacOSX(true));
+ default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
+ Platform::SetHostPlatform (default_platform_sp);
+#endif
+ PluginManager::RegisterPlugin (PlatformMacOSX::GetPluginNameStatic(false),
+ PlatformMacOSX::GetDescriptionStatic(false),
+ PlatformMacOSX::CreateInstance);
+ }
+
+}
+
+void
+PlatformMacOSX::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformMacOSX::CreateInstance);
+ }
+ }
+
+ PlatformDarwin::Terminate ();
+}
+
+PlatformSP
+PlatformMacOSX::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformMacOSX::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ // The only time we create an instance is when we are creating a remote
+ // macosx platform
+ const bool is_host = false;
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::Apple:
+ create = true;
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for vendor if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::Darwin: // Deprecated, but still support Darwin for historical reasons
+ case llvm::Triple::MacOSX:
+ break;
+#if defined(__APPLE__)
+ // Only accept "vendor" for vendor if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformMacOSX::%s() creating platform", __FUNCTION__);
+ return PlatformSP(new PlatformMacOSX (is_host));
+ }
+
+ if (log)
+ log->Printf ("PlatformMacOSX::%s() aborting creation of platform", __FUNCTION__);
+
+ return PlatformSP();
+}
+
+lldb_private::ConstString
+PlatformMacOSX::GetPluginNameStatic (bool is_host)
+{
+ if (is_host)
+ {
+ static ConstString g_host_name(Platform::GetHostPlatformName ());
+ return g_host_name;
+ }
+ else
+ {
+ static ConstString g_remote_name("remote-macosx");
+ return g_remote_name;
+ }
+}
+
+const char *
+PlatformMacOSX::GetDescriptionStatic (bool is_host)
+{
+ if (is_host)
+ return "Local Mac OS X user platform plug-in.";
+ else
+ return "Remote Mac OS X user platform plug-in.";
+}
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformMacOSX::PlatformMacOSX (bool is_host) :
+ PlatformDarwin (is_host)
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformMacOSX::~PlatformMacOSX()
+{
+}
+
+ConstString
+PlatformMacOSX::GetSDKDirectory (lldb_private::Target &target)
+{
+ ModuleSP exe_module_sp (target.GetExecutableModule());
+ if (exe_module_sp)
+ {
+ ObjectFile *objfile = exe_module_sp->GetObjectFile();
+ if (objfile)
+ {
+ std::string xcode_contents_path;
+ std::string default_xcode_sdk;
+ FileSpec fspec;
+ uint32_t versions[2];
+ if (objfile->GetSDKVersion(versions, sizeof(versions)))
+ {
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, fspec))
+ {
+ std::string path;
+ xcode_contents_path = fspec.GetPath();
+ size_t pos = xcode_contents_path.find("/Xcode.app/Contents/");
+ if (pos != std::string::npos)
+ {
+ // LLDB.framework is inside an Xcode app bundle, we can locate the SDK from here
+ xcode_contents_path.erase(pos + strlen("/Xcode.app/Contents/"));
+ }
+ else
+ {
+ xcode_contents_path.clear();
+ // Use the selected Xcode
+ int status = 0;
+ int signo = 0;
+ std::string output;
+ const char *command = "xcrun -sdk macosx --show-sdk-path";
+ lldb_private::Error error = RunShellCommand (command, // shell command to run
+ NULL, // current working directory
+ &status, // Put the exit status of the process in here
+ &signo, // Put the signal that caused the process to exit in here
+ &output, // Get the output from the command and place it in this string
+ 3); // Timeout in seconds to wait for shell program to finish
+ if (status == 0 && !output.empty())
+ {
+ size_t first_non_newline = output.find_last_not_of("\r\n");
+ if (first_non_newline != std::string::npos)
+ output.erase(first_non_newline+1);
+ default_xcode_sdk = output;
+
+ pos = default_xcode_sdk.find("/Xcode.app/Contents/");
+ if (pos != std::string::npos)
+ xcode_contents_path = default_xcode_sdk.substr(0, pos + strlen("/Xcode.app/Contents/"));
+ }
+ }
+ }
+
+ if (!xcode_contents_path.empty())
+ {
+ StreamString sdk_path;
+ sdk_path.Printf("%sDeveloper/Platforms/MacOSX.platform/Developer/SDKs/MacOSX%u.%u.sdk", xcode_contents_path.c_str(), versions[0], versions[1]);
+ fspec.SetFile(sdk_path.GetString().c_str(), false);
+ if (fspec.Exists())
+ return ConstString(sdk_path.GetString().c_str());
+ }
+
+ if (!default_xcode_sdk.empty())
+ {
+ fspec.SetFile(default_xcode_sdk.c_str(), false);
+ if (fspec.Exists())
+ return ConstString(default_xcode_sdk.c_str());
+ }
+ }
+ }
+ }
+ return ConstString();
+}
+
+
+Error
+PlatformMacOSX::GetSymbolFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ if (IsRemote())
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file);
+ }
+
+ // Default to the local case
+ local_file = platform_file;
+ return Error();
+}
+
+lldb_private::Error
+PlatformMacOSX::GetFileWithUUID (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file)
+{
+ if (IsRemote() && m_remote_platform_sp)
+ {
+ std::string local_os_build;
+#if !defined(__linux__)
+ HostInfo::GetOSBuildString(local_os_build);
+#endif
+ std::string remote_os_build;
+ m_remote_platform_sp->GetOSBuildString(remote_os_build);
+ if (local_os_build.compare(remote_os_build) == 0)
+ {
+ // same OS version: the local file is good enough
+ local_file = platform_file;
+ return Error();
+ }
+ else
+ {
+ // try to find the file in the cache
+ std::string cache_path(GetLocalCacheDirectory());
+ std::string module_path (platform_file.GetPath());
+ cache_path.append(module_path);
+ FileSpec module_cache_spec(cache_path.c_str(),false);
+ if (module_cache_spec.Exists())
+ {
+ local_file = module_cache_spec;
+ return Error();
+ }
+ // bring in the remote module file
+ FileSpec module_cache_folder = module_cache_spec.CopyByRemovingLastPathComponent();
+ // try to make the local directory first
+ Error err =
+ FileSystem::MakeDirectory(module_cache_folder, eFilePermissionsDirectoryDefault);
+ if (err.Fail())
+ return err;
+ err = GetFile(platform_file, module_cache_spec);
+ if (err.Fail())
+ return err;
+ if (module_cache_spec.Exists())
+ {
+ local_file = module_cache_spec;
+ return Error();
+ }
+ else
+ return Error("unable to obtain valid module file");
+ }
+ }
+ local_file = platform_file;
+ return Error();
+}
+
+bool
+PlatformMacOSX::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
+ return ARMGetSupportedArchitectureAtIndex (idx, arch);
+#else
+ return x86GetSupportedArchitectureAtIndex (idx, arch);
+#endif
+}
+
+lldb_private::Error
+PlatformMacOSX::GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ Process* process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ Error error = GetSharedModuleWithLocalCache(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
+
+ if (module_sp)
+ {
+ if (module_spec.GetArchitecture().GetCore() == ArchSpec::eCore_x86_64_x86_64h)
+ {
+ ObjectFile *objfile = module_sp->GetObjectFile();
+ if (objfile == NULL)
+ {
+ // We didn't find an x86_64h slice, fall back to a x86_64 slice
+ ModuleSpec module_spec_x86_64 (module_spec);
+ module_spec_x86_64.GetArchitecture() = ArchSpec("x86_64-apple-macosx");
+ lldb::ModuleSP x86_64_module_sp;
+ lldb::ModuleSP old_x86_64_module_sp;
+ bool did_create = false;
+ Error x86_64_error = GetSharedModuleWithLocalCache(module_spec_x86_64, x86_64_module_sp, module_search_paths_ptr, &old_x86_64_module_sp, &did_create);
+ if (x86_64_module_sp && x86_64_module_sp->GetObjectFile())
+ {
+ module_sp = x86_64_module_sp;
+ if (old_module_sp_ptr)
+ *old_module_sp_ptr = old_x86_64_module_sp;
+ if (did_create_ptr)
+ *did_create_ptr = did_create;
+ return x86_64_error;
+ }
+ }
+ }
+ }
+ return error;
+}
+
diff --git a/source/Plugins/Platform/MacOSX/PlatformMacOSX.h b/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
new file mode 100644
index 000000000000..10e177ea6362
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
@@ -0,0 +1,104 @@
+//===-- PlatformMacOSX.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_PlatformMacOSX_h_
+#define liblldb_PlatformMacOSX_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "PlatformDarwin.h"
+
+class PlatformMacOSX : public PlatformDarwin
+{
+public:
+ PlatformMacOSX(bool is_host);
+
+ ~PlatformMacOSX() override;
+
+ //------------------------------------------------------------
+ // Class functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic (bool is_host);
+
+ static const char *
+ GetDescriptionStatic(bool is_host);
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override
+ {
+ return GetPluginNameStatic (IsHost());
+ }
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ const char *
+ GetDescription () override
+ {
+ return GetDescriptionStatic (IsHost());
+ }
+
+ lldb_private::Error
+ GetSymbolFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
+
+ lldb_private::Error
+ GetFile (const lldb_private::FileSpec& source,
+ const lldb_private::FileSpec& destination) override
+ {
+ return PlatformDarwin::GetFile (source,destination);
+ }
+
+ lldb_private::Error
+ GetFileWithUUID (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file) override;
+
+ bool GetSupportedArchitectureAtIndex(uint32_t idx, lldb_private::ArchSpec &arch) override;
+
+ lldb_private::ConstString GetSDKDirectory(lldb_private::Target &target) override;
+
+ void
+ AddClangModuleCompilationOptions (lldb_private::Target *target, std::vector<std::string> &options) override
+ {
+ return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(target, options, PlatformDarwin::SDKType::MacOSX);
+ }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformMacOSX);
+};
+
+#endif // liblldb_PlatformMacOSX_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp
new file mode 100644
index 000000000000..04231f27ff9b
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp
@@ -0,0 +1,912 @@
+//===-- PlatformRemoteAppleTV.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "PlatformRemoteAppleTV.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformRemoteAppleTV::PlatformRemoteAppleTV () :
+ PlatformDarwin (false), // This is a remote platform
+ m_sdk_directory_infos(),
+ m_device_support_directory(),
+ m_device_support_directory_for_os_version (),
+ m_build_update(),
+ m_last_module_sdk_idx (UINT32_MAX),
+ m_connected_module_sdk_idx (UINT32_MAX)
+{
+}
+
+PlatformRemoteAppleTV::SDKDirectoryInfo::SDKDirectoryInfo (const lldb_private::FileSpec &sdk_dir) :
+ directory(sdk_dir),
+ build(),
+ version_major(0),
+ version_minor(0),
+ version_update(0),
+ user_cached(false)
+{
+ const char *dirname_cstr = sdk_dir.GetFilename().GetCString();
+ const char *pos = Args::StringToVersion (dirname_cstr,
+ version_major,
+ version_minor,
+ version_update);
+
+ if (pos && pos[0] == ' ' && pos[1] == '(')
+ {
+ const char *build_start = pos + 2;
+ const char *end_paren = strchr (build_start, ')');
+ if (end_paren && build_start < end_paren)
+ build.SetCStringWithLength(build_start, end_paren - build_start);
+ }
+}
+
+//------------------------------------------------------------------
+// Static Variables
+//------------------------------------------------------------------
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+void
+PlatformRemoteAppleTV::Initialize ()
+{
+ PlatformDarwin::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+ PluginManager::RegisterPlugin (PlatformRemoteAppleTV::GetPluginNameStatic(),
+ PlatformRemoteAppleTV::GetDescriptionStatic(),
+ PlatformRemoteAppleTV::CreateInstance);
+ }
+}
+
+void
+PlatformRemoteAppleTV::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformRemoteAppleTV::CreateInstance);
+ }
+ }
+
+ PlatformDarwin::Terminate ();
+}
+
+PlatformSP
+PlatformRemoteAppleTV::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformRemoteAppleTV::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ bool create = force;
+ if (!create && arch && arch->IsValid())
+ {
+ switch (arch->GetMachine())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::thumb:
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ llvm::Triple::VendorType vendor = triple.getVendor();
+ switch (vendor)
+ {
+ case llvm::Triple::Apple:
+ create = true;
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the vendor if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+
+#endif
+ default:
+ break;
+ }
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::TvOS: // This is the right triple value for Apple TV debugging
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the OS if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformRemoteAppleTV::%s() creating platform", __FUNCTION__);
+
+ return lldb::PlatformSP(new PlatformRemoteAppleTV ());
+ }
+
+ if (log)
+ log->Printf ("PlatformRemoteAppleTV::%s() aborting creation of platform", __FUNCTION__);
+
+ return lldb::PlatformSP();
+}
+
+lldb_private::ConstString
+PlatformRemoteAppleTV::GetPluginNameStatic ()
+{
+ static ConstString g_name("remote-tvos");
+ return g_name;
+}
+
+const char *
+PlatformRemoteAppleTV::GetDescriptionStatic()
+{
+ return "Remote Apple TV platform plug-in.";
+}
+
+void
+PlatformRemoteAppleTV::GetStatus (Stream &strm)
+{
+ Platform::GetStatus (strm);
+ const char *sdk_directory = GetDeviceSupportDirectoryForOSVersion();
+ if (sdk_directory)
+ strm.Printf (" SDK Path: \"%s\"\n", sdk_directory);
+ else
+ strm.PutCString (" SDK Path: error: unable to locate SDK\n");
+
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ for (uint32_t i=0; i<num_sdk_infos; ++i)
+ {
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
+ strm.Printf (" SDK Roots: [%2u] \"%s\"\n",
+ i,
+ sdk_dir_info.directory.GetPath().c_str());
+ }
+}
+
+Error
+PlatformRemoteAppleTV::ResolveExecutable (const ModuleSpec &ms,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ ModuleSpec resolved_module_spec(ms);
+
+ // Resolve any executable within a bundle on MacOSX
+ // TODO: verify that this handles shallow bundles, if not then implement one ourselves
+ Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ {
+ if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid())
+ {
+ error = ModuleList::GetSharedModule(resolved_module_spec,
+ exe_module_sp,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ return error;
+ exe_module_sp.reset();
+ }
+ // No valid architecture was specified or the exact ARM slice wasn't
+ // found so ask the platform for the architectures that we should be
+ // using (in the correct order) and see if we can find a match that way
+ StreamString arch_names;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
+ {
+ error = ModuleList::GetSharedModule(resolved_module_spec,
+ exe_module_sp,
+ nullptr,
+ nullptr,
+ nullptr);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ if (resolved_module_spec.GetFileSpec().Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("'%s' does not exist",
+ resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+
+ return error;
+}
+
+FileSpec::EnumerateDirectoryResult
+PlatformRemoteAppleTV::GetContainedFilesIntoVectorOfStringsCallback (void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &file_spec)
+{
+ ((PlatformRemoteAppleTV::SDKDirectoryInfoCollection *)baton)->push_back(PlatformRemoteAppleTV::SDKDirectoryInfo(file_spec));
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+bool
+PlatformRemoteAppleTV::UpdateSDKDirectoryInfosIfNeeded()
+{
+ if (m_sdk_directory_infos.empty())
+ {
+ const char *device_support_dir = GetDeviceSupportDirectory();
+ if (device_support_dir)
+ {
+ const bool find_directories = true;
+ const bool find_files = false;
+ const bool find_other = false;
+
+ SDKDirectoryInfoCollection builtin_sdk_directory_infos;
+ FileSpec::EnumerateDirectory (m_device_support_directory.c_str(),
+ find_directories,
+ find_files,
+ find_other,
+ GetContainedFilesIntoVectorOfStringsCallback,
+ &builtin_sdk_directory_infos);
+
+ // Only add SDK directories that have symbols in them, some SDKs only contain
+ // developer disk images and no symbols, so they aren't useful to us.
+ FileSpec sdk_symbols_symlink_fspec;
+ for (const auto &sdk_directory_info : builtin_sdk_directory_infos)
+ {
+ sdk_symbols_symlink_fspec = sdk_directory_info.directory;
+ sdk_symbols_symlink_fspec.AppendPathComponent("Symbols.Internal");
+ if (sdk_symbols_symlink_fspec.Exists())
+ {
+ m_sdk_directory_infos.push_back(sdk_directory_info);
+ }
+ else
+ {
+ sdk_symbols_symlink_fspec.GetFilename().SetCString("Symbols");
+ if (sdk_symbols_symlink_fspec.Exists())
+ m_sdk_directory_infos.push_back(sdk_directory_info);
+ }
+ }
+
+ const uint32_t num_installed = m_sdk_directory_infos.size();
+ FileSpec local_sdk_cache("~/Library/Developer/Xcode/tvOS DeviceSupport", true);
+ if (!local_sdk_cache.Exists())
+ {
+ // Try looking for another possible name
+ local_sdk_cache = FileSpec("~/Library/Developer/Xcode/Apple TVOS DeviceSupport", true);
+ }
+ if (!local_sdk_cache.Exists())
+ {
+ // Try looking for another possible name
+ local_sdk_cache = FileSpec("~/Library/Developer/Xcode/AppleTVOS DeviceSupport", true);
+ }
+ if (!local_sdk_cache.Exists())
+ {
+ // Try looking for another possible name
+ local_sdk_cache = FileSpec("~/Library/Developer/Xcode/AppleTV OS DeviceSupport", true);
+ }
+ if (!local_sdk_cache.Exists())
+ {
+ // Try looking for another possible name
+ local_sdk_cache = FileSpec("~/Library/Developer/Xcode/Apple TV OS DeviceSupport", true);
+ }
+ if (local_sdk_cache.Exists())
+ {
+ char path[PATH_MAX];
+ if (local_sdk_cache.GetPath(path, sizeof(path)))
+ {
+ FileSpec::EnumerateDirectory (path,
+ find_directories,
+ find_files,
+ find_other,
+ GetContainedFilesIntoVectorOfStringsCallback,
+ &m_sdk_directory_infos);
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ // First try for an exact match of major, minor and update
+ for (uint32_t i=num_installed; i<num_sdk_infos; ++i)
+ {
+ m_sdk_directory_infos[i].user_cached = true;
+ }
+ }
+ }
+ }
+ }
+ return !m_sdk_directory_infos.empty();
+}
+
+const PlatformRemoteAppleTV::SDKDirectoryInfo *
+PlatformRemoteAppleTV::GetSDKDirectoryForCurrentOSVersion ()
+{
+ uint32_t i;
+ if (UpdateSDKDirectoryInfosIfNeeded())
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+
+ // Check to see if the user specified a build string. If they did, then
+ // be sure to match it.
+ std::vector<bool> check_sdk_info(num_sdk_infos, true);
+ ConstString build(m_sdk_build);
+ if (build)
+ {
+ for (i=0; i<num_sdk_infos; ++i)
+ check_sdk_info[i] = m_sdk_directory_infos[i].build == build;
+ }
+
+ // If we are connected we can find the version of the OS the platform
+ // us running on and select the right SDK
+ uint32_t major, minor, update;
+ if (GetOSVersion(major, minor, update))
+ {
+ if (UpdateSDKDirectoryInfosIfNeeded())
+ {
+ // First try for an exact match of major, minor and update
+ for (i=0; i<num_sdk_infos; ++i)
+ {
+ if (check_sdk_info[i])
+ {
+ if (m_sdk_directory_infos[i].version_major == major &&
+ m_sdk_directory_infos[i].version_minor == minor &&
+ m_sdk_directory_infos[i].version_update == update)
+ {
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ }
+ // First try for an exact match of major and minor
+ for (i=0; i<num_sdk_infos; ++i)
+ {
+ if (check_sdk_info[i])
+ {
+ if (m_sdk_directory_infos[i].version_major == major &&
+ m_sdk_directory_infos[i].version_minor == minor)
+ {
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ }
+ // Lastly try to match of major version only..
+ for (i=0; i<num_sdk_infos; ++i)
+ {
+ if (check_sdk_info[i])
+ {
+ if (m_sdk_directory_infos[i].version_major == major)
+ {
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ }
+ }
+ }
+ else if (build)
+ {
+ // No version, just a build number, search for the first one that matches
+ for (i=0; i<num_sdk_infos; ++i)
+ if (check_sdk_info[i])
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ return nullptr;
+}
+
+const PlatformRemoteAppleTV::SDKDirectoryInfo *
+PlatformRemoteAppleTV::GetSDKDirectoryForLatestOSVersion ()
+{
+ const PlatformRemoteAppleTV::SDKDirectoryInfo *result = nullptr;
+ if (UpdateSDKDirectoryInfosIfNeeded())
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ // First try for an exact match of major, minor and update
+ for (uint32_t i=0; i<num_sdk_infos; ++i)
+ {
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
+ if (sdk_dir_info.version_major != UINT32_MAX)
+ {
+ if (result == nullptr || sdk_dir_info.version_major > result->version_major)
+ {
+ result = &sdk_dir_info;
+ }
+ else if (sdk_dir_info.version_major == result->version_major)
+ {
+ if (sdk_dir_info.version_minor > result->version_minor)
+ {
+ result = &sdk_dir_info;
+ }
+ else if (sdk_dir_info.version_minor == result->version_minor)
+ {
+ if (sdk_dir_info.version_update > result->version_update)
+ {
+ result = &sdk_dir_info;
+ }
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+const char *
+PlatformRemoteAppleTV::GetDeviceSupportDirectory()
+{
+ if (m_device_support_directory.empty())
+ {
+ const char *device_support_dir = GetDeveloperDirectory();
+ if (device_support_dir)
+ {
+ m_device_support_directory.assign (device_support_dir);
+ m_device_support_directory.append ("/Platforms/AppleTVOS.platform/DeviceSupport");
+ }
+ else
+ {
+ // Assign a single NULL character so we know we tried to find the device
+ // support directory and we don't keep trying to find it over and over.
+ m_device_support_directory.assign (1, '\0');
+ }
+ }
+ // We should have put a single NULL character into m_device_support_directory
+ // or it should have a valid path if the code gets here
+ assert (m_device_support_directory.empty() == false);
+ if (m_device_support_directory[0])
+ return m_device_support_directory.c_str();
+ return nullptr;
+}
+
+const char *
+PlatformRemoteAppleTV::GetDeviceSupportDirectoryForOSVersion()
+{
+ if (m_sdk_sysroot)
+ return m_sdk_sysroot.GetCString();
+
+ if (m_device_support_directory_for_os_version.empty())
+ {
+ const PlatformRemoteAppleTV::SDKDirectoryInfo *sdk_dir_info = GetSDKDirectoryForCurrentOSVersion ();
+ if (sdk_dir_info == nullptr)
+ sdk_dir_info = GetSDKDirectoryForLatestOSVersion ();
+ if (sdk_dir_info)
+ {
+ char path[PATH_MAX];
+ if (sdk_dir_info->directory.GetPath(path, sizeof(path)))
+ {
+ m_device_support_directory_for_os_version = path;
+ return m_device_support_directory_for_os_version.c_str();
+ }
+ }
+ else
+ {
+ // Assign a single NULL character so we know we tried to find the device
+ // support directory and we don't keep trying to find it over and over.
+ m_device_support_directory_for_os_version.assign (1, '\0');
+ }
+ }
+ // We should have put a single NULL character into m_device_support_directory_for_os_version
+ // or it should have a valid path if the code gets here
+ assert (m_device_support_directory_for_os_version.empty() == false);
+ if (m_device_support_directory_for_os_version[0])
+ return m_device_support_directory_for_os_version.c_str();
+ return nullptr;
+}
+
+uint32_t
+PlatformRemoteAppleTV::FindFileInAllSDKs (const char *platform_file_path,
+ FileSpecList &file_list)
+{
+ if (platform_file_path && platform_file_path[0] && UpdateSDKDirectoryInfosIfNeeded())
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ lldb_private::FileSpec local_file;
+ // First try for an exact match of major, minor and update
+ for (uint32_t sdk_idx=0; sdk_idx<num_sdk_infos; ++sdk_idx)
+ {
+ if (GetFileInSDK (platform_file_path,
+ sdk_idx,
+ local_file))
+ {
+ file_list.Append(local_file);
+ }
+ }
+ }
+ return file_list.GetSize();
+}
+
+bool
+PlatformRemoteAppleTV::GetFileInSDK (const char *platform_file_path,
+ uint32_t sdk_idx,
+ lldb_private::FileSpec &local_file)
+{
+ if (sdk_idx < m_sdk_directory_infos.size())
+ {
+ char sdkroot_path[PATH_MAX];
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[sdk_idx];
+ if (sdk_dir_info.directory.GetPath(sdkroot_path, sizeof(sdkroot_path)))
+ {
+ const bool symbols_dirs_only = true;
+
+ return GetFileInSDKRoot (platform_file_path,
+ sdkroot_path,
+ symbols_dirs_only,
+ local_file);
+ }
+ }
+ return false;
+}
+
+bool
+PlatformRemoteAppleTV::GetFileInSDKRoot (const char *platform_file_path,
+ const char *sdkroot_path,
+ bool symbols_dirs_only,
+ lldb_private::FileSpec &local_file)
+{
+ if (sdkroot_path && sdkroot_path[0] && platform_file_path && platform_file_path[0])
+ {
+ char resolved_path[PATH_MAX];
+
+ if (!symbols_dirs_only)
+ {
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s%s",
+ sdkroot_path,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return true;
+ }
+
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols.Internal%s",
+ sdkroot_path,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return true;
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols%s",
+ sdkroot_path,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return true;
+ }
+ return false;
+}
+
+Error
+PlatformRemoteAppleTV::GetSymbolFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ Error error;
+ char platform_file_path[PATH_MAX];
+ if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
+ {
+ char resolved_path[PATH_MAX];
+
+ const char * os_version_dir = GetDeviceSupportDirectoryForOSVersion();
+ if (os_version_dir)
+ {
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/%s",
+ os_version_dir,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return error;
+
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols.Internal/%s",
+ os_version_dir,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return error;
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols/%s",
+ os_version_dir,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return error;
+
+ }
+ local_file = platform_file;
+ if (local_file.Exists())
+ return error;
+
+ error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'",
+ platform_file_path,
+ GetPluginName().GetCString());
+ }
+ else
+ {
+ error.SetErrorString ("invalid platform file argument");
+ }
+ return error;
+}
+
+Error
+PlatformRemoteAppleTV::GetSharedModule (const ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ // For Apple TV, the SDK files are all cached locally on the host
+ // system. So first we ask for the file in the cached SDK,
+ // then we attempt to get a shared module for the right architecture
+ // with the right UUID.
+ const FileSpec &platform_file = module_spec.GetFileSpec();
+
+ Error error;
+ char platform_file_path[PATH_MAX];
+
+ if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
+ {
+ ModuleSpec platform_module_spec(module_spec);
+
+ UpdateSDKDirectoryInfosIfNeeded();
+
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+
+ // If we are connected we migth be able to correctly deduce the SDK directory
+ // using the OS build.
+ const uint32_t connected_sdk_idx = GetConnectedSDKIndex ();
+ if (connected_sdk_idx < num_sdk_infos)
+ {
+ if (GetFileInSDK (platform_file_path, connected_sdk_idx, platform_module_spec.GetFileSpec()))
+ {
+ module_sp.reset();
+ error = ResolveExecutable(platform_module_spec,
+ module_sp,
+ nullptr);
+ if (module_sp)
+ {
+ m_last_module_sdk_idx = connected_sdk_idx;
+ error.Clear();
+ return error;
+ }
+ }
+ }
+
+ // Try the last SDK index if it is set as most files from an SDK
+ // will tend to be valid in that same SDK.
+ if (m_last_module_sdk_idx < num_sdk_infos)
+ {
+ if (GetFileInSDK (platform_file_path, m_last_module_sdk_idx, platform_module_spec.GetFileSpec()))
+ {
+ module_sp.reset();
+ error = ResolveExecutable(platform_module_spec,
+ module_sp,
+ nullptr);
+ if (module_sp)
+ {
+ error.Clear();
+ return error;
+ }
+ }
+ }
+
+ // First try for an exact match of major, minor and update
+ for (uint32_t sdk_idx=0; sdk_idx<num_sdk_infos; ++sdk_idx)
+ {
+ if (m_last_module_sdk_idx == sdk_idx)
+ {
+ // Skip the last module SDK index if we already searched
+ // it above
+ continue;
+ }
+ if (GetFileInSDK (platform_file_path, sdk_idx, platform_module_spec.GetFileSpec()))
+ {
+ //printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str());
+
+ error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
+ if (module_sp)
+ {
+ // Remember the index of the last SDK that we found a file
+ // in in case the wrong SDK was selected.
+ m_last_module_sdk_idx = sdk_idx;
+ error.Clear();
+ return error;
+ }
+ }
+ }
+ }
+ // Not the module we are looking for... Nothing to see here...
+ module_sp.reset();
+
+ // This may not be an SDK-related module. Try whether we can bring in the thing to our local cache.
+ error = GetSharedModuleWithLocalCache(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
+ if (error.Success())
+ return error;
+
+ const bool always_create = false;
+ error = ModuleList::GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr,
+ always_create);
+
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(platform_file);
+
+ return error;
+}
+
+bool
+PlatformRemoteAppleTV::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ ArchSpec system_arch (GetSystemArchitecture());
+
+ const ArchSpec::Core system_core = system_arch.GetCore();
+ switch (system_core)
+ {
+ default:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("arm64-apple-tvos"); return true;
+ case 1: arch.SetTriple ("armv7s-apple-tvos"); return true;
+ case 2: arch.SetTriple ("armv7-apple-tvos"); return true;
+ case 3: arch.SetTriple ("thumbv7s-apple-tvos"); return true;
+ case 4: arch.SetTriple ("thumbv7-apple-tvos"); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_arm64:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("arm64-apple-tvos"); return true;
+ case 1: arch.SetTriple ("armv7s-apple-tvos"); return true;
+ case 2: arch.SetTriple ("armv7-apple-tvos"); return true;
+ case 3: arch.SetTriple ("thumbv7s-apple-tvos"); return true;
+ case 4: arch.SetTriple ("thumbv7-apple-tvos"); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7s:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7s-apple-tvos"); return true;
+ case 1: arch.SetTriple ("armv7-apple-tvos"); return true;
+ case 2: arch.SetTriple ("thumbv7s-apple-tvos"); return true;
+ case 3: arch.SetTriple ("thumbv7-apple-tvos"); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7-apple-tvos"); return true;
+ case 1: arch.SetTriple ("thumbv7-apple-tvos"); return true;
+ default: break;
+ }
+ break;
+ }
+ arch.Clear();
+ return false;
+}
+
+uint32_t
+PlatformRemoteAppleTV::GetConnectedSDKIndex ()
+{
+ if (IsConnected())
+ {
+ if (m_connected_module_sdk_idx == UINT32_MAX)
+ {
+ std::string build;
+ if (GetRemoteOSBuildString(build))
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ for (uint32_t i=0; i<num_sdk_infos; ++i)
+ {
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
+ if (strstr(sdk_dir_info.directory.GetFilename().AsCString(""), build.c_str()))
+ {
+ m_connected_module_sdk_idx = i;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ m_connected_module_sdk_idx = UINT32_MAX;
+ }
+ return m_connected_module_sdk_idx;
+}
diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h
new file mode 100644
index 000000000000..28bd9df0fad7
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h
@@ -0,0 +1,171 @@
+//===-- PlatformRemoteAppleTV.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_PlatformRemoteAppleTV_h_
+#define liblldb_PlatformRemoteAppleTV_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/FileSpec.h"
+
+#include "PlatformDarwin.h"
+
+class PlatformRemoteAppleTV : public PlatformDarwin
+{
+public:
+ PlatformRemoteAppleTV();
+
+ ~PlatformRemoteAppleTV() override = default;
+
+ //------------------------------------------------------------
+ // Class Functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ static const char *
+ GetDescriptionStatic();
+
+ //------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override
+ {
+ return GetPluginNameStatic();
+ }
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ lldb_private::Error
+ ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr) override;
+
+ const char *
+ GetDescription () override
+ {
+ return GetDescriptionStatic();
+ }
+
+ void
+ GetStatus (lldb_private::Stream &strm) override;
+
+ virtual lldb_private::Error
+ GetSymbolFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ bool
+ GetSupportedArchitectureAtIndex (uint32_t idx,
+ lldb_private::ArchSpec &arch) override;
+
+ void
+ AddClangModuleCompilationOptions (lldb_private::Target *target, std::vector<std::string> &options) override
+ {
+ return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(target, options, PlatformDarwin::SDKType::iPhoneOS);
+ }
+
+protected:
+ struct SDKDirectoryInfo
+ {
+ SDKDirectoryInfo (const lldb_private::FileSpec &sdk_dir_spec);
+ lldb_private::FileSpec directory;
+ lldb_private::ConstString build;
+ uint32_t version_major;
+ uint32_t version_minor;
+ uint32_t version_update;
+ bool user_cached;
+ };
+ typedef std::vector<SDKDirectoryInfo> SDKDirectoryInfoCollection;
+ SDKDirectoryInfoCollection m_sdk_directory_infos;
+ std::string m_device_support_directory;
+ std::string m_device_support_directory_for_os_version;
+ std::string m_build_update;
+ uint32_t m_last_module_sdk_idx;
+ uint32_t m_connected_module_sdk_idx;
+
+ bool
+ UpdateSDKDirectoryInfosIfNeeded();
+
+ const char *
+ GetDeviceSupportDirectory();
+
+ const char *
+ GetDeviceSupportDirectoryForOSVersion();
+
+ const SDKDirectoryInfo *
+ GetSDKDirectoryForLatestOSVersion ();
+
+ const SDKDirectoryInfo *
+ GetSDKDirectoryForCurrentOSVersion ();
+
+ static lldb_private::FileSpec::EnumerateDirectoryResult
+ GetContainedFilesIntoVectorOfStringsCallback (void *baton,
+ lldb_private::FileSpec::FileType file_type,
+ const lldb_private::FileSpec &file_spec);
+
+ uint32_t
+ FindFileInAllSDKs (const char *platform_file_path,
+ lldb_private::FileSpecList &file_list);
+
+ bool
+ GetFileInSDK (const char *platform_file_path,
+ uint32_t sdk_idx,
+ lldb_private::FileSpec &local_file);
+
+ bool
+ GetFileInSDKRoot (const char *platform_file_path,
+ const char *sdkroot_path,
+ bool symbols_dirs_only,
+ lldb_private::FileSpec &local_file);
+
+ uint32_t
+ FindFileInAllSDKs (const lldb_private::FileSpec &platform_file,
+ lldb_private::FileSpecList &file_list);
+
+ uint32_t
+ GetConnectedSDKIndex ();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformRemoteAppleTV);
+};
+
+#endif // liblldb_PlatformRemoteAppleTV_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp
new file mode 100644
index 000000000000..808fd96a5284
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp
@@ -0,0 +1,944 @@
+//===-- PlatformRemoteAppleWatch.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "PlatformRemoteAppleWatch.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformRemoteAppleWatch::PlatformRemoteAppleWatch () :
+ PlatformDarwin (false), // This is a remote platform
+ m_sdk_directory_infos(),
+ m_device_support_directory(),
+ m_device_support_directory_for_os_version (),
+ m_build_update(),
+ m_last_module_sdk_idx (UINT32_MAX),
+ m_connected_module_sdk_idx (UINT32_MAX)
+{
+}
+
+PlatformRemoteAppleWatch::SDKDirectoryInfo::SDKDirectoryInfo (const lldb_private::FileSpec &sdk_dir) :
+ directory(sdk_dir),
+ build(),
+ version_major(0),
+ version_minor(0),
+ version_update(0),
+ user_cached(false)
+{
+ const char *dirname_cstr = sdk_dir.GetFilename().GetCString();
+ const char *pos = Args::StringToVersion (dirname_cstr,
+ version_major,
+ version_minor,
+ version_update);
+
+ if (pos && pos[0] == ' ' && pos[1] == '(')
+ {
+ const char *build_start = pos + 2;
+ const char *end_paren = strchr (build_start, ')');
+ if (end_paren && build_start < end_paren)
+ build.SetCStringWithLength(build_start, end_paren - build_start);
+ }
+}
+
+//------------------------------------------------------------------
+// Static Variables
+//------------------------------------------------------------------
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+void
+PlatformRemoteAppleWatch::Initialize ()
+{
+ PlatformDarwin::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+ PluginManager::RegisterPlugin (PlatformRemoteAppleWatch::GetPluginNameStatic(),
+ PlatformRemoteAppleWatch::GetDescriptionStatic(),
+ PlatformRemoteAppleWatch::CreateInstance);
+ }
+}
+
+void
+PlatformRemoteAppleWatch::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformRemoteAppleWatch::CreateInstance);
+ }
+ }
+
+ PlatformDarwin::Terminate ();
+}
+
+PlatformSP
+PlatformRemoteAppleWatch::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformRemoteAppleWatch::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ bool create = force;
+ if (!create && arch && arch->IsValid())
+ {
+ switch (arch->GetMachine())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::thumb:
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ llvm::Triple::VendorType vendor = triple.getVendor();
+ switch (vendor)
+ {
+ case llvm::Triple::Apple:
+ create = true;
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the vendor if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+
+#endif
+ default:
+ break;
+ }
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::WatchOS: // This is the right triple value for Apple Watch debugging
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the OS if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
+ // If lldb is running on a watch, this isn't a RemoteWatch environment; it's a local system environment.
+ if (force == false)
+ {
+ create = false;
+ }
+#endif
+
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformRemoteAppleWatch::%s() creating platform", __FUNCTION__);
+
+ return lldb::PlatformSP(new PlatformRemoteAppleWatch ());
+ }
+
+ if (log)
+ log->Printf ("PlatformRemoteAppleWatch::%s() aborting creation of platform", __FUNCTION__);
+
+ return lldb::PlatformSP();
+}
+
+lldb_private::ConstString
+PlatformRemoteAppleWatch::GetPluginNameStatic ()
+{
+ static ConstString g_name("remote-watchos");
+ return g_name;
+}
+
+const char *
+PlatformRemoteAppleWatch::GetDescriptionStatic()
+{
+ return "Remote Apple Watch platform plug-in.";
+}
+
+void
+PlatformRemoteAppleWatch::GetStatus (Stream &strm)
+{
+ Platform::GetStatus (strm);
+ const char *sdk_directory = GetDeviceSupportDirectoryForOSVersion();
+ if (sdk_directory)
+ strm.Printf (" SDK Path: \"%s\"\n", sdk_directory);
+ else
+ strm.PutCString (" SDK Path: error: unable to locate SDK\n");
+
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ for (uint32_t i=0; i<num_sdk_infos; ++i)
+ {
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
+ strm.Printf (" SDK Roots: [%2u] \"%s\"\n",
+ i,
+ sdk_dir_info.directory.GetPath().c_str());
+ }
+}
+
+Error
+PlatformRemoteAppleWatch::ResolveExecutable (const ModuleSpec &ms,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ ModuleSpec resolved_module_spec(ms);
+
+ // Resolve any executable within a bundle on MacOSX
+ // TODO: verify that this handles shallow bundles, if not then implement one ourselves
+ Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ {
+ if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid())
+ {
+ error = ModuleList::GetSharedModule(resolved_module_spec,
+ exe_module_sp,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ return error;
+ exe_module_sp.reset();
+ }
+ // No valid architecture was specified or the exact ARM slice wasn't
+ // found so ask the platform for the architectures that we should be
+ // using (in the correct order) and see if we can find a match that way
+ StreamString arch_names;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
+ {
+ error = ModuleList::GetSharedModule(resolved_module_spec,
+ exe_module_sp,
+ nullptr,
+ nullptr,
+ nullptr);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ if (resolved_module_spec.GetFileSpec().Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("'%s' does not exist",
+ resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+
+ return error;
+}
+
+FileSpec::EnumerateDirectoryResult
+PlatformRemoteAppleWatch::GetContainedFilesIntoVectorOfStringsCallback (void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &file_spec)
+{
+ ((PlatformRemoteAppleWatch::SDKDirectoryInfoCollection *)baton)->push_back(PlatformRemoteAppleWatch::SDKDirectoryInfo(file_spec));
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+bool
+PlatformRemoteAppleWatch::UpdateSDKDirectoryInfosIfNeeded()
+{
+ if (m_sdk_directory_infos.empty())
+ {
+ const char *device_support_dir = GetDeviceSupportDirectory();
+ if (device_support_dir)
+ {
+ const bool find_directories = true;
+ const bool find_files = false;
+ const bool find_other = false;
+
+ SDKDirectoryInfoCollection builtin_sdk_directory_infos;
+ FileSpec::EnumerateDirectory (m_device_support_directory.c_str(),
+ find_directories,
+ find_files,
+ find_other,
+ GetContainedFilesIntoVectorOfStringsCallback,
+ &builtin_sdk_directory_infos);
+
+ // Only add SDK directories that have symbols in them, some SDKs only contain
+ // developer disk images and no symbols, so they aren't useful to us.
+ FileSpec sdk_symbols_symlink_fspec;
+ for (const auto &sdk_directory_info : builtin_sdk_directory_infos)
+ {
+ sdk_symbols_symlink_fspec = sdk_directory_info.directory;
+ sdk_symbols_symlink_fspec.AppendPathComponent("Symbols.Internal");
+ if (sdk_symbols_symlink_fspec.Exists())
+ {
+ m_sdk_directory_infos.push_back(sdk_directory_info);
+ }
+ else
+ {
+ sdk_symbols_symlink_fspec.GetFilename().SetCString("Symbols");
+ if (sdk_symbols_symlink_fspec.Exists())
+ m_sdk_directory_infos.push_back(sdk_directory_info);
+ }
+ }
+
+ const uint32_t num_installed = m_sdk_directory_infos.size();
+ FileSpec local_sdk_cache("~/Library/Developer/Xcode/watchOS DeviceSupport", true);
+ if (!local_sdk_cache.Exists())
+ {
+ local_sdk_cache = FileSpec("~/Library/Developer/Xcode/watch OS DeviceSupport", true);
+ }
+ if (!local_sdk_cache.Exists())
+ {
+ local_sdk_cache = FileSpec("~/Library/Developer/Xcode/WatchOS DeviceSupport", true);
+ }
+ if (!local_sdk_cache.Exists())
+ {
+ local_sdk_cache = FileSpec("~/Library/Developer/Xcode/Watch OS DeviceSupport", true);
+ }
+ if (local_sdk_cache.Exists())
+ {
+ char path[PATH_MAX];
+ if (local_sdk_cache.GetPath(path, sizeof(path)))
+ {
+ FileSpec::EnumerateDirectory (path,
+ find_directories,
+ find_files,
+ find_other,
+ GetContainedFilesIntoVectorOfStringsCallback,
+ &m_sdk_directory_infos);
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ // First try for an exact match of major, minor and update
+ for (uint32_t i=num_installed; i<num_sdk_infos; ++i)
+ {
+ m_sdk_directory_infos[i].user_cached = true;
+ }
+ }
+ }
+ }
+ }
+ return !m_sdk_directory_infos.empty();
+}
+
+const PlatformRemoteAppleWatch::SDKDirectoryInfo *
+PlatformRemoteAppleWatch::GetSDKDirectoryForCurrentOSVersion ()
+{
+ uint32_t i;
+ if (UpdateSDKDirectoryInfosIfNeeded())
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+
+ // Check to see if the user specified a build string. If they did, then
+ // be sure to match it.
+ std::vector<bool> check_sdk_info(num_sdk_infos, true);
+ ConstString build(m_sdk_build);
+ if (build)
+ {
+ for (i=0; i<num_sdk_infos; ++i)
+ check_sdk_info[i] = m_sdk_directory_infos[i].build == build;
+ }
+
+ // If we are connected we can find the version of the OS the platform
+ // us running on and select the right SDK
+ uint32_t major, minor, update;
+ if (GetOSVersion(major, minor, update))
+ {
+ if (UpdateSDKDirectoryInfosIfNeeded())
+ {
+ // First try for an exact match of major, minor and update
+ for (i=0; i<num_sdk_infos; ++i)
+ {
+ if (check_sdk_info[i])
+ {
+ if (m_sdk_directory_infos[i].version_major == major &&
+ m_sdk_directory_infos[i].version_minor == minor &&
+ m_sdk_directory_infos[i].version_update == update)
+ {
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ }
+ // First try for an exact match of major and minor
+ for (i=0; i<num_sdk_infos; ++i)
+ {
+ if (check_sdk_info[i])
+ {
+ if (m_sdk_directory_infos[i].version_major == major &&
+ m_sdk_directory_infos[i].version_minor == minor)
+ {
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ }
+ // Lastly try to match of major version only..
+ for (i=0; i<num_sdk_infos; ++i)
+ {
+ if (check_sdk_info[i])
+ {
+ if (m_sdk_directory_infos[i].version_major == major)
+ {
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ }
+ }
+ }
+ else if (build)
+ {
+ // No version, just a build number, search for the first one that matches
+ for (i=0; i<num_sdk_infos; ++i)
+ if (check_sdk_info[i])
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ return nullptr;
+}
+
+const PlatformRemoteAppleWatch::SDKDirectoryInfo *
+PlatformRemoteAppleWatch::GetSDKDirectoryForLatestOSVersion ()
+{
+ const PlatformRemoteAppleWatch::SDKDirectoryInfo *result = nullptr;
+ if (UpdateSDKDirectoryInfosIfNeeded())
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ // First try for an exact match of major, minor and update
+ for (uint32_t i=0; i<num_sdk_infos; ++i)
+ {
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
+ if (sdk_dir_info.version_major != UINT32_MAX)
+ {
+ if (result == nullptr || sdk_dir_info.version_major > result->version_major)
+ {
+ result = &sdk_dir_info;
+ }
+ else if (sdk_dir_info.version_major == result->version_major)
+ {
+ if (sdk_dir_info.version_minor > result->version_minor)
+ {
+ result = &sdk_dir_info;
+ }
+ else if (sdk_dir_info.version_minor == result->version_minor)
+ {
+ if (sdk_dir_info.version_update > result->version_update)
+ {
+ result = &sdk_dir_info;
+ }
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+const char *
+PlatformRemoteAppleWatch::GetDeviceSupportDirectory()
+{
+ if (m_device_support_directory.empty())
+ {
+ const char *device_support_dir = GetDeveloperDirectory();
+ if (device_support_dir)
+ {
+ m_device_support_directory.assign (device_support_dir);
+ m_device_support_directory.append ("/Platforms/watchOS.platform/DeviceSupport");
+ FileSpec platform_device_support_dir (m_device_support_directory.c_str(), true);
+ if (!platform_device_support_dir.Exists())
+ {
+ std::string alt_platform_dirname = device_support_dir;
+ alt_platform_dirname.append ("/Platforms/WatchOS.platform/DeviceSupport");
+ FileSpec alt_platform_device_support_dir (m_device_support_directory.c_str(), true);
+ if (alt_platform_device_support_dir.Exists())
+ {
+ m_device_support_directory = alt_platform_dirname;
+ }
+ }
+ }
+ else
+ {
+ // Assign a single NULL character so we know we tried to find the device
+ // support directory and we don't keep trying to find it over and over.
+ m_device_support_directory.assign (1, '\0');
+ }
+ }
+ // We should have put a single NULL character into m_device_support_directory
+ // or it should have a valid path if the code gets here
+ assert (m_device_support_directory.empty() == false);
+ if (m_device_support_directory[0])
+ return m_device_support_directory.c_str();
+ return nullptr;
+}
+
+const char *
+PlatformRemoteAppleWatch::GetDeviceSupportDirectoryForOSVersion()
+{
+ if (m_sdk_sysroot)
+ return m_sdk_sysroot.GetCString();
+
+ if (m_device_support_directory_for_os_version.empty())
+ {
+ const PlatformRemoteAppleWatch::SDKDirectoryInfo *sdk_dir_info = GetSDKDirectoryForCurrentOSVersion ();
+ if (sdk_dir_info == nullptr)
+ sdk_dir_info = GetSDKDirectoryForLatestOSVersion ();
+ if (sdk_dir_info)
+ {
+ char path[PATH_MAX];
+ if (sdk_dir_info->directory.GetPath(path, sizeof(path)))
+ {
+ m_device_support_directory_for_os_version = path;
+ return m_device_support_directory_for_os_version.c_str();
+ }
+ }
+ else
+ {
+ // Assign a single NULL character so we know we tried to find the device
+ // support directory and we don't keep trying to find it over and over.
+ m_device_support_directory_for_os_version.assign (1, '\0');
+ }
+ }
+ // We should have put a single NULL character into m_device_support_directory_for_os_version
+ // or it should have a valid path if the code gets here
+ assert (m_device_support_directory_for_os_version.empty() == false);
+ if (m_device_support_directory_for_os_version[0])
+ return m_device_support_directory_for_os_version.c_str();
+ return nullptr;
+}
+
+uint32_t
+PlatformRemoteAppleWatch::FindFileInAllSDKs (const char *platform_file_path,
+ FileSpecList &file_list)
+{
+ if (platform_file_path && platform_file_path[0] && UpdateSDKDirectoryInfosIfNeeded())
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ lldb_private::FileSpec local_file;
+ // First try for an exact match of major, minor and update
+ for (uint32_t sdk_idx=0; sdk_idx<num_sdk_infos; ++sdk_idx)
+ {
+ if (GetFileInSDK (platform_file_path,
+ sdk_idx,
+ local_file))
+ {
+ file_list.Append(local_file);
+ }
+ }
+ }
+ return file_list.GetSize();
+}
+
+bool
+PlatformRemoteAppleWatch::GetFileInSDK (const char *platform_file_path,
+ uint32_t sdk_idx,
+ lldb_private::FileSpec &local_file)
+{
+ if (sdk_idx < m_sdk_directory_infos.size())
+ {
+ char sdkroot_path[PATH_MAX];
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[sdk_idx];
+ if (sdk_dir_info.directory.GetPath(sdkroot_path, sizeof(sdkroot_path)))
+ {
+ const bool symbols_dirs_only = true;
+
+ return GetFileInSDKRoot (platform_file_path,
+ sdkroot_path,
+ symbols_dirs_only,
+ local_file);
+ }
+ }
+ return false;
+}
+
+bool
+PlatformRemoteAppleWatch::GetFileInSDKRoot (const char *platform_file_path,
+ const char *sdkroot_path,
+ bool symbols_dirs_only,
+ lldb_private::FileSpec &local_file)
+{
+ if (sdkroot_path && sdkroot_path[0] && platform_file_path && platform_file_path[0])
+ {
+ char resolved_path[PATH_MAX];
+
+ if (!symbols_dirs_only)
+ {
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s%s",
+ sdkroot_path,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return true;
+ }
+
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols.Internal%s",
+ sdkroot_path,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return true;
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols%s",
+ sdkroot_path,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return true;
+ }
+ return false;
+}
+
+Error
+PlatformRemoteAppleWatch::GetSymbolFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ Error error;
+ char platform_file_path[PATH_MAX];
+ if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
+ {
+ char resolved_path[PATH_MAX];
+
+ const char * os_version_dir = GetDeviceSupportDirectoryForOSVersion();
+ if (os_version_dir)
+ {
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/%s",
+ os_version_dir,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return error;
+
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols.Internal/%s",
+ os_version_dir,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return error;
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols/%s",
+ os_version_dir,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return error;
+
+ }
+ local_file = platform_file;
+ if (local_file.Exists())
+ return error;
+
+ error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'",
+ platform_file_path,
+ GetPluginName().GetCString());
+ }
+ else
+ {
+ error.SetErrorString ("invalid platform file argument");
+ }
+ return error;
+}
+
+Error
+PlatformRemoteAppleWatch::GetSharedModule (const ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ // For Apple Watch, the SDK files are all cached locally on the host
+ // system. So first we ask for the file in the cached SDK,
+ // then we attempt to get a shared module for the right architecture
+ // with the right UUID.
+ const FileSpec &platform_file = module_spec.GetFileSpec();
+
+ Error error;
+ char platform_file_path[PATH_MAX];
+
+ if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
+ {
+ ModuleSpec platform_module_spec(module_spec);
+
+ UpdateSDKDirectoryInfosIfNeeded();
+
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+
+ // If we are connected we migth be able to correctly deduce the SDK directory
+ // using the OS build.
+ const uint32_t connected_sdk_idx = GetConnectedSDKIndex ();
+ if (connected_sdk_idx < num_sdk_infos)
+ {
+ if (GetFileInSDK (platform_file_path, connected_sdk_idx, platform_module_spec.GetFileSpec()))
+ {
+ module_sp.reset();
+ error = ResolveExecutable(platform_module_spec,
+ module_sp,
+ nullptr);
+ if (module_sp)
+ {
+ m_last_module_sdk_idx = connected_sdk_idx;
+ error.Clear();
+ return error;
+ }
+ }
+ }
+
+ // Try the last SDK index if it is set as most files from an SDK
+ // will tend to be valid in that same SDK.
+ if (m_last_module_sdk_idx < num_sdk_infos)
+ {
+ if (GetFileInSDK (platform_file_path, m_last_module_sdk_idx, platform_module_spec.GetFileSpec()))
+ {
+ module_sp.reset();
+ error = ResolveExecutable(platform_module_spec,
+ module_sp,
+ nullptr);
+ if (module_sp)
+ {
+ error.Clear();
+ return error;
+ }
+ }
+ }
+
+ // First try for an exact match of major, minor and update
+ for (uint32_t sdk_idx=0; sdk_idx<num_sdk_infos; ++sdk_idx)
+ {
+ if (m_last_module_sdk_idx == sdk_idx)
+ {
+ // Skip the last module SDK index if we already searched
+ // it above
+ continue;
+ }
+ if (GetFileInSDK (platform_file_path, sdk_idx, platform_module_spec.GetFileSpec()))
+ {
+ //printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str());
+
+ error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
+ if (module_sp)
+ {
+ // Remember the index of the last SDK that we found a file
+ // in in case the wrong SDK was selected.
+ m_last_module_sdk_idx = sdk_idx;
+ error.Clear();
+ return error;
+ }
+ }
+ }
+ }
+ // Not the module we are looking for... Nothing to see here...
+ module_sp.reset();
+
+ // This may not be an SDK-related module. Try whether we can bring in the thing to our local cache.
+ error = GetSharedModuleWithLocalCache(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
+ if (error.Success())
+ return error;
+
+ const bool always_create = false;
+ error = ModuleList::GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr,
+ always_create);
+
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(platform_file);
+
+ return error;
+}
+
+bool
+PlatformRemoteAppleWatch::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ ArchSpec system_arch (GetSystemArchitecture());
+
+ const ArchSpec::Core system_core = system_arch.GetCore();
+ switch (system_core)
+ {
+ default:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("arm64-apple-watchos"); return true;
+ case 1: arch.SetTriple ("armv7k-apple-watchos"); return true;
+ case 2: arch.SetTriple ("armv7s-apple-watchos"); return true;
+ case 3: arch.SetTriple ("armv7-apple-watchos"); return true;
+ case 4: arch.SetTriple ("thumbv7k-apple-watchos"); return true;
+ case 5: arch.SetTriple ("thumbv7-apple-watchos"); return true;
+ case 6: arch.SetTriple ("thumbv7s-apple-watchos"); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_arm64:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("arm64-apple-watchos"); return true;
+ case 1: arch.SetTriple ("armv7k-apple-watchos"); return true;
+ case 2: arch.SetTriple ("armv7s-apple-watchos"); return true;
+ case 3: arch.SetTriple ("armv7-apple-watchos"); return true;
+ case 4: arch.SetTriple ("thumbv7k-apple-watchos"); return true;
+ case 5: arch.SetTriple ("thumbv7-apple-watchos"); return true;
+ case 6: arch.SetTriple ("thumbv7s-apple-watchos"); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7k:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7k-apple-watchos"); return true;
+ case 1: arch.SetTriple ("armv7s-apple-watchos"); return true;
+ case 2: arch.SetTriple ("armv7-apple-watchos"); return true;
+ case 3: arch.SetTriple ("thumbv7k-apple-watchos"); return true;
+ case 4: arch.SetTriple ("thumbv7-apple-watchos"); return true;
+ case 5: arch.SetTriple ("thumbv7s-apple-watchos"); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7s:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7s-apple-watchos"); return true;
+ case 1: arch.SetTriple ("armv7k-apple-watchos"); return true;
+ case 2: arch.SetTriple ("armv7-apple-watchos"); return true;
+ case 3: arch.SetTriple ("thumbv7k-apple-watchos"); return true;
+ case 4: arch.SetTriple ("thumbv7-apple-watchos"); return true;
+ case 5: arch.SetTriple ("thumbv7s-apple-watchos"); return true;
+ default: break;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7:
+ switch (idx)
+ {
+ case 0: arch.SetTriple ("armv7-apple-watchos"); return true;
+ case 1: arch.SetTriple ("armv7k-apple-watchos"); return true;
+ case 2: arch.SetTriple ("thumbv7k-apple-watchos"); return true;
+ case 3: arch.SetTriple ("thumbv7-apple-watchos"); return true;
+ default: break;
+ }
+ break;
+ }
+ arch.Clear();
+ return false;
+}
+
+uint32_t
+PlatformRemoteAppleWatch::GetConnectedSDKIndex ()
+{
+ if (IsConnected())
+ {
+ if (m_connected_module_sdk_idx == UINT32_MAX)
+ {
+ std::string build;
+ if (GetRemoteOSBuildString(build))
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ for (uint32_t i=0; i<num_sdk_infos; ++i)
+ {
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
+ if (strstr(sdk_dir_info.directory.GetFilename().AsCString(""), build.c_str()))
+ {
+ m_connected_module_sdk_idx = i;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ m_connected_module_sdk_idx = UINT32_MAX;
+ }
+ return m_connected_module_sdk_idx;
+}
diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h
new file mode 100644
index 000000000000..891bc5d1c6ef
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h
@@ -0,0 +1,173 @@
+//===-- PlatformRemoteAppleWatch.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_PlatformRemoteAppleWatch_h_
+#define liblldb_PlatformRemoteAppleWatch_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/FileSpec.h"
+
+#include "PlatformDarwin.h"
+
+class PlatformRemoteAppleWatch : public PlatformDarwin
+{
+public:
+ PlatformRemoteAppleWatch();
+
+ ~PlatformRemoteAppleWatch() override = default;
+
+ //------------------------------------------------------------
+ // Class Functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ static const char *
+ GetDescriptionStatic();
+
+ //------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override
+ {
+ return GetPluginNameStatic();
+ }
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ lldb_private::Error
+ ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr) override;
+
+ const char *
+ GetDescription () override
+ {
+ return GetDescriptionStatic();
+ }
+
+ void
+ GetStatus (lldb_private::Stream &strm) override;
+
+ virtual lldb_private::Error
+ GetSymbolFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ bool
+ GetSupportedArchitectureAtIndex (uint32_t idx,
+ lldb_private::ArchSpec &arch) override;
+
+ void
+ AddClangModuleCompilationOptions (lldb_private::Target *target, std::vector<std::string> &options) override
+ {
+ return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(target, options, PlatformDarwin::SDKType::iPhoneOS);
+ }
+
+protected:
+ struct SDKDirectoryInfo
+ {
+ SDKDirectoryInfo (const lldb_private::FileSpec &sdk_dir_spec);
+ lldb_private::FileSpec directory;
+ lldb_private::ConstString build;
+ uint32_t version_major;
+ uint32_t version_minor;
+ uint32_t version_update;
+ bool user_cached;
+ };
+ typedef std::vector<SDKDirectoryInfo> SDKDirectoryInfoCollection;
+ SDKDirectoryInfoCollection m_sdk_directory_infos;
+ std::string m_device_support_directory;
+ std::string m_device_support_directory_for_os_version;
+ std::string m_build_update;
+ uint32_t m_last_module_sdk_idx;
+ uint32_t m_connected_module_sdk_idx;
+
+ bool
+ UpdateSDKDirectoryInfosIfNeeded();
+
+ const char *
+ GetDeviceSupportDirectory();
+
+ const char *
+ GetDeviceSupportDirectoryForOSVersion();
+
+ const SDKDirectoryInfo *
+ GetSDKDirectoryForLatestOSVersion ();
+
+ const SDKDirectoryInfo *
+ GetSDKDirectoryForCurrentOSVersion ();
+
+ static lldb_private::FileSpec::EnumerateDirectoryResult
+ GetContainedFilesIntoVectorOfStringsCallback (void *baton,
+ lldb_private::FileSpec::FileType file_type,
+ const lldb_private::FileSpec &file_spec);
+
+ uint32_t
+ FindFileInAllSDKs (const char *platform_file_path,
+ lldb_private::FileSpecList &file_list);
+
+ bool
+ GetFileInSDK (const char *platform_file_path,
+ uint32_t sdk_idx,
+ lldb_private::FileSpec &local_file);
+
+ bool
+ GetFileInSDKRoot (const char *platform_file_path,
+ const char *sdkroot_path,
+ bool symbols_dirs_only,
+ lldb_private::FileSpec &local_file);
+
+ uint32_t
+ FindFileInAllSDKs (const lldb_private::FileSpec &platform_file,
+ lldb_private::FileSpecList &file_list);
+
+ uint32_t
+ GetConnectedSDKIndex ();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformRemoteAppleWatch);
+};
+
+#endif // liblldb_PlatformRemoteAppleWatch_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp b/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
new file mode 100644
index 000000000000..75afa9019dcd
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
@@ -0,0 +1,974 @@
+//===-- PlatformRemoteiOS.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformRemoteiOS.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+PlatformRemoteiOS::SDKDirectoryInfo::SDKDirectoryInfo (const lldb_private::FileSpec &sdk_dir) :
+ directory(sdk_dir),
+ build(),
+ version_major(0),
+ version_minor(0),
+ version_update(0),
+ user_cached(false)
+{
+ const char *dirname_cstr = sdk_dir.GetFilename().GetCString();
+ const char *pos = Args::StringToVersion (dirname_cstr,
+ version_major,
+ version_minor,
+ version_update);
+
+ if (pos && pos[0] == ' ' && pos[1] == '(')
+ {
+ const char *build_start = pos + 2;
+ const char *end_paren = strchr (build_start, ')');
+ if (end_paren && build_start < end_paren)
+ build.SetCStringWithLength(build_start, end_paren - build_start);
+ }
+}
+
+//------------------------------------------------------------------
+// Static Variables
+//------------------------------------------------------------------
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+void
+PlatformRemoteiOS::Initialize ()
+{
+ PlatformDarwin::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+ PluginManager::RegisterPlugin (PlatformRemoteiOS::GetPluginNameStatic(),
+ PlatformRemoteiOS::GetDescriptionStatic(),
+ PlatformRemoteiOS::CreateInstance);
+ }
+}
+
+void
+PlatformRemoteiOS::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformRemoteiOS::CreateInstance);
+ }
+ }
+
+ PlatformDarwin::Terminate ();
+}
+
+PlatformSP
+PlatformRemoteiOS::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformRemoteiOS::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ switch (arch->GetMachine())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::thumb:
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ llvm::Triple::VendorType vendor = triple.getVendor();
+ switch (vendor)
+ {
+ case llvm::Triple::Apple:
+ create = true;
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the vendor if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+
+#endif
+ default:
+ break;
+ }
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::Darwin: // Deprecated, but still support Darwin for historical reasons
+ case llvm::Triple::IOS: // This is the right triple value for iOS debugging
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the OS if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformRemoteiOS::%s() creating platform", __FUNCTION__);
+
+ return lldb::PlatformSP(new PlatformRemoteiOS ());
+ }
+
+ if (log)
+ log->Printf ("PlatformRemoteiOS::%s() aborting creation of platform", __FUNCTION__);
+
+ return lldb::PlatformSP();
+}
+
+
+lldb_private::ConstString
+PlatformRemoteiOS::GetPluginNameStatic ()
+{
+ static ConstString g_name("remote-ios");
+ return g_name;
+}
+
+const char *
+PlatformRemoteiOS::GetDescriptionStatic()
+{
+ return "Remote iOS platform plug-in.";
+}
+
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformRemoteiOS::PlatformRemoteiOS () :
+ PlatformDarwin (false), // This is a remote platform
+ m_sdk_directory_infos(),
+ m_device_support_directory(),
+ m_device_support_directory_for_os_version (),
+ m_build_update(),
+ m_last_module_sdk_idx (UINT32_MAX),
+ m_connected_module_sdk_idx (UINT32_MAX)
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformRemoteiOS::~PlatformRemoteiOS()
+{
+}
+
+
+void
+PlatformRemoteiOS::GetStatus (Stream &strm)
+{
+ Platform::GetStatus (strm);
+ const char *sdk_directory = GetDeviceSupportDirectoryForOSVersion();
+ if (sdk_directory)
+ strm.Printf (" SDK Path: \"%s\"\n", sdk_directory);
+ else
+ strm.PutCString (" SDK Path: error: unable to locate SDK\n");
+
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ for (uint32_t i=0; i<num_sdk_infos; ++i)
+ {
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
+ strm.Printf (" SDK Roots: [%2u] \"%s\"\n",
+ i,
+ sdk_dir_info.directory.GetPath().c_str());
+ }
+}
+
+
+Error
+PlatformRemoteiOS::ResolveExecutable (const ModuleSpec &ms,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ ModuleSpec resolved_module_spec(ms);
+
+ // Resolve any executable within a bundle on MacOSX
+ // TODO: verify that this handles shallow bundles, if not then implement one ourselves
+ Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ {
+ if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid())
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ return error;
+ exe_module_sp.reset();
+ }
+ // No valid architecture was specified or the exact ARM slice wasn't
+ // found so ask the platform for the architectures that we should be
+ // using (in the correct order) and see if we can find a match that way
+ StreamString arch_names;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ if (resolved_module_spec.GetFileSpec().Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("'%s' does not exist",
+ resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+
+ return error;
+}
+
+FileSpec::EnumerateDirectoryResult
+PlatformRemoteiOS::GetContainedFilesIntoVectorOfStringsCallback (void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &file_spec)
+{
+ ((PlatformRemoteiOS::SDKDirectoryInfoCollection *)baton)->push_back(PlatformRemoteiOS::SDKDirectoryInfo(file_spec));
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+bool
+PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded()
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (m_sdk_directory_infos.empty())
+ {
+ // A --sysroot option was supplied - add it to our list of SDKs to check
+ if (m_sdk_sysroot)
+ {
+ FileSpec sdk_sysroot_fspec(m_sdk_sysroot.GetCString(), true);
+ const SDKDirectoryInfo sdk_sysroot_directory_info(sdk_sysroot_fspec);
+ m_sdk_directory_infos.push_back(sdk_sysroot_directory_info);
+ if (log)
+ {
+ log->Printf ("PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded added --sysroot SDK directory %s", m_sdk_sysroot.GetCString());
+ }
+ return true;
+ }
+ const char *device_support_dir = GetDeviceSupportDirectory();
+ if (log)
+ {
+ log->Printf ("PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded Got DeviceSupport directory %s", device_support_dir);
+ }
+ if (device_support_dir)
+ {
+ const bool find_directories = true;
+ const bool find_files = false;
+ const bool find_other = false;
+
+ SDKDirectoryInfoCollection builtin_sdk_directory_infos;
+ FileSpec::EnumerateDirectory (m_device_support_directory.c_str(),
+ find_directories,
+ find_files,
+ find_other,
+ GetContainedFilesIntoVectorOfStringsCallback,
+ &builtin_sdk_directory_infos);
+
+ // Only add SDK directories that have symbols in them, some SDKs only contain
+ // developer disk images and no symbols, so they aren't useful to us.
+ FileSpec sdk_symbols_symlink_fspec;
+ for (const auto &sdk_directory_info : builtin_sdk_directory_infos)
+ {
+ sdk_symbols_symlink_fspec = sdk_directory_info.directory;
+ sdk_symbols_symlink_fspec.AppendPathComponent("Symbols");
+ if (sdk_symbols_symlink_fspec.Exists())
+ {
+ m_sdk_directory_infos.push_back(sdk_directory_info);
+ if (log)
+ {
+ log->Printf ("PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded added builtin SDK directory %s", sdk_symbols_symlink_fspec.GetPath().c_str());
+ }
+ }
+ }
+
+ const uint32_t num_installed = m_sdk_directory_infos.size();
+ FileSpec local_sdk_cache("~/Library/Developer/Xcode/iOS DeviceSupport", true);
+ if (local_sdk_cache.Exists())
+ {
+ if (log)
+ {
+ log->Printf ("PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded searching %s for additional SDKs", local_sdk_cache.GetPath().c_str());
+ }
+ char path[PATH_MAX];
+ if (local_sdk_cache.GetPath(path, sizeof(path)))
+ {
+ FileSpec::EnumerateDirectory (path,
+ find_directories,
+ find_files,
+ find_other,
+ GetContainedFilesIntoVectorOfStringsCallback,
+ &m_sdk_directory_infos);
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ // First try for an exact match of major, minor and update
+ for (uint32_t i=num_installed; i<num_sdk_infos; ++i)
+ {
+ m_sdk_directory_infos[i].user_cached = true;
+ if (log)
+ {
+ log->Printf ("PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded user SDK directory %s", m_sdk_directory_infos[i].directory.GetPath().c_str());
+ }
+ }
+ }
+ }
+ }
+ }
+ return !m_sdk_directory_infos.empty();
+}
+
+const PlatformRemoteiOS::SDKDirectoryInfo *
+PlatformRemoteiOS::GetSDKDirectoryForCurrentOSVersion ()
+{
+ uint32_t i;
+ if (UpdateSDKDirectoryInfosIfNeeded())
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+
+ // Check to see if the user specified a build string. If they did, then
+ // be sure to match it.
+ std::vector<bool> check_sdk_info(num_sdk_infos, true);
+ ConstString build(m_sdk_build);
+ if (build)
+ {
+ for (i=0; i<num_sdk_infos; ++i)
+ check_sdk_info[i] = m_sdk_directory_infos[i].build == build;
+ }
+
+ // If we are connected we can find the version of the OS the platform
+ // us running on and select the right SDK
+ uint32_t major, minor, update;
+ if (GetOSVersion(major, minor, update))
+ {
+ if (UpdateSDKDirectoryInfosIfNeeded())
+ {
+ // First try for an exact match of major, minor and update
+ for (i=0; i<num_sdk_infos; ++i)
+ {
+ if (check_sdk_info[i])
+ {
+ if (m_sdk_directory_infos[i].version_major == major &&
+ m_sdk_directory_infos[i].version_minor == minor &&
+ m_sdk_directory_infos[i].version_update == update)
+ {
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ }
+ // First try for an exact match of major and minor
+ for (i=0; i<num_sdk_infos; ++i)
+ {
+ if (check_sdk_info[i])
+ {
+ if (m_sdk_directory_infos[i].version_major == major &&
+ m_sdk_directory_infos[i].version_minor == minor)
+ {
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ }
+ // Lastly try to match of major version only..
+ for (i=0; i<num_sdk_infos; ++i)
+ {
+ if (check_sdk_info[i])
+ {
+ if (m_sdk_directory_infos[i].version_major == major)
+ {
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ }
+ }
+ }
+ else if (build)
+ {
+ // No version, just a build number, search for the first one that matches
+ for (i=0; i<num_sdk_infos; ++i)
+ if (check_sdk_info[i])
+ return &m_sdk_directory_infos[i];
+ }
+ }
+ return NULL;
+}
+
+const PlatformRemoteiOS::SDKDirectoryInfo *
+PlatformRemoteiOS::GetSDKDirectoryForLatestOSVersion ()
+{
+ const PlatformRemoteiOS::SDKDirectoryInfo *result = NULL;
+ if (UpdateSDKDirectoryInfosIfNeeded())
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ // First try for an exact match of major, minor and update
+ for (uint32_t i=0; i<num_sdk_infos; ++i)
+ {
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
+ if (sdk_dir_info.version_major != UINT32_MAX)
+ {
+ if (result == NULL || sdk_dir_info.version_major > result->version_major)
+ {
+ result = &sdk_dir_info;
+ }
+ else if (sdk_dir_info.version_major == result->version_major)
+ {
+ if (sdk_dir_info.version_minor > result->version_minor)
+ {
+ result = &sdk_dir_info;
+ }
+ else if (sdk_dir_info.version_minor == result->version_minor)
+ {
+ if (sdk_dir_info.version_update > result->version_update)
+ {
+ result = &sdk_dir_info;
+ }
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+
+
+const char *
+PlatformRemoteiOS::GetDeviceSupportDirectory()
+{
+ if (m_device_support_directory.empty())
+ {
+ const char *device_support_dir = GetDeveloperDirectory();
+ if (device_support_dir)
+ {
+ m_device_support_directory.assign (device_support_dir);
+ m_device_support_directory.append ("/Platforms/iPhoneOS.platform/DeviceSupport");
+ }
+ else
+ {
+ // Assign a single NULL character so we know we tried to find the device
+ // support directory and we don't keep trying to find it over and over.
+ m_device_support_directory.assign (1, '\0');
+ }
+ }
+ // We should have put a single NULL character into m_device_support_directory
+ // or it should have a valid path if the code gets here
+ assert (m_device_support_directory.empty() == false);
+ if (m_device_support_directory[0])
+ return m_device_support_directory.c_str();
+ return NULL;
+}
+
+
+const char *
+PlatformRemoteiOS::GetDeviceSupportDirectoryForOSVersion()
+{
+ if (m_sdk_sysroot)
+ return m_sdk_sysroot.GetCString();
+
+ if (m_device_support_directory_for_os_version.empty())
+ {
+ const PlatformRemoteiOS::SDKDirectoryInfo *sdk_dir_info = GetSDKDirectoryForCurrentOSVersion ();
+ if (sdk_dir_info == NULL)
+ sdk_dir_info = GetSDKDirectoryForLatestOSVersion ();
+ if (sdk_dir_info)
+ {
+ char path[PATH_MAX];
+ if (sdk_dir_info->directory.GetPath(path, sizeof(path)))
+ {
+ m_device_support_directory_for_os_version = path;
+ return m_device_support_directory_for_os_version.c_str();
+ }
+ }
+ else
+ {
+ // Assign a single NULL character so we know we tried to find the device
+ // support directory and we don't keep trying to find it over and over.
+ m_device_support_directory_for_os_version.assign (1, '\0');
+ }
+ }
+ // We should have put a single NULL character into m_device_support_directory_for_os_version
+ // or it should have a valid path if the code gets here
+ assert (m_device_support_directory_for_os_version.empty() == false);
+ if (m_device_support_directory_for_os_version[0])
+ return m_device_support_directory_for_os_version.c_str();
+ return NULL;
+}
+
+uint32_t
+PlatformRemoteiOS::FindFileInAllSDKs (const char *platform_file_path,
+ FileSpecList &file_list)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST | LIBLLDB_LOG_VERBOSE);
+ if (platform_file_path && platform_file_path[0] && UpdateSDKDirectoryInfosIfNeeded())
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ lldb_private::FileSpec local_file;
+ // First try for an exact match of major, minor and update
+ for (uint32_t sdk_idx=0; sdk_idx<num_sdk_infos; ++sdk_idx)
+ {
+ if (log)
+ {
+ log->Printf ("Searching for %s in sdk path %s", platform_file_path, m_sdk_directory_infos[sdk_idx].directory.GetPath().c_str());
+ }
+ if (GetFileInSDK (platform_file_path,
+ sdk_idx,
+ local_file))
+ {
+ file_list.Append(local_file);
+ }
+ }
+ }
+ return file_list.GetSize();
+}
+
+bool
+PlatformRemoteiOS::GetFileInSDK (const char *platform_file_path,
+ uint32_t sdk_idx,
+ lldb_private::FileSpec &local_file)
+{
+ if (sdk_idx < m_sdk_directory_infos.size())
+ {
+ char sdkroot_path[PATH_MAX];
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[sdk_idx];
+ if (sdk_dir_info.directory.GetPath(sdkroot_path, sizeof(sdkroot_path)))
+ {
+ const bool symbols_dirs_only = true;
+
+ return GetFileInSDKRoot (platform_file_path,
+ sdkroot_path,
+ symbols_dirs_only,
+ local_file);
+ }
+ }
+ return false;
+}
+
+
+bool
+PlatformRemoteiOS::GetFileInSDKRoot (const char *platform_file_path,
+ const char *sdkroot_path,
+ bool symbols_dirs_only,
+ lldb_private::FileSpec &local_file)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (sdkroot_path && sdkroot_path[0] && platform_file_path && platform_file_path[0])
+ {
+ char resolved_path[PATH_MAX];
+
+ if (!symbols_dirs_only)
+ {
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s%s",
+ sdkroot_path,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ {
+ if (log)
+ {
+ log->Printf ("Found a copy of %s in the SDK dir %s", platform_file_path, sdkroot_path);
+ }
+ return true;
+ }
+ }
+
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols.Internal%s",
+ sdkroot_path,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ {
+ if (log)
+ {
+ log->Printf ("Found a copy of %s in the SDK dir %s/Symbols.Internal", platform_file_path, sdkroot_path);
+ }
+ return true;
+ }
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols%s",
+ sdkroot_path,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ {
+ if (log)
+ {
+ log->Printf ("Found a copy of %s in the SDK dir %s/Symbols", platform_file_path, sdkroot_path);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+
+Error
+PlatformRemoteiOS::GetSymbolFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ Error error;
+ char platform_file_path[PATH_MAX];
+ if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
+ {
+ char resolved_path[PATH_MAX];
+
+ const char * os_version_dir = GetDeviceSupportDirectoryForOSVersion();
+ if (os_version_dir)
+ {
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/%s",
+ os_version_dir,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ {
+ if (log)
+ {
+ log->Printf ("Found a copy of %s in the DeviceSupport dir %s", platform_file_path, os_version_dir);
+ }
+ return error;
+ }
+
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols.Internal/%s",
+ os_version_dir,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ {
+ if (log)
+ {
+ log->Printf ("Found a copy of %s in the DeviceSupport dir %s/Symbols.Internal", platform_file_path, os_version_dir);
+ }
+ return error;
+ }
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/Symbols/%s",
+ os_version_dir,
+ platform_file_path);
+
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ {
+ if (log)
+ {
+ log->Printf ("Found a copy of %s in the DeviceSupport dir %s/Symbols", platform_file_path, os_version_dir);
+ }
+ return error;
+ }
+
+ }
+ local_file = platform_file;
+ if (local_file.Exists())
+ return error;
+
+ error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'",
+ platform_file_path,
+ GetPluginName().GetCString());
+ }
+ else
+ {
+ error.SetErrorString ("invalid platform file argument");
+ }
+ return error;
+}
+
+Error
+PlatformRemoteiOS::GetSharedModule (const ModuleSpec &module_spec,
+ Process* process,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ // For iOS, the SDK files are all cached locally on the host
+ // system. So first we ask for the file in the cached SDK,
+ // then we attempt to get a shared module for the right architecture
+ // with the right UUID.
+ const FileSpec &platform_file = module_spec.GetFileSpec();
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST | LIBLLDB_LOG_VERBOSE);
+
+ Error error;
+ char platform_file_path[PATH_MAX];
+
+ if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
+ {
+ ModuleSpec platform_module_spec(module_spec);
+
+ UpdateSDKDirectoryInfosIfNeeded();
+
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+
+ // If we are connected we migth be able to correctly deduce the SDK directory
+ // using the OS build.
+ const uint32_t connected_sdk_idx = GetConnectedSDKIndex ();
+ if (connected_sdk_idx < num_sdk_infos)
+ {
+ if (log)
+ {
+ log->Printf ("Searching for %s in sdk path %s", platform_file_path, m_sdk_directory_infos[connected_sdk_idx].directory.GetPath().c_str());
+ }
+ if (GetFileInSDK (platform_file_path, connected_sdk_idx, platform_module_spec.GetFileSpec()))
+ {
+ module_sp.reset();
+ error = ResolveExecutable (platform_module_spec,
+ module_sp,
+ NULL);
+ if (module_sp)
+ {
+ m_last_module_sdk_idx = connected_sdk_idx;
+ error.Clear();
+ return error;
+ }
+ }
+ }
+
+ // Try the last SDK index if it is set as most files from an SDK
+ // will tend to be valid in that same SDK.
+ if (m_last_module_sdk_idx < num_sdk_infos)
+ {
+ if (log)
+ {
+ log->Printf ("Searching for %s in sdk path %s", platform_file_path, m_sdk_directory_infos[m_last_module_sdk_idx].directory.GetPath().c_str());
+ }
+ if (GetFileInSDK (platform_file_path, m_last_module_sdk_idx, platform_module_spec.GetFileSpec()))
+ {
+ module_sp.reset();
+ error = ResolveExecutable (platform_module_spec,
+ module_sp,
+ NULL);
+ if (module_sp)
+ {
+ error.Clear();
+ return error;
+ }
+ }
+ }
+
+ // First try for an exact match of major, minor and update:
+ // If a particalar SDK version was specified via --version or --build, look for a match on disk.
+ const SDKDirectoryInfo *current_sdk_info = GetSDKDirectoryForCurrentOSVersion();
+ const uint32_t current_sdk_idx = GetSDKIndexBySDKDirectoryInfo(current_sdk_info);
+ if (current_sdk_idx < num_sdk_infos && current_sdk_idx != m_last_module_sdk_idx)
+ {
+ if (log)
+ {
+ log->Printf ("Searching for %s in sdk path %s", platform_file_path, m_sdk_directory_infos[current_sdk_idx].directory.GetPath().c_str());
+ }
+ if (GetFileInSDK (platform_file_path, current_sdk_idx, platform_module_spec.GetFileSpec()))
+ {
+ module_sp.reset();
+ error = ResolveExecutable (platform_module_spec,
+ module_sp,
+ NULL);
+ if (module_sp)
+ {
+ m_last_module_sdk_idx = current_sdk_idx;
+ error.Clear();
+ return error;
+ }
+ }
+ }
+
+ // Second try all SDKs that were found.
+ for (uint32_t sdk_idx=0; sdk_idx<num_sdk_infos; ++sdk_idx)
+ {
+ if (m_last_module_sdk_idx == sdk_idx)
+ {
+ // Skip the last module SDK index if we already searched
+ // it above
+ continue;
+ }
+ if (log)
+ {
+ log->Printf ("Searching for %s in sdk path %s", platform_file_path, m_sdk_directory_infos[sdk_idx].directory.GetPath().c_str());
+ }
+ if (GetFileInSDK (platform_file_path, sdk_idx, platform_module_spec.GetFileSpec()))
+ {
+ //printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str());
+
+ error = ResolveExecutable (platform_module_spec, module_sp, NULL);
+ if (module_sp)
+ {
+ // Remember the index of the last SDK that we found a file
+ // in in case the wrong SDK was selected.
+ m_last_module_sdk_idx = sdk_idx;
+ error.Clear();
+ return error;
+ }
+ }
+ }
+ }
+ // Not the module we are looking for... Nothing to see here...
+ module_sp.reset();
+
+ // This may not be an SDK-related module. Try whether we can bring in the thing to our local cache.
+ error = GetSharedModuleWithLocalCache(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
+ if (error.Success())
+ return error;
+
+ const bool always_create = false;
+ error = ModuleList::GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr,
+ always_create);
+
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(platform_file);
+
+ return error;
+}
+
+bool
+PlatformRemoteiOS::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ return ARMGetSupportedArchitectureAtIndex (idx, arch);
+}
+
+uint32_t
+PlatformRemoteiOS::GetConnectedSDKIndex ()
+{
+ if (IsConnected())
+ {
+ if (m_connected_module_sdk_idx == UINT32_MAX)
+ {
+ std::string build;
+ if (GetRemoteOSBuildString(build))
+ {
+ const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
+ for (uint32_t i=0; i<num_sdk_infos; ++i)
+ {
+ const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
+ if (strstr(sdk_dir_info.directory.GetFilename().AsCString(""), build.c_str()))
+ {
+ m_connected_module_sdk_idx = i;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ m_connected_module_sdk_idx = UINT32_MAX;
+ }
+ return m_connected_module_sdk_idx;
+}
+
+uint32_t
+PlatformRemoteiOS::GetSDKIndexBySDKDirectoryInfo (const SDKDirectoryInfo *sdk_info)
+{
+ if (sdk_info == NULL)
+ {
+ return UINT32_MAX;
+ }
+
+ return sdk_info - &m_sdk_directory_infos[0];
+}
diff --git a/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h b/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h
new file mode 100644
index 000000000000..9726d8238e13
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h
@@ -0,0 +1,173 @@
+//===-- PlatformRemoteiOS.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_PlatformRemoteiOS_h_
+#define liblldb_PlatformRemoteiOS_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/FileSpec.h"
+#include "PlatformDarwin.h"
+
+class PlatformRemoteiOS : public PlatformDarwin
+{
+public:
+ PlatformRemoteiOS ();
+
+ ~PlatformRemoteiOS() override;
+
+ //------------------------------------------------------------
+ // Class Functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ static const char *
+ GetDescriptionStatic();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override
+ {
+ return GetPluginNameStatic();
+ }
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ lldb_private::Error
+ ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr) override;
+
+ const char *
+ GetDescription () override
+ {
+ return GetDescriptionStatic();
+ }
+
+ void
+ GetStatus (lldb_private::Stream &strm) override;
+
+ virtual lldb_private::Error
+ GetSymbolFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ bool
+ GetSupportedArchitectureAtIndex (uint32_t idx,
+ lldb_private::ArchSpec &arch) override;
+
+ void
+ AddClangModuleCompilationOptions (lldb_private::Target *target, std::vector<std::string> &options) override
+ {
+ return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(target, options, PlatformDarwin::SDKType::iPhoneOS);
+ }
+
+protected:
+ struct SDKDirectoryInfo
+ {
+ SDKDirectoryInfo (const lldb_private::FileSpec &sdk_dir_spec);
+ lldb_private::FileSpec directory;
+ lldb_private::ConstString build;
+ uint32_t version_major;
+ uint32_t version_minor;
+ uint32_t version_update;
+ bool user_cached;
+ };
+
+ typedef std::vector<SDKDirectoryInfo> SDKDirectoryInfoCollection;
+
+ SDKDirectoryInfoCollection m_sdk_directory_infos;
+ std::string m_device_support_directory;
+ std::string m_device_support_directory_for_os_version;
+ std::string m_build_update;
+ uint32_t m_last_module_sdk_idx;
+ uint32_t m_connected_module_sdk_idx;
+
+ bool
+ UpdateSDKDirectoryInfosIfNeeded();
+
+ const char *
+ GetDeviceSupportDirectory();
+
+ const char *
+ GetDeviceSupportDirectoryForOSVersion();
+
+ const SDKDirectoryInfo *
+ GetSDKDirectoryForLatestOSVersion ();
+
+ const SDKDirectoryInfo *
+ GetSDKDirectoryForCurrentOSVersion ();
+
+ static lldb_private::FileSpec::EnumerateDirectoryResult
+ GetContainedFilesIntoVectorOfStringsCallback (void *baton,
+ lldb_private::FileSpec::FileType file_type,
+ const lldb_private::FileSpec &file_spec);
+
+ uint32_t
+ FindFileInAllSDKs (const char *platform_file_path,
+ lldb_private::FileSpecList &file_list);
+
+ bool
+ GetFileInSDK (const char *platform_file_path,
+ uint32_t sdk_idx,
+ lldb_private::FileSpec &local_file);
+
+ bool
+ GetFileInSDKRoot (const char *platform_file_path,
+ const char *sdkroot_path,
+ bool symbols_dirs_only,
+ lldb_private::FileSpec &local_file);
+
+ uint32_t
+ FindFileInAllSDKs (const lldb_private::FileSpec &platform_file,
+ lldb_private::FileSpecList &file_list);
+
+ uint32_t
+ GetConnectedSDKIndex ();
+
+ // Get index of SDK in SDKDirectoryInfoCollection by its pointer and return UINT32_MAX if that SDK not found.
+ uint32_t
+ GetSDKIndexBySDKDirectoryInfo (const SDKDirectoryInfo *sdk_info);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformRemoteiOS);
+};
+
+#endif // liblldb_PlatformRemoteiOS_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp
new file mode 100644
index 000000000000..cbe9c7949a4a
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp
@@ -0,0 +1,502 @@
+//===-- PlatformiOSSimulator.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformiOSSimulator.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+// Static Variables
+//------------------------------------------------------------------
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+void
+PlatformiOSSimulator::Initialize ()
+{
+ PlatformAppleSimulator::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+ PluginManager::RegisterPlugin (PlatformiOSSimulator::GetPluginNameStatic(),
+ PlatformiOSSimulator::GetDescriptionStatic(),
+ PlatformiOSSimulator::CreateInstance);
+ }
+}
+
+void
+PlatformiOSSimulator::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformiOSSimulator::CreateInstance);
+ }
+ }
+
+ PlatformAppleSimulator::Terminate ();
+}
+
+PlatformSP
+PlatformiOSSimulator::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformiOSSimulator::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ switch (arch->GetMachine())
+ {
+ case llvm::Triple::x86_64:
+ case llvm::Triple::x86:
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::Apple:
+ create = true;
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the vendor if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::Darwin: // Deprecated, but still support Darwin for historical reasons
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS: // IOS is not used for simulator triples, but accept it just in case
+ break;
+
+#if defined(__APPLE__)
+ // Only accept "unknown" for the OS if the host is Apple and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformiOSSimulator::%s() creating platform", __FUNCTION__);
+
+ return PlatformSP(new PlatformiOSSimulator ());
+ }
+
+ if (log)
+ log->Printf ("PlatformiOSSimulator::%s() aborting creation of platform", __FUNCTION__);
+
+ return PlatformSP();
+}
+
+
+lldb_private::ConstString
+PlatformiOSSimulator::GetPluginNameStatic ()
+{
+ static ConstString g_name("ios-simulator");
+ return g_name;
+}
+
+const char *
+PlatformiOSSimulator::GetDescriptionStatic()
+{
+ return "iOS simulator platform plug-in.";
+}
+
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformiOSSimulator::PlatformiOSSimulator () :
+PlatformAppleSimulator (),
+m_sdk_directory ()
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformiOSSimulator::~PlatformiOSSimulator()
+{
+}
+
+
+void
+PlatformiOSSimulator::GetStatus (Stream &strm)
+{
+ Platform::GetStatus (strm);
+ const char *sdk_directory = GetSDKDirectoryAsCString();
+ if (sdk_directory)
+ strm.Printf (" SDK Path: \"%s\"\n", sdk_directory);
+ else
+ strm.PutCString (" SDK Path: error: unable to locate SDK\n");
+ PlatformAppleSimulator::GetStatus(strm);
+}
+
+
+Error
+PlatformiOSSimulator::ResolveExecutable (const ModuleSpec &module_spec,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ ModuleSpec resolved_module_spec(module_spec);
+
+ // If we have "ls" as the exe_file, resolve the executable loation based on
+ // the current path variables
+ // TODO: resolve bare executables in the Platform SDK
+ // if (!resolved_exe_file.Exists())
+ // resolved_exe_file.ResolveExecutableLocation ();
+
+ // Resolve any executable within a bundle on MacOSX
+ // TODO: verify that this handles shallow bundles, if not then implement one ourselves
+ Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ {
+ if (resolved_module_spec.GetArchitecture().IsValid())
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ return error;
+ exe_module_sp.reset();
+ }
+ // No valid architecture was specified or the exact ARM slice wasn't
+ // found so ask the platform for the architectures that we should be
+ // using (in the correct order) and see if we can find a match that way
+ StreamString arch_names;
+ ArchSpec platform_arch;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
+ {
+ // Only match x86 with x86 and x86_64 with x86_64...
+ if (!module_spec.GetArchitecture().IsValid() || module_spec.GetArchitecture().GetCore() == resolved_module_spec.GetArchitecture().GetCore())
+ {
+ error = ModuleList::GetSharedModule (resolved_module_spec,
+ exe_module_sp,
+ NULL,
+ NULL,
+ NULL);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (platform_arch.GetArchitectureName());
+ }
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ if (resolved_module_spec.GetFileSpec().Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("'%s' does not exist",
+ module_spec.GetFileSpec().GetPath().c_str());
+ }
+
+ return error;
+}
+
+static FileSpec::EnumerateDirectoryResult
+EnumerateDirectoryCallback (void *baton, FileSpec::FileType file_type, const FileSpec &file_spec)
+{
+ if (file_type == FileSpec::eFileTypeDirectory)
+ {
+ const char *filename = file_spec.GetFilename().GetCString();
+ if (filename && strncmp(filename, "iPhoneSimulator", strlen ("iPhoneSimulator")) == 0)
+ {
+ ::snprintf ((char *)baton, PATH_MAX, "%s", filename);
+ return FileSpec::eEnumerateDirectoryResultQuit;
+ }
+ }
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+
+
+const char *
+PlatformiOSSimulator::GetSDKDirectoryAsCString()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_sdk_directory.empty())
+ {
+ const char *developer_dir = GetDeveloperDirectory();
+ if (developer_dir)
+ {
+ char sdks_directory[PATH_MAX];
+ char sdk_dirname[PATH_MAX];
+ sdk_dirname[0] = '\0';
+ snprintf (sdks_directory,
+ sizeof(sdks_directory),
+ "%s/Platforms/iPhoneSimulator.platform/Developer/SDKs",
+ developer_dir);
+ FileSpec simulator_sdk_spec;
+ bool find_directories = true;
+ bool find_files = false;
+ bool find_other = false;
+ FileSpec::EnumerateDirectory (sdks_directory,
+ find_directories,
+ find_files,
+ find_other,
+ EnumerateDirectoryCallback,
+ sdk_dirname);
+
+ if (sdk_dirname[0])
+ {
+ m_sdk_directory = sdks_directory;
+ m_sdk_directory.append (1, '/');
+ m_sdk_directory.append (sdk_dirname);
+ return m_sdk_directory.c_str();
+ }
+ }
+ // Assign a single NULL character so we know we tried to find the device
+ // support directory and we don't keep trying to find it over and over.
+ m_sdk_directory.assign (1, '\0');
+ }
+
+ // We should have put a single NULL character into m_sdk_directory
+ // or it should have a valid path if the code gets here
+ assert (m_sdk_directory.empty() == false);
+ if (m_sdk_directory[0])
+ return m_sdk_directory.c_str();
+ return NULL;
+}
+
+Error
+PlatformiOSSimulator::GetSymbolFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ Error error;
+ char platform_file_path[PATH_MAX];
+ if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
+ {
+ char resolved_path[PATH_MAX];
+
+ const char * sdk_dir = GetSDKDirectoryAsCString();
+ if (sdk_dir)
+ {
+ ::snprintf (resolved_path,
+ sizeof(resolved_path),
+ "%s/%s",
+ sdk_dir,
+ platform_file_path);
+
+ // First try in the SDK and see if the file is in there
+ local_file.SetFile(resolved_path, true);
+ if (local_file.Exists())
+ return error;
+
+ // Else fall back to the actual path itself
+ local_file.SetFile(platform_file_path, true);
+ if (local_file.Exists())
+ return error;
+
+ }
+ error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'",
+ platform_file_path,
+ GetPluginName().GetCString());
+ }
+ else
+ {
+ error.SetErrorString ("invalid platform file argument");
+ }
+ return error;
+}
+
+Error
+PlatformiOSSimulator::GetSharedModule (const ModuleSpec &module_spec,
+ Process* process,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ // For iOS, the SDK files are all cached locally on the host
+ // system. So first we ask for the file in the cached SDK,
+ // then we attempt to get a shared module for the right architecture
+ // with the right UUID.
+ Error error;
+ ModuleSpec platform_module_spec (module_spec);
+ const FileSpec &platform_file = module_spec.GetFileSpec();
+ error = GetSymbolFile (platform_file, module_spec.GetUUIDPtr(), platform_module_spec.GetFileSpec());
+ if (error.Success())
+ {
+ error = ResolveExecutable (platform_module_spec, module_sp, module_search_paths_ptr);
+ }
+ else
+ {
+ const bool always_create = false;
+ error = ModuleList::GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr,
+ always_create);
+
+ }
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(platform_file);
+
+ return error;
+}
+
+
+uint32_t
+PlatformiOSSimulator::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ ProcessInstanceInfoList all_osx_process_infos;
+ // First we get all OSX processes
+ const uint32_t n = Host::FindProcesses (match_info, all_osx_process_infos);
+
+ // Now we filter them down to only the iOS triples
+ for (uint32_t i=0; i<n; ++i)
+ {
+ const ProcessInstanceInfo &proc_info = all_osx_process_infos.GetProcessInfoAtIndex(i);
+ if (proc_info.GetArchitecture().GetTriple().getOS() == llvm::Triple::IOS) {
+ process_infos.Append(proc_info);
+ }
+ }
+ return process_infos.GetSize();
+}
+
+bool
+PlatformiOSSimulator::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ static const ArchSpec platform_arch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
+ static const ArchSpec platform_arch64(HostInfo::GetArchitecture(HostInfo::eArchKind64));
+
+ if (idx == 0)
+ {
+ arch = platform_arch;
+ if (arch.IsValid())
+ {
+ arch.GetTriple().setOS (llvm::Triple::IOS);
+ return true;
+ }
+ }
+ else
+ {
+ if (platform_arch.IsExactMatch(platform_arch64))
+ {
+ // This macosx platform supports both 32 and 64 bit.
+ if (idx == 1)
+ {
+ // 32/64: return "x86_64-apple-macosx" for architecture 1
+ arch = platform_arch64;
+ return true;
+ }
+ else if (idx == 2 || idx == 3)
+ {
+ arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
+ if (arch.IsValid())
+ {
+ if (idx == 2)
+ arch.GetTriple().setOS (llvm::Triple::IOS);
+ // 32/64: return "i386-apple-ios" for architecture 2
+ // 32/64: return "i386-apple-macosx" for architecture 3
+ return true;
+ }
+ }
+ }
+ else if (idx == 1)
+ {
+ // This macosx platform supports only 32 bit, so return the *-apple-macosx version
+ arch = platform_arch;
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h b/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h
new file mode 100644
index 000000000000..f84d04b9c485
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h
@@ -0,0 +1,116 @@
+//===-- PlatformiOSSimulator.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_PlatformiOSSimulator_h_
+#define liblldb_PlatformiOSSimulator_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "PlatformAppleSimulator.h"
+
+class PlatformiOSSimulator : public PlatformAppleSimulator
+{
+public:
+ PlatformiOSSimulator ();
+
+ ~PlatformiOSSimulator() override;
+
+ //------------------------------------------------------------
+ // Class Functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ static const char *
+ GetDescriptionStatic();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override
+ {
+ return GetPluginNameStatic();
+ }
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ lldb_private::Error
+ ResolveExecutable (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr) override;
+
+ const char *
+ GetDescription () override
+ {
+ return GetDescriptionStatic();
+ }
+
+ void
+ GetStatus (lldb_private::Stream &strm) override;
+
+ virtual lldb_private::Error
+ GetSymbolFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ uint32_t
+ FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos) override;
+
+ bool
+ GetSupportedArchitectureAtIndex (uint32_t idx,
+ lldb_private::ArchSpec &arch) override;
+
+ void
+ AddClangModuleCompilationOptions (lldb_private::Target *target, std::vector<std::string> &options) override
+ {
+ return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(target, options, PlatformDarwin::SDKType::iPhoneSimulator);
+ }
+
+protected:
+ std::string m_sdk_directory;
+ std::string m_build_update;
+
+ const char *
+ GetSDKDirectoryAsCString();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformiOSSimulator);
+};
+
+#endif // liblldb_PlatformiOSSimulator_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.h b/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.h
new file mode 100644
index 000000000000..8393ea304906
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.h
@@ -0,0 +1,315 @@
+//===-- PlatformiOSSimulatorCoreSimulatorSupport.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_PlatformiOSSimulatorCoreSimulatorSupport_h_
+#define liblldb_PlatformiOSSimulatorCoreSimulatorSupport_h_
+
+// C Includes
+// C++ Includes
+#include <functional>
+#include <string>
+#include <ostream>
+#include <vector>
+// Other libraries and framework includes
+#ifdef __APPLE__
+#include <objc/objc.h>
+#else
+typedef void *id;
+#endif
+// Project includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+
+#include "llvm/ADT/Optional.h"
+
+// And now the actual magic
+namespace CoreSimulatorSupport
+{
+ class Process
+ {
+ public:
+ lldb::pid_t
+ GetPID ()
+ {
+ return m_pid;
+ }
+
+ explicit operator bool ()
+ {
+ return m_pid != LLDB_INVALID_PROCESS_ID;
+ }
+
+ lldb_private::Error
+ GetError ()
+ {
+ return m_error;
+ }
+
+ private:
+ Process (lldb::pid_t p);
+
+ Process(lldb_private::Error error);
+
+ Process (lldb::pid_t p, lldb_private::Error error);
+
+ lldb::pid_t m_pid;
+ lldb_private::Error m_error;
+
+ friend class Device;
+ };
+
+ class ModelIdentifier {
+ public:
+ ModelIdentifier (const std::string& mi);
+ ModelIdentifier ();
+
+ explicit operator bool () const
+ {
+ return !m_versions.empty();
+ }
+
+ size_t
+ GetNumVersions () const
+ {
+ return m_versions.size();
+ }
+
+ unsigned int
+ GetVersionAtIndex (size_t idx) const
+ {
+ return m_versions[idx];
+ }
+
+ std::string
+ GetFamily () const
+ {
+ return m_family.c_str();
+ }
+
+ private:
+ std::string m_family;
+ std::vector<unsigned int> m_versions;
+ };
+
+ class DeviceType
+ {
+ public:
+ enum class ProductFamilyID : int32_t
+ {
+ iPhone = 1,
+ iPad = 2,
+ appleTV = 3,
+ appleWatch = 4
+ };
+
+ DeviceType ();
+
+ DeviceType (id d);
+
+ explicit operator bool ();
+
+ std::string
+ GetName ();
+
+ lldb_private::ConstString
+ GetIdentifier ();
+
+ ModelIdentifier
+ GetModelIdentifier ();
+
+ lldb_private::ConstString
+ GetProductFamily ();
+
+ ProductFamilyID
+ GetProductFamilyID ();
+
+ private:
+ id m_dev;
+ llvm::Optional<ModelIdentifier> m_model_identifier;
+ };
+
+ class OSVersion {
+ public:
+ OSVersion (const std::string& ver,
+ const std::string& build);
+
+ OSVersion ();
+
+ explicit operator bool () const
+ {
+ return !m_versions.empty();
+ }
+
+ size_t
+ GetNumVersions () const
+ {
+ return m_versions.size();
+ }
+
+ unsigned int
+ GetVersionAtIndex (size_t idx) const
+ {
+ return m_versions[idx];
+ }
+
+ const char*
+ GetBuild () const
+ {
+ return m_build.c_str();
+ }
+
+ private:
+ std::vector<unsigned int> m_versions;
+ std::string m_build;
+ };
+
+ class DeviceRuntime
+ {
+ public:
+ DeviceRuntime ();
+
+ DeviceRuntime (id d);
+
+ explicit operator bool ();
+
+ OSVersion
+ GetVersion ();
+
+ bool
+ IsAvailable ();
+
+ private:
+ id m_dev;
+ llvm::Optional<OSVersion> m_os_version;
+ };
+
+ class Device
+ {
+ private:
+ typedef unsigned long int NSUInteger;
+
+ public:
+ enum class State : NSUInteger
+ {
+ Creating,
+ Shutdown,
+ Booting,
+ Booted,
+ ShuttingDown
+ };
+
+ Device ();
+
+ Device (id d);
+
+ explicit operator bool ();
+
+ std::string
+ GetName () const;
+
+ DeviceType
+ GetDeviceType ();
+
+ DeviceRuntime
+ GetDeviceRuntime ();
+
+ State
+ GetState ();
+
+ bool
+ Boot (lldb_private::Error &err);
+
+ bool
+ Shutdown (lldb_private::Error &err);
+
+ std::string
+ GetUDID () const;
+
+ Process
+ Spawn (lldb_private::ProcessLaunchInfo& launch_info);
+
+ private:
+ id m_dev;
+ llvm::Optional<DeviceType> m_dev_type;
+ llvm::Optional<DeviceRuntime> m_dev_runtime;
+
+ friend class DeviceSet;
+ };
+
+ bool
+ operator > (const OSVersion& lhs,
+ const OSVersion& rhs);
+
+ bool
+ operator > (const ModelIdentifier& lhs,
+ const ModelIdentifier& rhs);
+
+ bool
+ operator < (const OSVersion& lhs,
+ const OSVersion& rhs);
+
+ bool
+ operator < (const ModelIdentifier& lhs,
+ const ModelIdentifier& rhs);
+
+ bool
+ operator == (const OSVersion& lhs,
+ const OSVersion& rhs);
+
+ bool
+ operator == (const ModelIdentifier& lhs,
+ const ModelIdentifier& rhs);
+
+ bool
+ operator != (const OSVersion& lhs,
+ const OSVersion& rhs);
+
+ bool
+ operator != (const ModelIdentifier& lhs,
+ const ModelIdentifier& rhs);
+
+ class DeviceSet
+ {
+ public:
+ static DeviceSet
+ GetAllDevices ();
+
+ static DeviceSet
+ GetAvailableDevices ();
+
+ size_t
+ GetNumDevices ();
+
+ Device
+ GetDeviceAtIndex (size_t idx);
+
+ void
+ ForEach (std::function<bool(const Device &)> f);
+
+ DeviceSet
+ GetDevicesIf (std::function<bool(Device)> f);
+
+ DeviceSet
+ GetDevices (DeviceType::ProductFamilyID dev_id);
+
+ Device
+ GetFanciest (DeviceType::ProductFamilyID dev_id);
+
+ private:
+ DeviceSet (id arr) : m_dev(arr)
+ {
+ }
+
+ id m_dev;
+ };
+}
+
+#endif // liblldb_PlatformiOSSimulatorCoreSimulatorSupport_h_
diff --git a/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm b/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm
new file mode 100644
index 000000000000..7075de552529
--- /dev/null
+++ b/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm
@@ -0,0 +1,773 @@
+//===-- PlatformiOSSimulatorCoreSimulatorSupport.cpp ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformiOSSimulatorCoreSimulatorSupport.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
+// Project includes
+#include "lldb/Target/FileAction.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb_private;
+using namespace lldb_utility;
+// CoreSimulator lives as part of Xcode, which means we can't really link against it, so we dlopen()
+// it at runtime, and error out nicely if that fails
+@interface SimDeviceSet
+{}
++ (id) defaultSet;
+@end
+// However, the drawback is that the compiler will not know about the selectors we're trying to use
+// until runtime; to appease clang in this regard, define a fake protocol on NSObject that exposes
+// the needed interface names for us
+@protocol LLDBCoreSimulatorSupport <NSObject>
+- (NSArray *) devices;
+- (id) deviceType;
+- (NSString *) name;
+- (NSString *) identifier;
+- (NSString *) modelIdentifier;
+- (NSString *) productFamily;
+- (int32_t) productFamilyID;
+- (id) runtime;
+- (BOOL) available;
+- (NSString *) versionString;
+- (NSString *) buildVersionString;
+- (BOOL) bootWithOptions:(NSDictionary *)options error:(NSError**)error;
+- (NSUInteger) state;
+- (BOOL) shutdownWithError:(NSError **)error;
+- (NSUUID *) UDID;
+- (pid_t) spawnWithPath:(NSString *)path options:(NSDictionary *)options terminationHandler:(void (^)(int status)) terminationHandler error:(NSError **)error;
+@end
+
+CoreSimulatorSupport::Process::Process (lldb::pid_t p) :
+ m_pid (p),
+ m_error ()
+{
+}
+
+CoreSimulatorSupport::Process::Process(Error error) :
+ m_pid (LLDB_INVALID_PROCESS_ID),
+ m_error (error)
+{
+}
+
+CoreSimulatorSupport::Process::Process (lldb::pid_t p, Error error) :
+ m_pid (p),
+ m_error (error)
+{
+}
+
+
+CoreSimulatorSupport::DeviceType::DeviceType () :
+ m_dev (nil),
+ m_model_identifier ()
+{
+}
+
+CoreSimulatorSupport::DeviceType::DeviceType (id d) :
+ m_dev (d),
+ m_model_identifier ()
+{
+}
+
+CoreSimulatorSupport::DeviceType::operator bool ()
+{
+ return m_dev != nil;
+}
+
+ConstString
+CoreSimulatorSupport::DeviceType::GetIdentifier ()
+{
+ return ConstString( [[m_dev identifier] UTF8String] );
+}
+
+ConstString
+CoreSimulatorSupport::DeviceType::GetProductFamily ()
+{
+ return ConstString( [[m_dev productFamily] UTF8String] );
+}
+
+CoreSimulatorSupport::DeviceType::ProductFamilyID
+CoreSimulatorSupport::DeviceType::GetProductFamilyID ()
+{
+ return ProductFamilyID([m_dev productFamilyID]);
+}
+
+CoreSimulatorSupport::DeviceRuntime::DeviceRuntime () :
+ m_dev (nil),
+ m_os_version ()
+{
+}
+
+CoreSimulatorSupport::DeviceRuntime::DeviceRuntime (id d) :
+ m_dev (d),
+ m_os_version ()
+{
+}
+
+CoreSimulatorSupport::DeviceRuntime::operator bool ()
+{
+ return m_dev != nil;
+}
+
+bool
+CoreSimulatorSupport::DeviceRuntime::IsAvailable ()
+{
+ return [m_dev available];
+}
+
+CoreSimulatorSupport::Device::Device () :
+ m_dev (nil),
+ m_dev_type (),
+ m_dev_runtime ()
+{
+}
+
+CoreSimulatorSupport::Device::Device (id d) :
+ m_dev (d),
+ m_dev_type (),
+ m_dev_runtime ()
+{
+}
+
+CoreSimulatorSupport::Device::operator bool ()
+{
+ return m_dev != nil;
+}
+
+CoreSimulatorSupport::Device::State
+CoreSimulatorSupport::Device::GetState ()
+{
+ return (State)([m_dev state]);
+}
+
+CoreSimulatorSupport::ModelIdentifier::ModelIdentifier (const std::string& mi) :
+ m_family (),
+ m_versions ()
+{
+ bool any = false;
+ bool first_digit = false;
+ unsigned int val = 0;
+
+ for (char c : mi)
+ {
+ any = true;
+ if (::isdigit(c))
+ {
+ if (!first_digit)
+ first_digit = true;
+ val = 10*val + (c - '0');
+ }
+ else if (c == ',')
+ {
+ if (first_digit)
+ {
+ m_versions.push_back(val);
+ val = 0;
+ }
+ else
+ m_family.push_back(c);
+ }
+ else
+ {
+ if (first_digit)
+ {
+ m_family.clear();
+ m_versions.clear();
+ return;
+ }
+ else
+ {
+ m_family.push_back(c);
+ }
+ }
+ }
+
+ if (first_digit)
+ m_versions.push_back(val);
+}
+
+CoreSimulatorSupport::ModelIdentifier::ModelIdentifier () :
+ModelIdentifier("")
+{
+}
+
+CoreSimulatorSupport::OSVersion::OSVersion (const std::string& ver,
+ const std::string& build) :
+ m_versions (),
+ m_build (build)
+{
+ bool any = false;
+ unsigned int val = 0;
+ for (char c : ver)
+ {
+ if (c == '.')
+ {
+ m_versions.push_back(val);
+ val = 0;
+ }
+ else if (::isdigit(c))
+ {
+ val = 10*val + (c - '0');
+ any = true;
+ }
+ else
+ {
+ m_versions.clear();
+ return;
+ }
+ }
+ if (any)
+ m_versions.push_back(val);
+}
+
+CoreSimulatorSupport::OSVersion::OSVersion () :
+ OSVersion("","")
+{
+}
+
+CoreSimulatorSupport::ModelIdentifier
+CoreSimulatorSupport::DeviceType::GetModelIdentifier ()
+{
+ if (!m_model_identifier.hasValue())
+ {
+ auto utf8_model_id = [[m_dev modelIdentifier] UTF8String];
+ if (utf8_model_id && *utf8_model_id)
+ m_model_identifier = ModelIdentifier (utf8_model_id);
+ }
+
+ if (m_model_identifier.hasValue())
+ return m_model_identifier.getValue();
+ else
+ return ModelIdentifier();
+}
+
+CoreSimulatorSupport::OSVersion
+CoreSimulatorSupport::DeviceRuntime::GetVersion ()
+{
+ if (!m_os_version.hasValue())
+ {
+ auto utf8_ver_string = [[m_dev versionString] UTF8String];
+ auto utf8_build_ver = [[m_dev buildVersionString] UTF8String];
+ if (utf8_ver_string && *utf8_ver_string &&
+ utf8_build_ver && *utf8_build_ver)
+ {
+ m_os_version = OSVersion(utf8_ver_string, utf8_build_ver);
+ }
+ }
+
+ if (m_os_version.hasValue())
+ return m_os_version.getValue();
+ return OSVersion();
+}
+
+std::string
+CoreSimulatorSupport::DeviceType::GetName ()
+{
+ auto utf8_name = [[m_dev name] UTF8String];
+ if (utf8_name)
+ return std::string(utf8_name);
+ return "";
+}
+
+std::string
+CoreSimulatorSupport::Device::GetName () const
+{
+ auto utf8_name = [[m_dev name] UTF8String];
+ if (utf8_name)
+ return std::string(utf8_name);
+ return "";
+}
+
+std::string
+CoreSimulatorSupport::Device::GetUDID () const
+{
+ auto utf8_udid = [ [[m_dev UDID] UUIDString] UTF8String];
+ if (utf8_udid)
+ return std::string(utf8_udid);
+ else
+ return std::string();
+}
+
+CoreSimulatorSupport::DeviceType
+CoreSimulatorSupport::Device::GetDeviceType ()
+{
+ if (!m_dev_type.hasValue())
+ m_dev_type = DeviceType([m_dev deviceType]);
+
+ return m_dev_type.getValue();
+}
+
+CoreSimulatorSupport::DeviceRuntime
+CoreSimulatorSupport::Device::GetDeviceRuntime ()
+{
+ if (!m_dev_runtime.hasValue())
+ m_dev_runtime = DeviceRuntime([m_dev runtime]);
+
+ return m_dev_runtime.getValue();
+}
+
+bool
+CoreSimulatorSupport::operator > (const CoreSimulatorSupport::OSVersion& lhs,
+ const CoreSimulatorSupport::OSVersion& rhs)
+{
+ for (size_t i = 0;
+ i < rhs.GetNumVersions();
+ i++)
+ {
+ unsigned int l = lhs.GetVersionAtIndex(i);
+ unsigned int r = rhs.GetVersionAtIndex(i);
+ if (l > r)
+ return true;
+ }
+ return false;
+}
+
+bool
+CoreSimulatorSupport::operator > (const CoreSimulatorSupport::ModelIdentifier& lhs,
+ const CoreSimulatorSupport::ModelIdentifier& rhs)
+{
+ if (lhs.GetFamily() != rhs.GetFamily())
+ return false;
+ for (size_t i = 0;
+ i < rhs.GetNumVersions();
+ i++)
+ {
+ unsigned int l = lhs.GetVersionAtIndex(i);
+ unsigned int r = rhs.GetVersionAtIndex(i);
+ if (l > r)
+ return true;
+ }
+ return false;
+}
+
+bool
+CoreSimulatorSupport::operator < (const CoreSimulatorSupport::OSVersion& lhs,
+ const CoreSimulatorSupport::OSVersion& rhs)
+{
+ for (size_t i = 0;
+ i < rhs.GetNumVersions();
+ i++)
+ {
+ unsigned int l = lhs.GetVersionAtIndex(i);
+ unsigned int r = rhs.GetVersionAtIndex(i);
+ if (l < r)
+ return true;
+ }
+ return false;
+}
+
+bool
+CoreSimulatorSupport::operator < (const CoreSimulatorSupport::ModelIdentifier& lhs,
+ const CoreSimulatorSupport::ModelIdentifier& rhs)
+{
+ if (lhs.GetFamily() != rhs.GetFamily())
+ return false;
+
+ for (size_t i = 0;
+ i < rhs.GetNumVersions();
+ i++)
+ {
+ unsigned int l = lhs.GetVersionAtIndex(i);
+ unsigned int r = rhs.GetVersionAtIndex(i);
+ if (l < r)
+ return true;
+ }
+ return false;
+}
+
+bool
+CoreSimulatorSupport::operator == (const CoreSimulatorSupport::OSVersion& lhs,
+ const CoreSimulatorSupport::OSVersion& rhs)
+{
+ for (size_t i = 0;
+ i < rhs.GetNumVersions();
+ i++)
+ {
+ unsigned int l = lhs.GetVersionAtIndex(i);
+ unsigned int r = rhs.GetVersionAtIndex(i);
+ if (l != r)
+ return false;
+ }
+ return true;
+}
+
+bool
+CoreSimulatorSupport::operator == (const CoreSimulatorSupport::ModelIdentifier& lhs,
+ const CoreSimulatorSupport::ModelIdentifier& rhs)
+{
+ if (lhs.GetFamily() != rhs.GetFamily())
+ return false;
+
+ for (size_t i = 0;
+ i < rhs.GetNumVersions();
+ i++)
+ {
+ unsigned int l = lhs.GetVersionAtIndex(i);
+ unsigned int r = rhs.GetVersionAtIndex(i);
+ if (l != r)
+ return false;
+ }
+ return true;
+}
+
+bool
+CoreSimulatorSupport::operator != (const CoreSimulatorSupport::OSVersion& lhs,
+ const CoreSimulatorSupport::OSVersion& rhs)
+{
+ for (size_t i = 0;
+ i < rhs.GetNumVersions();
+ i++)
+ {
+ unsigned int l = lhs.GetVersionAtIndex(i);
+ unsigned int r = rhs.GetVersionAtIndex(i);
+ if (l != r)
+ return true;
+ }
+ return false;
+}
+
+bool
+CoreSimulatorSupport::operator != (const CoreSimulatorSupport::ModelIdentifier& lhs,
+ const CoreSimulatorSupport::ModelIdentifier& rhs)
+{
+ if (lhs.GetFamily() != rhs.GetFamily())
+ return false;
+
+ for (size_t i = 0;
+ i < rhs.GetNumVersions();
+ i++)
+ {
+ unsigned int l = lhs.GetVersionAtIndex(i);
+ unsigned int r = rhs.GetVersionAtIndex(i);
+ if (l != r)
+ return true;
+ }
+ return false;
+}
+
+bool
+CoreSimulatorSupport::Device::Boot (Error &err)
+{
+ if (m_dev == nil)
+ {
+ err.SetErrorString("no valid simulator instance");
+ return false;
+ }
+
+#define kSimDeviceBootEnv @"env" /* An NSDictionary of "extra" environment key/values */
+#define kSimDeviceBootPersist @"persist" /* An NSNumber (boolean) indicating whether or not the session should outlive the calling process (default false) */
+#define kSimDeviceBootDisabledJobs @"disabled_jobs" /* An NSDictionary of NSStrings -> NSNumbers, each string is the name of a job, and the value is the corresponding state (true if disabled) */
+
+ NSDictionary *options = @{
+ kSimDeviceBootPersist : @NO,
+ kSimDeviceBootDisabledJobs : @{@"com.apple.backboardd" : @YES}
+ };
+
+#undef kSimDeviceBootEnv
+#undef kSimDeviceBootPersist
+#undef kSimDeviceBootDisabledJobs
+
+ NSError* nserror;
+ if ([m_dev bootWithOptions:options error:&nserror])
+ {
+ err.Clear();
+ return true;
+ }
+ else
+ {
+ err.SetErrorString([[nserror description] UTF8String]);
+ return false;
+ }
+}
+
+bool
+CoreSimulatorSupport::Device::Shutdown (Error &err)
+{
+ NSError* nserror;
+ if ([m_dev shutdownWithError:&nserror])
+ {
+ err.Clear();
+ return true;
+ }
+ else
+ {
+ err.SetErrorString([[nserror description] UTF8String]);
+ return false;
+ }
+}
+
+
+static Error
+HandleFileAction(ProcessLaunchInfo& launch_info,
+ NSMutableDictionary *options,
+ NSString *key,
+ const int fd,
+ File &file)
+{
+ Error error;
+ const FileAction *file_action = launch_info.GetFileActionForFD (fd);
+ if (file_action)
+ {
+ switch (file_action->GetAction())
+ {
+ case FileAction::eFileActionNone:
+ break;
+
+ case FileAction::eFileActionClose:
+ error.SetErrorStringWithFormat ("close file action for %i not supported", fd);
+ break;
+
+ case FileAction::eFileActionDuplicate:
+ error.SetErrorStringWithFormat ("duplication file action for %i not supported", fd);
+ break;
+
+ case FileAction::eFileActionOpen:
+ {
+ FileSpec file_spec = file_action->GetFileSpec();
+ if (file_spec)
+ {
+ const int master_fd = launch_info.GetPTY().GetMasterFileDescriptor();
+ if (master_fd != PseudoTerminal::invalid_fd)
+ {
+ // Check in case our file action open wants to open the slave
+ const char *slave_path = launch_info.GetPTY().GetSlaveName(NULL, 0);
+ if (slave_path)
+ {
+ FileSpec slave_spec(slave_path, false);
+ if (file_spec == slave_spec)
+ {
+ int slave_fd = launch_info.GetPTY().GetSlaveFileDescriptor();
+ if (slave_fd == PseudoTerminal::invalid_fd)
+ slave_fd = launch_info.GetPTY().OpenSlave(O_RDWR, nullptr, 0);
+ if (slave_fd == PseudoTerminal::invalid_fd)
+ {
+ error.SetErrorStringWithFormat("unable to open slave pty '%s'", slave_path);
+ return error; // Failure
+ }
+ [options setValue:[NSNumber numberWithInteger:slave_fd] forKey:key];
+ return error; // Success
+ }
+ }
+ }
+ Error posix_error;
+ int created_fd = open(file_spec.GetPath().c_str(), file_action->GetActionArgument(), S_IRUSR | S_IWUSR);
+ if (created_fd >= 0)
+ {
+ file.SetDescriptor(created_fd, true);
+ [options setValue:[NSNumber numberWithInteger:created_fd] forKey:key];
+ return error; // Success
+ }
+ else
+ {
+ posix_error.SetErrorToErrno();
+ error.SetErrorStringWithFormat("unable to open file '%s': %s", file_spec.GetPath().c_str(), posix_error.AsCString());
+ }
+ }
+ }
+ break;
+ }
+ }
+ return error; // Success, no file action, nothing to do
+}
+
+CoreSimulatorSupport::Process
+CoreSimulatorSupport::Device::Spawn (ProcessLaunchInfo& launch_info)
+{
+#define kSimDeviceSpawnEnvironment @"environment" /* An NSDictionary (NSStrings -> NSStrings) of environment key/values */
+#define kSimDeviceSpawnStdin @"stdin" /* An NSNumber corresponding to a fd */
+#define kSimDeviceSpawnStdout @"stdout" /* An NSNumber corresponding to a fd */
+#define kSimDeviceSpawnStderr @"stderr" /* An NSNumber corresponding to a fd */
+#define kSimDeviceSpawnArguments @"arguments" /* An NSArray of strings to use as the argv array. If not provided, path will be argv[0] */
+#define kSimDeviceSpawnWaitForDebugger @"wait_for_debugger" /* An NSNumber (bool) */
+
+ NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
+
+ if (launch_info.GetFlags().Test(lldb::eLaunchFlagDebug))
+ [options setObject:@YES forKey:kSimDeviceSpawnWaitForDebugger];
+
+ if (launch_info.GetArguments().GetArgumentCount())
+ {
+ const Args& args(launch_info.GetArguments());
+ NSMutableArray *args_array = [[NSMutableArray alloc] init];
+ for (size_t idx = 0;
+ idx < args.GetArgumentCount();
+ idx++)
+ [args_array addObject:[NSString stringWithUTF8String:args.GetArgumentAtIndex(idx)]];
+
+ [options setObject:args_array forKey:kSimDeviceSpawnArguments];
+ }
+
+ if (launch_info.GetEnvironmentEntries().GetArgumentCount())
+ {
+ const Args& envs(launch_info.GetEnvironmentEntries());
+ NSMutableDictionary *env_dict = [[NSMutableDictionary alloc] init];
+ for (size_t idx = 0;
+ idx < envs.GetArgumentCount();
+ idx++)
+ {
+ llvm::StringRef arg_sr(envs.GetArgumentAtIndex(idx));
+ auto first_eq = arg_sr.find('=');
+ if (first_eq == llvm::StringRef::npos)
+ continue;
+ llvm::StringRef key = arg_sr.substr(0, first_eq);
+ llvm::StringRef value = arg_sr.substr(first_eq+1);
+
+ NSString *key_ns = [NSString stringWithUTF8String:key.str().c_str()];
+ NSString *value_ns = [NSString stringWithUTF8String:value.str().c_str()];
+
+ [env_dict setValue:value_ns forKey:key_ns];
+ }
+
+ [options setObject:env_dict forKey:kSimDeviceSpawnEnvironment];
+ }
+
+ Error error;
+ File stdin_file;
+ File stdout_file;
+ File stderr_file;
+ error = HandleFileAction(launch_info, options, kSimDeviceSpawnStdin, STDIN_FILENO, stdin_file);
+
+ if (error.Fail())
+ return CoreSimulatorSupport::Process(error);
+
+ error = HandleFileAction(launch_info, options, kSimDeviceSpawnStdout, STDOUT_FILENO, stdout_file);
+
+ if (error.Fail())
+ return CoreSimulatorSupport::Process(error);
+
+ error = HandleFileAction(launch_info, options, kSimDeviceSpawnStderr, STDERR_FILENO, stderr_file);
+
+ if (error.Fail())
+ return CoreSimulatorSupport::Process(error);
+
+#undef kSimDeviceSpawnEnvironment
+#undef kSimDeviceSpawnStdin
+#undef kSimDeviceSpawnStdout
+#undef kSimDeviceSpawnStderr
+#undef kSimDeviceSpawnWaitForDebugger
+#undef kSimDeviceSpawnArguments
+
+ NSError* nserror;
+
+ pid_t pid = [m_dev spawnWithPath: [NSString stringWithUTF8String: launch_info.GetExecutableFile().GetPath().c_str()]
+ options: options
+ terminationHandler: nil
+ error: &nserror];
+
+
+ if (pid < 0)
+ {
+ const char* nserror_string = [[nserror description] UTF8String];
+ error.SetErrorString(nserror_string ? nserror_string : "unable to launch");
+ }
+
+ return CoreSimulatorSupport::Process (pid, error);
+}
+
+CoreSimulatorSupport::DeviceSet
+CoreSimulatorSupport::DeviceSet::GetAllDevices ()
+{
+ return DeviceSet([[NSClassFromString(@"SimDeviceSet") defaultSet] devices]);
+}
+
+CoreSimulatorSupport::DeviceSet
+CoreSimulatorSupport::DeviceSet::GetAvailableDevices ()
+{
+ return GetAllDevices().GetDevicesIf( [] (Device d) -> bool {
+ return (d && d.GetDeviceType() && d.GetDeviceRuntime() && d.GetDeviceRuntime().IsAvailable());
+ });
+}
+
+size_t
+CoreSimulatorSupport::DeviceSet::GetNumDevices ()
+{
+ return [m_dev count];
+}
+
+CoreSimulatorSupport::Device
+CoreSimulatorSupport::DeviceSet::GetDeviceAtIndex (size_t idx)
+{
+ if (idx < GetNumDevices())
+ return Device([m_dev objectAtIndex:idx]);
+ return Device();
+}
+
+CoreSimulatorSupport::DeviceSet
+CoreSimulatorSupport::DeviceSet::GetDevicesIf (std::function<bool(CoreSimulatorSupport::Device)> f)
+{
+ NSMutableArray *array = [[NSMutableArray alloc] init];
+ for (NSUInteger i = 0;
+ i < GetNumDevices();
+ i++)
+ {
+ Device d(GetDeviceAtIndex(i));
+ if (f(d))
+ [array addObject:(id)d.m_dev];
+ }
+
+ return DeviceSet(array);
+}
+
+void
+CoreSimulatorSupport::DeviceSet::ForEach (std::function<bool(const Device &)> f)
+{
+ const size_t n = GetNumDevices();
+ for (NSUInteger i = 0; i < n; ++i)
+ {
+ if (f(GetDeviceAtIndex(i)) == false)
+ break;
+ }
+}
+
+CoreSimulatorSupport::DeviceSet
+CoreSimulatorSupport::DeviceSet::GetDevices (CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id)
+{
+ NSMutableArray *array = [[NSMutableArray alloc] init];
+ const size_t n = GetNumDevices();
+ for (NSUInteger i = 0; i < n; ++i)
+ {
+ Device d(GetDeviceAtIndex(i));
+ if (d && d.GetDeviceType() && d.GetDeviceType().GetProductFamilyID() == dev_id)
+ [array addObject:(id)d.m_dev];
+ }
+
+ return DeviceSet(array);
+}
+
+CoreSimulatorSupport::Device
+CoreSimulatorSupport::DeviceSet::GetFanciest (CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id)
+{
+ Device dev;
+
+ for (NSUInteger i = 0;
+ i < GetNumDevices();
+ i++)
+ {
+ Device d(GetDeviceAtIndex(i));
+ if (d && d.GetDeviceType() && d.GetDeviceType().GetProductFamilyID() == dev_id)
+ {
+ if (!dev)
+ dev = d;
+ else
+ {
+ if ((d.GetDeviceType().GetModelIdentifier() > dev.GetDeviceType().GetModelIdentifier()) ||
+ d.GetDeviceRuntime().GetVersion() > dev.GetDeviceRuntime().GetVersion())
+ dev = d;
+ }
+ }
+ }
+
+ return dev;
+}
diff --git a/source/Plugins/Platform/Makefile b/source/Plugins/Platform/Makefile
new file mode 100644
index 000000000000..572b08644074
--- /dev/null
+++ b/source/Plugins/Platform/Makefile
@@ -0,0 +1,36 @@
+##===- source/Plugins/Platform/Makefile --------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../..
+
+include $(LLDB_LEVEL)/../../Makefile.config
+
+PARALLEL_DIRS := gdb-server MacOSX Linux FreeBSD NetBSD POSIX Windows Kalimba Android
+
+# ifeq ($(HOST_OS),Darwin)
+# DIRS += MacOSX
+# endif
+#
+# ifeq ($(HOST_OS),Linux)
+# DIRS += Linux
+# endif
+#
+# ifeq ($(HOST_OS),FreeBSD)
+# DIRS += FreeBSD
+# endif
+#
+# ifeq ($(HOST_OS),GNU/kFreeBSD)
+# DIRS += FreeBSD
+# endif
+#
+# ifeq ($(HOST_OS),NetBSD)
+# DIRS += NetBSD
+# endif
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Platform/NetBSD/CMakeLists.txt b/source/Plugins/Platform/NetBSD/CMakeLists.txt
new file mode 100644
index 000000000000..c70b419b98b4
--- /dev/null
+++ b/source/Plugins/Platform/NetBSD/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginPlatformNetBSD
+ PlatformNetBSD.cpp
+ )
diff --git a/source/Plugins/Platform/NetBSD/Makefile b/source/Plugins/Platform/NetBSD/Makefile
new file mode 100644
index 000000000000..2c480bdbe8da
--- /dev/null
+++ b/source/Plugins/Platform/NetBSD/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/NetBSD/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformNetBSD
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Platform/POSIX/CMakeLists.txt b/source/Plugins/Platform/POSIX/CMakeLists.txt
new file mode 100644
index 000000000000..c23e68155c2b
--- /dev/null
+++ b/source/Plugins/Platform/POSIX/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginPlatformPOSIX
+ PlatformPOSIX.cpp
+ )
diff --git a/source/Plugins/Platform/POSIX/Makefile b/source/Plugins/Platform/POSIX/Makefile
new file mode 100644
index 000000000000..eca927720ba8
--- /dev/null
+++ b/source/Plugins/Platform/POSIX/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/POSIX/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformPOSIX
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Platform/Windows/CMakeLists.txt b/source/Plugins/Platform/Windows/CMakeLists.txt
new file mode 100644
index 000000000000..09fbc11d33f2
--- /dev/null
+++ b/source/Plugins/Platform/Windows/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginPlatformWindows
+ PlatformWindows.cpp
+ )
diff --git a/source/Plugins/Platform/Windows/Makefile b/source/Plugins/Platform/Windows/Makefile
new file mode 100644
index 000000000000..b78cd7bfd080
--- /dev/null
+++ b/source/Plugins/Platform/Windows/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/Windows/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformWindows
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Platform/Windows/PlatformWindows.cpp b/source/Plugins/Platform/Windows/PlatformWindows.cpp
new file mode 100644
index 000000000000..4172f80176d3
--- /dev/null
+++ b/source/Plugins/Platform/Windows/PlatformWindows.cpp
@@ -0,0 +1,753 @@
+//===-- PlatformWindows.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformWindows.h"
+
+// C Includes
+#include <stdio.h>
+#if defined (_WIN32)
+#include "lldb/Host/windows/windows.h"
+#include <winsock2.h>
+#endif
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static uint32_t g_initialize_count = 0;
+
+namespace
+{
+ class SupportedArchList
+ {
+ public:
+ SupportedArchList()
+ {
+ AddArch(ArchSpec("i686-pc-windows"));
+ AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
+ AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32));
+ AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
+ AddArch(ArchSpec("i386-pc-windows"));
+ }
+
+ size_t Count() const { return m_archs.size(); }
+
+ const ArchSpec& operator[](int idx) { return m_archs[idx]; }
+
+ private:
+ void AddArch(const ArchSpec& spec)
+ {
+ auto iter = std::find_if(
+ m_archs.begin(), m_archs.end(),
+ [spec](const ArchSpec& rhs) { return spec.IsExactMatch(rhs); });
+ if (iter != m_archs.end())
+ return;
+ if (spec.IsValid())
+ m_archs.push_back(spec);
+ }
+
+ std::vector<ArchSpec> m_archs;
+ };
+} // anonymous namespace
+
+PlatformSP
+PlatformWindows::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
+{
+ // The only time we create an instance is when we are creating a remote
+ // windows platform
+ const bool is_host = false;
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::PC:
+ create = true;
+ break;
+
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+
+ default:
+ break;
+ }
+
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::Win32:
+ break;
+
+ case llvm::Triple::UnknownOS:
+ create = arch->TripleOSWasSpecified();
+ break;
+
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ if (create)
+ return PlatformSP(new PlatformWindows (is_host));
+ return PlatformSP();
+}
+
+lldb_private::ConstString
+PlatformWindows::GetPluginNameStatic(bool is_host)
+{
+ if (is_host)
+ {
+ static ConstString g_host_name(Platform::GetHostPlatformName ());
+ return g_host_name;
+ }
+ else
+ {
+ static ConstString g_remote_name("remote-windows");
+ return g_remote_name;
+ }
+}
+
+const char *
+PlatformWindows::GetPluginDescriptionStatic(bool is_host)
+{
+ return is_host ?
+ "Local Windows user platform plug-in." :
+ "Remote Windows user platform plug-in.";
+}
+
+lldb_private::ConstString
+PlatformWindows::GetPluginName()
+{
+ return GetPluginNameStatic(IsHost());
+}
+
+void
+PlatformWindows::Initialize()
+{
+ Platform::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+#if defined (_WIN32)
+ WSADATA dummy;
+ WSAStartup(MAKEWORD(2,2), &dummy);
+ // Force a host flag to true for the default platform object.
+ PlatformSP default_platform_sp (new PlatformWindows(true));
+ default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
+ Platform::SetHostPlatform (default_platform_sp);
+#endif
+ PluginManager::RegisterPlugin(PlatformWindows::GetPluginNameStatic(false),
+ PlatformWindows::GetPluginDescriptionStatic(false),
+ PlatformWindows::CreateInstance);
+ }
+}
+
+void
+PlatformWindows::Terminate( void )
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+#ifdef _WIN32
+ WSACleanup();
+#endif
+ PluginManager::UnregisterPlugin (PlatformWindows::CreateInstance);
+ }
+ }
+
+ Platform::Terminate ();
+}
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformWindows::PlatformWindows (bool is_host) :
+ Platform(is_host)
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformWindows::~PlatformWindows() = default;
+
+bool
+PlatformWindows::GetModuleSpec (const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec)
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetModuleSpec (module_file_spec, arch, module_spec);
+
+ return Platform::GetModuleSpec (module_file_spec, arch, module_spec);
+}
+
+Error
+PlatformWindows::ResolveExecutable (const ModuleSpec &ms,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ char exe_path[PATH_MAX];
+ ModuleSpec resolved_module_spec(ms);
+
+ if (IsHost())
+ {
+ // if we cant resolve the executable loation based on the current path variables
+ if (!resolved_module_spec.GetFileSpec().Exists())
+ {
+ resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
+ resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
+ }
+
+ if (!resolved_module_spec.GetFileSpec().Exists())
+ resolved_module_spec.GetFileSpec().ResolveExecutableLocation ();
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ error.Clear();
+ else
+ {
+ ms.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path);
+ }
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ {
+ error = GetCachedExecutable (resolved_module_spec, exe_module_sp, nullptr, *m_remote_platform_sp);
+ }
+ else
+ {
+ // We may connect to a process and use the provided executable (Don't use local $PATH).
+ if (resolved_module_spec.GetFileSpec().Exists())
+ error.Clear();
+ else
+ error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path);
+ }
+ }
+
+ if (error.Success())
+ {
+ if (resolved_module_spec.GetArchitecture().IsValid())
+ {
+ error = ModuleList::GetSharedModule(resolved_module_spec,
+ exe_module_sp,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (!exe_module_sp || exe_module_sp->GetObjectFile() == nullptr)
+ {
+ exe_module_sp.reset();
+ error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+ }
+ else
+ {
+ // No valid architecture was specified, ask the platform for
+ // the architectures that we should be using (in the correct order)
+ // and see if we can find a match that way
+ StreamString arch_names;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
+ {
+ error = ModuleList::GetSharedModule(resolved_module_spec,
+ exe_module_sp,
+ nullptr,
+ nullptr,
+ nullptr);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ if (resolved_module_spec.GetFileSpec().Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
+size_t
+PlatformWindows::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
+{
+ ArchSpec arch = target.GetArchitecture();
+ const uint8_t *trap_opcode = nullptr;
+ size_t trap_opcode_size = 0;
+
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ {
+ static const uint8_t g_i386_opcode[] = { 0xCC };
+ trap_opcode = g_i386_opcode;
+ trap_opcode_size = sizeof(g_i386_opcode);
+ }
+ break;
+
+ case llvm::Triple::hexagon:
+ {
+ static const uint8_t g_hex_opcode[] = { 0x0c, 0xdb, 0x00, 0x54 };
+ trap_opcode = g_hex_opcode;
+ trap_opcode_size = sizeof(g_hex_opcode);
+ }
+ break;
+ default:
+ llvm_unreachable("Unhandled architecture in PlatformWindows::GetSoftwareBreakpointTrapOpcode()");
+ break;
+ }
+
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+
+ return 0;
+}
+
+bool
+PlatformWindows::GetRemoteOSVersion ()
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetOSVersion (m_major_os_version,
+ m_minor_os_version,
+ m_update_os_version);
+ return false;
+}
+
+bool
+PlatformWindows::GetRemoteOSBuildString (std::string &s)
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteOSBuildString (s);
+ s.clear();
+ return false;
+}
+
+bool
+PlatformWindows::GetRemoteOSKernelDescription (std::string &s)
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteOSKernelDescription (s);
+ s.clear();
+ return false;
+}
+
+// Remote Platform subclasses need to override this function
+ArchSpec
+PlatformWindows::GetRemoteSystemArchitecture ()
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteSystemArchitecture ();
+ return ArchSpec();
+}
+
+const char *
+PlatformWindows::GetHostname ()
+{
+ if (IsHost())
+ return Platform::GetHostname();
+
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetHostname ();
+ return nullptr;
+}
+
+bool
+PlatformWindows::IsConnected () const
+{
+ if (IsHost())
+ return true;
+ else if (m_remote_platform_sp)
+ return m_remote_platform_sp->IsConnected();
+ return false;
+}
+
+Error
+PlatformWindows::ConnectRemote (Args& args)
+{
+ Error error;
+ if (IsHost())
+ {
+ error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().AsCString() );
+ }
+ else
+ {
+ if (!m_remote_platform_sp)
+ m_remote_platform_sp = Platform::Create (ConstString("remote-gdb-server"), error);
+
+ if (m_remote_platform_sp)
+ {
+ if (error.Success())
+ {
+ if (m_remote_platform_sp)
+ {
+ error = m_remote_platform_sp->ConnectRemote (args);
+ }
+ else
+ {
+ error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
+ }
+ }
+ }
+ else
+ error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
+
+ if (error.Fail())
+ m_remote_platform_sp.reset();
+ }
+
+ return error;
+}
+
+Error
+PlatformWindows::DisconnectRemote ()
+{
+ Error error;
+
+ if (IsHost())
+ {
+ error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().AsCString() );
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ error = m_remote_platform_sp->DisconnectRemote ();
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return error;
+}
+
+bool
+PlatformWindows::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ bool success = false;
+ if (IsHost())
+ {
+ success = Platform::GetProcessInfo (pid, process_info);
+ }
+ else if (m_remote_platform_sp)
+ {
+ success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
+ }
+ return success;
+}
+
+uint32_t
+PlatformWindows::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ uint32_t match_count = 0;
+ if (IsHost())
+ {
+ // Let the base class figure out the host details
+ match_count = Platform::FindProcesses (match_info, process_infos);
+ }
+ else
+ {
+ // If we are remote, we can only return results if we are connected
+ if (m_remote_platform_sp)
+ match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos);
+ }
+ return match_count;
+}
+
+Error
+PlatformWindows::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ if (IsHost())
+ {
+ error = Platform::LaunchProcess (launch_info);
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ error = m_remote_platform_sp->LaunchProcess (launch_info);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return error;
+}
+
+ProcessSP
+PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, Error &error)
+{
+ // Windows has special considerations that must be followed when launching or attaching to a process. The
+ // key requirement is that when launching or attaching to a process, you must do it from the same the thread
+ // that will go into a permanent loop which will then receive debug events from the process. In particular,
+ // this means we can't use any of LLDB's generic mechanisms to do it for us, because it doesn't have the
+ // special knowledge required for setting up the background thread or passing the right flags.
+ //
+ // Another problem is that that LLDB's standard model for debugging a process is to first launch it, have
+ // it stop at the entry point, and then attach to it. In Windows this doesn't quite work, you have to
+ // specify as an argument to CreateProcess() that you're going to debug the process. So we override DebugProcess
+ // here to handle this. Launch operations go directly to the process plugin, and attach operations almost go
+ // directly to the process plugin (but we hijack the events first). In essence, we encapsulate all the logic
+ // of Launching and Attaching in the process plugin, and PlatformWindows::DebugProcess is just a pass-through
+ // to get to the process plugin.
+
+ if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ {
+ // This is a process attach. Don't need to launch anything.
+ ProcessAttachInfo attach_info(launch_info);
+ return Attach(attach_info, debugger, target, error);
+ }
+ else
+ {
+ ProcessSP process_sp = target->CreateProcess(launch_info.GetListenerForProcess(debugger),
+ launch_info.GetProcessPluginName(),
+ nullptr);
+
+ // We need to launch and attach to the process.
+ launch_info.GetFlags().Set(eLaunchFlagDebug);
+ if (process_sp)
+ error = process_sp->Launch(launch_info);
+
+ return process_sp;
+ }
+}
+
+lldb::ProcessSP
+PlatformWindows::Attach(ProcessAttachInfo &attach_info,
+ Debugger &debugger,
+ Target *target,
+ Error &error)
+{
+ error.Clear();
+ lldb::ProcessSP process_sp;
+ if (!IsHost())
+ {
+ if (m_remote_platform_sp)
+ process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ return process_sp;
+ }
+
+ if (target == nullptr)
+ {
+ TargetSP new_target_sp;
+ FileSpec emptyFileSpec;
+ ArchSpec emptyArchSpec;
+
+ error = debugger.GetTargetList().CreateTarget(debugger,
+ nullptr,
+ nullptr,
+ false,
+ nullptr,
+ new_target_sp);
+ target = new_target_sp.get();
+ }
+
+ if (!target || error.Fail())
+ return process_sp;
+
+ debugger.GetTargetList().SetSelectedTarget(target);
+
+ const char *plugin_name = attach_info.GetProcessPluginName();
+ process_sp = target->CreateProcess(attach_info.GetListenerForProcess(debugger), plugin_name, nullptr);
+
+ process_sp->HijackProcessEvents(attach_info.GetHijackListener().get());
+ if (process_sp)
+ error = process_sp->Attach (attach_info);
+
+ return process_sp;
+}
+
+const char *
+PlatformWindows::GetUserName (uint32_t uid)
+{
+ // Check the cache in Platform in case we have already looked this uid up
+ const char *user_name = Platform::GetUserName(uid);
+ if (user_name)
+ return user_name;
+
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetUserName(uid);
+ return nullptr;
+}
+
+const char *
+PlatformWindows::GetGroupName (uint32_t gid)
+{
+ const char *group_name = Platform::GetGroupName(gid);
+ if (group_name)
+ return group_name;
+
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetGroupName(gid);
+ return nullptr;
+}
+
+Error
+PlatformWindows::GetFileWithUUID (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ if (IsRemote())
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file);
+ }
+
+ // Default to the local case
+ local_file = platform_file;
+ return Error();
+}
+
+Error
+PlatformWindows::GetSharedModule (const ModuleSpec &module_spec,
+ Process* process,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ Error error;
+ module_sp.reset();
+
+ if (IsRemote())
+ {
+ // If we have a remote platform always, let it try and locate
+ // the shared module first.
+ if (m_remote_platform_sp)
+ {
+ error = m_remote_platform_sp->GetSharedModule (module_spec,
+ process,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr);
+ }
+ }
+
+ if (!module_sp)
+ {
+ // Fall back to the local platform and find the file locally
+ error = Platform::GetSharedModule (module_spec,
+ process,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr);
+ }
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+ return error;
+}
+
+bool
+PlatformWindows::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ static SupportedArchList architectures;
+
+ if (idx >= architectures.Count())
+ return false;
+ arch = architectures[idx];
+ return true;
+}
+
+void
+PlatformWindows::GetStatus (Stream &strm)
+{
+ Platform::GetStatus(strm);
+
+#ifdef _WIN32
+ uint32_t major;
+ uint32_t minor;
+ uint32_t update;
+ if (!HostInfo::GetOSVersion(major, minor, update))
+ {
+ strm << "Windows";
+ return;
+ }
+
+ strm << "Host: Windows " << major
+ << '.' << minor
+ << " Build: " << update << '\n';
+#endif
+}
+
+bool
+PlatformWindows::CanDebugProcess()
+{
+ return true;
+}
+
+size_t
+PlatformWindows::GetEnvironment(StringList &env)
+{
+ if (IsRemote())
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetEnvironment(env);
+ return 0;
+ }
+
+ return Host::GetEnvironment(env);
+}
+
+ConstString
+PlatformWindows::GetFullNameForDylib (ConstString basename)
+{
+ if (basename.IsEmpty())
+ return basename;
+
+ StreamString stream;
+ stream.Printf("%s.dll", basename.GetCString());
+ return ConstString(stream.GetData());
+}
diff --git a/source/Plugins/Platform/Windows/PlatformWindows.h b/source/Plugins/Platform/Windows/PlatformWindows.h
new file mode 100644
index 000000000000..e9a04b4cc33d
--- /dev/null
+++ b/source/Plugins/Platform/Windows/PlatformWindows.h
@@ -0,0 +1,169 @@
+//===-- PlatformWindows.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_PlatformWindows_h_
+#define liblldb_PlatformWindows_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Platform.h"
+
+namespace lldb_private
+{
+
+class PlatformWindows : public Platform
+{
+public:
+ PlatformWindows(bool is_host);
+
+ ~PlatformWindows() override;
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic(bool is_host);
+
+ static const char *
+ GetPluginDescriptionStatic(bool is_host);
+
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ bool
+ GetModuleSpec (const lldb_private::FileSpec& module_file_spec,
+ const lldb_private::ArchSpec& arch,
+ lldb_private::ModuleSpec &module_spec) override;
+
+ Error
+ ResolveExecutable(const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr) override;
+
+ const char *
+ GetDescription() override
+ {
+ return GetPluginDescriptionStatic(IsHost());
+ }
+
+ size_t
+ GetSoftwareBreakpointTrapOpcode(lldb_private::Target &target,
+ lldb_private::BreakpointSite *bp_site) override;
+
+ bool
+ GetRemoteOSVersion() override;
+
+ bool
+ GetRemoteOSBuildString(std::string &s) override;
+
+ bool
+ GetRemoteOSKernelDescription(std::string &s) override;
+
+ // Remote Platform subclasses need to override this function
+ lldb_private::ArchSpec
+ GetRemoteSystemArchitecture() override;
+
+ bool
+ IsConnected() const override;
+
+ lldb_private::Error
+ ConnectRemote(lldb_private::Args& args) override;
+
+ lldb_private::Error
+ DisconnectRemote() override;
+
+ const char *
+ GetHostname() override;
+
+ const char *
+ GetUserName(uint32_t uid) override;
+
+ const char *
+ GetGroupName(uint32_t gid) override;
+
+ bool
+ GetProcessInfo(lldb::pid_t pid,
+ lldb_private::ProcessInstanceInfo &proc_info) override;
+
+ uint32_t
+ FindProcesses(const lldb_private::ProcessInstanceInfoMatch &match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos) override;
+
+ lldb_private::Error
+ LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) override;
+
+ lldb::ProcessSP
+ DebugProcess(lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Debugger &debugger,
+ lldb_private::Target *target, lldb_private::Error &error) override;
+
+ lldb::ProcessSP
+ Attach(lldb_private::ProcessAttachInfo &attach_info, lldb_private::Debugger &debugger,
+ lldb_private::Target *target, lldb_private::Error &error) override;
+
+ lldb_private::Error
+ GetFileWithUUID(const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID* uuid, lldb_private::FileSpec &local_file) override;
+
+ lldb_private::Error
+ GetSharedModule(const lldb_private::ModuleSpec &module_spec,
+ lldb_private::Process* process,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) override;
+
+ bool
+ GetSupportedArchitectureAtIndex(uint32_t idx, lldb_private::ArchSpec &arch) override;
+
+ void
+ GetStatus(lldb_private::Stream &strm) override;
+
+ bool CanDebugProcess() override;
+
+ size_t GetEnvironment(StringList &env) override;
+
+ // FIXME not sure what the _sigtramp equivalent would be on this platform
+ void
+ CalculateTrapHandlerSymbolNames () override
+ {
+ }
+
+ ConstString
+ GetFullNameForDylib (ConstString basename) override;
+
+protected:
+ lldb::PlatformSP m_remote_platform_sp;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformWindows);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_PlatformWindows_h_
diff --git a/source/Plugins/Platform/gdb-server/CMakeLists.txt b/source/Plugins/Platform/gdb-server/CMakeLists.txt
new file mode 100644
index 000000000000..b0b669e5b8b7
--- /dev/null
+++ b/source/Plugins/Platform/gdb-server/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginPlatformGDB
+ PlatformRemoteGDBServer.cpp
+ )
diff --git a/source/Plugins/Platform/gdb-server/Makefile b/source/Plugins/Platform/gdb-server/Makefile
new file mode 100644
index 000000000000..c56613b2a653
--- /dev/null
+++ b/source/Plugins/Platform/gdb-server/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/gdb-server/Makefile ---------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformGDB
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Process/CMakeLists.txt b/source/Plugins/Process/CMakeLists.txt
new file mode 100644
index 000000000000..d15df94414b3
--- /dev/null
+++ b/source/Plugins/Process/CMakeLists.txt
@@ -0,0 +1,19 @@
+if (CMAKE_SYSTEM_NAME MATCHES "Linux")
+ add_subdirectory(Linux)
+ add_subdirectory(POSIX)
+elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ add_subdirectory(FreeBSD)
+ add_subdirectory(POSIX)
+elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
+ add_subdirectory(POSIX)
+elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ add_subdirectory(Windows/Live)
+ add_subdirectory(Windows/MiniDump)
+ add_subdirectory(Windows/Common)
+elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ add_subdirectory(MacOSX-Kernel)
+endif()
+add_subdirectory(gdb-remote)
+add_subdirectory(Utility)
+add_subdirectory(mach-core)
+add_subdirectory(elf-core)
diff --git a/source/Plugins/Process/FreeBSD/CMakeLists.txt b/source/Plugins/Process/FreeBSD/CMakeLists.txt
new file mode 100644
index 000000000000..c0e3374fef89
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/CMakeLists.txt
@@ -0,0 +1,16 @@
+include_directories(.)
+include_directories(../POSIX)
+include_directories(../Utility)
+
+add_lldb_library(lldbPluginProcessFreeBSD
+ ProcessFreeBSD.cpp
+ FreeBSDThread.cpp
+ ProcessMonitor.cpp
+
+ POSIXStopInfo.cpp
+ RegisterContextPOSIXProcessMonitor_arm.cpp
+ RegisterContextPOSIXProcessMonitor_arm64.cpp
+ RegisterContextPOSIXProcessMonitor_powerpc.cpp
+ RegisterContextPOSIXProcessMonitor_x86.cpp
+ RegisterContextPOSIXProcessMonitor_mips64.cpp
+ )
diff --git a/source/Plugins/Process/FreeBSD/Makefile b/source/Plugins/Process/FreeBSD/Makefile
new file mode 100644
index 000000000000..7f546540e556
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/Makefile
@@ -0,0 +1,17 @@
+##===- source/Plugins/Process/FreeBSD/Makefile ---------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginProcessFreeBSD
+BUILD_ARCHIVE = 1
+
+# Extend the include path so we may locate UnwindLLDB.h
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/source/Plugins/Utility
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
index 3cc46f489875..5f9365418d7a 100644
--- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
+++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
@@ -88,7 +88,7 @@ public:
DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override;
lldb_private::Error
- DoLaunch (lldb_private::Module *exe_module,
+ DoLaunch (lldb_private::Module *exe_module,
lldb_private::ProcessLaunchInfo &launch_info) override;
void
@@ -160,7 +160,7 @@ public:
UpdateThreadListIfNeeded();
bool
- UpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ UpdateThreadList(lldb_private::ThreadList &old_thread_list,
lldb_private::ThreadList &new_thread_list) override;
virtual lldb::ByteOrder
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
index ceb527b61d80..cd016fbd4b8c 100644
--- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -317,7 +317,7 @@ ReadRegOperation::Execute(ProcessMonitor *monitor)
else if (m_size == sizeof(uint64_t))
m_value = *(uint64_t *)(((caddr_t)&regs) + m_offset);
else
- memcpy(&m_value, (((caddr_t)&regs) + m_offset), m_size);
+ memcpy((void *)&m_value, (((caddr_t)&regs) + m_offset), m_size);
m_result = true;
}
}
@@ -393,7 +393,7 @@ ReadDebugRegOperation::Execute(ProcessMonitor *monitor)
if (m_size == sizeof(uintptr_t))
m_value = *(uintptr_t *)(((caddr_t)&regs) + m_offset);
else
- memcpy(&m_value, (((caddr_t)&regs) + m_offset), m_size);
+ memcpy((void *)&m_value, (((caddr_t)&regs) + m_offset), m_size);
m_result = true;
}
}
diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
index 012f4b6e1555..a1a0cab82a15 100644
--- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
+++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
@@ -260,9 +260,7 @@ RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable)
bool
RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint()
{
- lldb::addr_t pc;
-
- if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ if (GetPC() == LLDB_INVALID_ADDRESS)
return false;
return true;
diff --git a/source/Plugins/Process/Linux/CMakeLists.txt b/source/Plugins/Process/Linux/CMakeLists.txt
new file mode 100644
index 000000000000..80de8413d209
--- /dev/null
+++ b/source/Plugins/Process/Linux/CMakeLists.txt
@@ -0,0 +1,14 @@
+include_directories(.)
+include_directories(../POSIX)
+include_directories(../Utility)
+
+add_lldb_library(lldbPluginProcessLinux
+ NativeProcessLinux.cpp
+ NativeRegisterContextLinux.cpp
+ NativeRegisterContextLinux_arm.cpp
+ NativeRegisterContextLinux_arm64.cpp
+ NativeRegisterContextLinux_x86_64.cpp
+ NativeRegisterContextLinux_mips64.cpp
+ NativeThreadLinux.cpp
+ ProcFileReader.cpp
+ )
diff --git a/source/Plugins/Process/Linux/Makefile b/source/Plugins/Process/Linux/Makefile
new file mode 100644
index 000000000000..239e94d608e9
--- /dev/null
+++ b/source/Plugins/Process/Linux/Makefile
@@ -0,0 +1,17 @@
+##===- source/Plugins/Process/Linux/Makefile ---------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginProcessLinux
+BUILD_ARCHIVE = 1
+
+# Extend the include path so we may locate UnwindLLDB.h
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/source/Plugins/Utility
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp
new file mode 100644
index 000000000000..87c76f57830c
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -0,0 +1,3189 @@
+//===-- NativeProcessLinux.cpp -------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessLinux.h"
+
+// C Includes
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+// C++ Includes
+#include <fstream>
+#include <mutex>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+
+// Other libraries and framework includes
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/common/NativeBreakpoint.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Utility/StringExtractor.h"
+
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "NativeThreadLinux.h"
+#include "ProcFileReader.h"
+#include "Procfs.h"
+
+// System includes - They have to be included after framework includes because they define some
+// macros which collide with variable names in other modules
+#include <linux/unistd.h>
+#include <sys/socket.h>
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+
+#include "lldb/Host/linux/Personality.h"
+#include "lldb/Host/linux/Ptrace.h"
+#include "lldb/Host/linux/Signalfd.h"
+#include "lldb/Host/linux/Uio.h"
+#include "lldb/Host/android/Android.h"
+
+#define LLDB_PERSONALITY_GET_CURRENT_SETTINGS 0xffffffff
+
+// Support hardware breakpoints in case it has not been defined
+#ifndef TRAP_HWBKPT
+ #define TRAP_HWBKPT 4
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_linux;
+using namespace llvm;
+
+// Private bits we only need internally.
+
+static bool ProcessVmReadvSupported()
+{
+ static bool is_supported;
+ static std::once_flag flag;
+
+ std::call_once(flag, [] {
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ uint32_t source = 0x47424742;
+ uint32_t dest = 0;
+
+ struct iovec local, remote;
+ remote.iov_base = &source;
+ local.iov_base = &dest;
+ remote.iov_len = local.iov_len = sizeof source;
+
+ // We shall try if cross-process-memory reads work by attempting to read a value from our own process.
+ ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0);
+ is_supported = (res == sizeof(source) && source == dest);
+ if (log)
+ {
+ if (is_supported)
+ log->Printf("%s: Detected kernel support for process_vm_readv syscall. Fast memory reads enabled.",
+ __FUNCTION__);
+ else
+ log->Printf("%s: syscall process_vm_readv failed (error: %s). Fast memory reads disabled.",
+ __FUNCTION__, strerror(errno));
+ }
+ });
+
+ return is_supported;
+}
+
+namespace
+{
+ Error
+ ResolveProcessArchitecture (lldb::pid_t pid, Platform &platform, ArchSpec &arch)
+ {
+ // Grab process info for the running process.
+ ProcessInstanceInfo process_info;
+ if (!platform.GetProcessInfo (pid, process_info))
+ return Error("failed to get process info");
+
+ // Resolve the executable module.
+ ModuleSP exe_module_sp;
+ ModuleSpec exe_module_spec(process_info.GetExecutableFile(), process_info.GetArchitecture());
+ FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths ());
+ Error error = platform.ResolveExecutable(
+ exe_module_spec,
+ exe_module_sp,
+ executable_search_paths.GetSize () ? &executable_search_paths : NULL);
+
+ if (!error.Success ())
+ return error;
+
+ // Check if we've got our architecture from the exe_module.
+ arch = exe_module_sp->GetArchitecture ();
+ if (arch.IsValid ())
+ return Error();
+ else
+ return Error("failed to retrieve a valid architecture from the exe module");
+ }
+
+ void
+ DisplayBytes (StreamString &s, void *bytes, uint32_t count)
+ {
+ uint8_t *ptr = (uint8_t *)bytes;
+ const uint32_t loop_count = std::min<uint32_t>(DEBUG_PTRACE_MAXBYTES, count);
+ for(uint32_t i=0; i<loop_count; i++)
+ {
+ s.Printf ("[%x]", *ptr);
+ ptr++;
+ }
+ }
+
+ void
+ PtraceDisplayBytes(int &req, void *data, size_t data_size)
+ {
+ StreamString buf;
+ Log *verbose_log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (
+ POSIX_LOG_PTRACE | POSIX_LOG_VERBOSE));
+
+ if (verbose_log)
+ {
+ switch(req)
+ {
+ case PTRACE_POKETEXT:
+ {
+ DisplayBytes(buf, &data, 8);
+ verbose_log->Printf("PTRACE_POKETEXT %s", buf.GetData());
+ break;
+ }
+ case PTRACE_POKEDATA:
+ {
+ DisplayBytes(buf, &data, 8);
+ verbose_log->Printf("PTRACE_POKEDATA %s", buf.GetData());
+ break;
+ }
+ case PTRACE_POKEUSER:
+ {
+ DisplayBytes(buf, &data, 8);
+ verbose_log->Printf("PTRACE_POKEUSER %s", buf.GetData());
+ break;
+ }
+ case PTRACE_SETREGS:
+ {
+ DisplayBytes(buf, data, data_size);
+ verbose_log->Printf("PTRACE_SETREGS %s", buf.GetData());
+ break;
+ }
+ case PTRACE_SETFPREGS:
+ {
+ DisplayBytes(buf, data, data_size);
+ verbose_log->Printf("PTRACE_SETFPREGS %s", buf.GetData());
+ break;
+ }
+ case PTRACE_SETSIGINFO:
+ {
+ DisplayBytes(buf, data, sizeof(siginfo_t));
+ verbose_log->Printf("PTRACE_SETSIGINFO %s", buf.GetData());
+ break;
+ }
+ case PTRACE_SETREGSET:
+ {
+ // Extract iov_base from data, which is a pointer to the struct IOVEC
+ DisplayBytes(buf, *(void **)data, data_size);
+ verbose_log->Printf("PTRACE_SETREGSET %s", buf.GetData());
+ break;
+ }
+ default:
+ {
+ }
+ }
+ }
+ }
+
+ static constexpr unsigned k_ptrace_word_size = sizeof(void*);
+ static_assert(sizeof(long) >= k_ptrace_word_size, "Size of long must be larger than ptrace word size");
+} // end of anonymous namespace
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static Error
+EnsureFDFlags(int fd, int flags)
+{
+ Error error;
+
+ int status = fcntl(fd, F_GETFL);
+ if (status == -1)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ return error;
+}
+
+NativeProcessLinux::LaunchArgs::LaunchArgs(Module *module,
+ char const **argv,
+ char const **envp,
+ const FileSpec &stdin_file_spec,
+ const FileSpec &stdout_file_spec,
+ const FileSpec &stderr_file_spec,
+ const FileSpec &working_dir,
+ const ProcessLaunchInfo &launch_info)
+ : m_module(module),
+ m_argv(argv),
+ m_envp(envp),
+ m_stdin_file_spec(stdin_file_spec),
+ m_stdout_file_spec(stdout_file_spec),
+ m_stderr_file_spec(stderr_file_spec),
+ m_working_dir(working_dir),
+ m_launch_info(launch_info)
+{
+}
+
+NativeProcessLinux::LaunchArgs::~LaunchArgs()
+{ }
+
+// -----------------------------------------------------------------------------
+// Public Static Methods
+// -----------------------------------------------------------------------------
+
+Error
+NativeProcessProtocol::Launch (
+ ProcessLaunchInfo &launch_info,
+ NativeProcessProtocol::NativeDelegate &native_delegate,
+ MainLoop &mainloop,
+ NativeProcessProtocolSP &native_process_sp)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ lldb::ModuleSP exe_module_sp;
+ PlatformSP platform_sp (Platform::GetHostPlatform ());
+ Error error = platform_sp->ResolveExecutable(
+ ModuleSpec(launch_info.GetExecutableFile(), launch_info.GetArchitecture()),
+ exe_module_sp,
+ nullptr);
+
+ if (! error.Success())
+ return error;
+
+ // Verify the working directory is valid if one was specified.
+ FileSpec working_dir{launch_info.GetWorkingDirectory()};
+ if (working_dir &&
+ (!working_dir.ResolvePath() ||
+ working_dir.GetFileType() != FileSpec::eFileTypeDirectory))
+ {
+ error.SetErrorStringWithFormat ("No such file or directory: %s",
+ working_dir.GetCString());
+ return error;
+ }
+
+ const FileAction *file_action;
+
+ // Default of empty will mean to use existing open file descriptors.
+ FileSpec stdin_file_spec{};
+ FileSpec stdout_file_spec{};
+ FileSpec stderr_file_spec{};
+
+ file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
+ if (file_action)
+ stdin_file_spec = file_action->GetFileSpec();
+
+ file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
+ if (file_action)
+ stdout_file_spec = file_action->GetFileSpec();
+
+ file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
+ if (file_action)
+ stderr_file_spec = file_action->GetFileSpec();
+
+ if (log)
+ {
+ if (stdin_file_spec)
+ log->Printf ("NativeProcessLinux::%s setting STDIN to '%s'",
+ __FUNCTION__, stdin_file_spec.GetCString());
+ else
+ log->Printf ("NativeProcessLinux::%s leaving STDIN as is", __FUNCTION__);
+
+ if (stdout_file_spec)
+ log->Printf ("NativeProcessLinux::%s setting STDOUT to '%s'",
+ __FUNCTION__, stdout_file_spec.GetCString());
+ else
+ log->Printf ("NativeProcessLinux::%s leaving STDOUT as is", __FUNCTION__);
+
+ if (stderr_file_spec)
+ log->Printf ("NativeProcessLinux::%s setting STDERR to '%s'",
+ __FUNCTION__, stderr_file_spec.GetCString());
+ else
+ log->Printf ("NativeProcessLinux::%s leaving STDERR as is", __FUNCTION__);
+ }
+
+ // Create the NativeProcessLinux in launch mode.
+ native_process_sp.reset (new NativeProcessLinux ());
+
+ if (log)
+ {
+ int i = 0;
+ for (const char **args = launch_info.GetArguments ().GetConstArgumentVector (); *args; ++args, ++i)
+ {
+ log->Printf ("NativeProcessLinux::%s arg %d: \"%s\"", __FUNCTION__, i, *args ? *args : "nullptr");
+ ++i;
+ }
+ }
+
+ if (!native_process_sp->RegisterNativeDelegate (native_delegate))
+ {
+ native_process_sp.reset ();
+ error.SetErrorStringWithFormat ("failed to register the native delegate");
+ return error;
+ }
+
+ std::static_pointer_cast<NativeProcessLinux> (native_process_sp)->LaunchInferior (
+ mainloop,
+ exe_module_sp.get(),
+ launch_info.GetArguments ().GetConstArgumentVector (),
+ launch_info.GetEnvironmentEntries ().GetConstArgumentVector (),
+ stdin_file_spec,
+ stdout_file_spec,
+ stderr_file_spec,
+ working_dir,
+ launch_info,
+ error);
+
+ if (error.Fail ())
+ {
+ native_process_sp.reset ();
+ if (log)
+ log->Printf ("NativeProcessLinux::%s failed to launch process: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ launch_info.SetProcessID (native_process_sp->GetID ());
+
+ return error;
+}
+
+Error
+NativeProcessProtocol::Attach (
+ lldb::pid_t pid,
+ NativeProcessProtocol::NativeDelegate &native_delegate,
+ MainLoop &mainloop,
+ NativeProcessProtocolSP &native_process_sp)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log && log->GetMask ().Test (POSIX_LOG_VERBOSE))
+ log->Printf ("NativeProcessLinux::%s(pid = %" PRIi64 ")", __FUNCTION__, pid);
+
+ // Grab the current platform architecture. This should be Linux,
+ // since this code is only intended to run on a Linux host.
+ PlatformSP platform_sp (Platform::GetHostPlatform ());
+ if (!platform_sp)
+ return Error("failed to get a valid default platform");
+
+ // Retrieve the architecture for the running process.
+ ArchSpec process_arch;
+ Error error = ResolveProcessArchitecture (pid, *platform_sp.get (), process_arch);
+ if (!error.Success ())
+ return error;
+
+ std::shared_ptr<NativeProcessLinux> native_process_linux_sp (new NativeProcessLinux ());
+
+ if (!native_process_linux_sp->RegisterNativeDelegate (native_delegate))
+ {
+ error.SetErrorStringWithFormat ("failed to register the native delegate");
+ return error;
+ }
+
+ native_process_linux_sp->AttachToInferior (mainloop, pid, error);
+ if (!error.Success ())
+ return error;
+
+ native_process_sp = native_process_linux_sp;
+ return error;
+}
+
+// -----------------------------------------------------------------------------
+// Public Instance Methods
+// -----------------------------------------------------------------------------
+
+NativeProcessLinux::NativeProcessLinux () :
+ NativeProcessProtocol (LLDB_INVALID_PROCESS_ID),
+ m_arch (),
+ m_supports_mem_region (eLazyBoolCalculate),
+ m_mem_region_cache (),
+ m_mem_region_cache_mutex(),
+ m_pending_notification_tid(LLDB_INVALID_THREAD_ID)
+{
+}
+
+void
+NativeProcessLinux::LaunchInferior (
+ MainLoop &mainloop,
+ Module *module,
+ const char *argv[],
+ const char *envp[],
+ const FileSpec &stdin_file_spec,
+ const FileSpec &stdout_file_spec,
+ const FileSpec &stderr_file_spec,
+ const FileSpec &working_dir,
+ const ProcessLaunchInfo &launch_info,
+ Error &error)
+{
+ m_sigchld_handle = mainloop.RegisterSignal(SIGCHLD,
+ [this] (MainLoopBase &) { SigchldHandler(); }, error);
+ if (! m_sigchld_handle)
+ return;
+
+ if (module)
+ m_arch = module->GetArchitecture ();
+
+ SetState (eStateLaunching);
+
+ std::unique_ptr<LaunchArgs> args(
+ new LaunchArgs(module, argv, envp,
+ stdin_file_spec,
+ stdout_file_spec,
+ stderr_file_spec,
+ working_dir,
+ launch_info));
+
+ Launch(args.get(), error);
+}
+
+void
+NativeProcessLinux::AttachToInferior (MainLoop &mainloop, lldb::pid_t pid, Error &error)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 ")", __FUNCTION__, pid);
+
+ m_sigchld_handle = mainloop.RegisterSignal(SIGCHLD,
+ [this] (MainLoopBase &) { SigchldHandler(); }, error);
+ if (! m_sigchld_handle)
+ return;
+
+ // We can use the Host for everything except the ResolveExecutable portion.
+ PlatformSP platform_sp = Platform::GetHostPlatform ();
+ if (!platform_sp)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 "): no default platform set", __FUNCTION__, pid);
+ error.SetErrorString ("no default platform available");
+ return;
+ }
+
+ // Gather info about the process.
+ ProcessInstanceInfo process_info;
+ if (!platform_sp->GetProcessInfo (pid, process_info))
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 "): failed to get process info", __FUNCTION__, pid);
+ error.SetErrorString ("failed to get process info");
+ return;
+ }
+
+ // Resolve the executable module
+ ModuleSP exe_module_sp;
+ FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
+ ModuleSpec exe_module_spec(process_info.GetExecutableFile(), process_info.GetArchitecture());
+ error = platform_sp->ResolveExecutable(exe_module_spec, exe_module_sp,
+ executable_search_paths.GetSize() ? &executable_search_paths : NULL);
+ if (!error.Success())
+ return;
+
+ // Set the architecture to the exe architecture.
+ m_arch = exe_module_sp->GetArchitecture();
+ if (log)
+ log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 ") detected architecture %s", __FUNCTION__, pid, m_arch.GetArchitectureName ());
+
+ m_pid = pid;
+ SetState(eStateAttaching);
+
+ Attach(pid, error);
+}
+
+::pid_t
+NativeProcessLinux::Launch(LaunchArgs *args, Error &error)
+{
+ assert (args && "null args");
+
+ const char **argv = args->m_argv;
+ const char **envp = args->m_envp;
+ const FileSpec working_dir = args->m_working_dir;
+
+ lldb_utility::PseudoTerminal terminal;
+ const size_t err_len = 1024;
+ char err_str[err_len];
+ lldb::pid_t pid;
+
+ // Propagate the environment if one is not supplied.
+ if (envp == NULL || envp[0] == NULL)
+ envp = const_cast<const char **>(environ);
+
+ if ((pid = terminal.Fork(err_str, err_len)) == static_cast<lldb::pid_t> (-1))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("Process fork failed: %s", err_str);
+ return -1;
+ }
+
+ // Recognized child exit status codes.
+ enum {
+ ePtraceFailed = 1,
+ eDupStdinFailed,
+ eDupStdoutFailed,
+ eDupStderrFailed,
+ eChdirFailed,
+ eExecFailed,
+ eSetGidFailed,
+ eSetSigMaskFailed
+ };
+
+ // Child process.
+ if (pid == 0)
+ {
+ // First, make sure we disable all logging. If we are logging to stdout, our logs can be
+ // mistaken for inferior output.
+ Log::DisableAllLogChannels(nullptr);
+ // FIXME consider opening a pipe between parent/child and have this forked child
+ // send log info to parent re: launch status.
+
+ // Start tracing this child that is about to exec.
+ error = PtraceWrapper(PTRACE_TRACEME, 0);
+ if (error.Fail())
+ exit(ePtraceFailed);
+
+ // terminal has already dupped the tty descriptors to stdin/out/err.
+ // This closes original fd from which they were copied (and avoids
+ // leaking descriptors to the debugged process.
+ terminal.CloseSlaveFileDescriptor();
+
+ // Do not inherit setgid powers.
+ if (setgid(getgid()) != 0)
+ exit(eSetGidFailed);
+
+ // Attempt to have our own process group.
+ if (setpgid(0, 0) != 0)
+ {
+ // FIXME log that this failed. This is common.
+ // Don't allow this to prevent an inferior exec.
+ }
+
+ // Dup file descriptors if needed.
+ if (args->m_stdin_file_spec)
+ if (!DupDescriptor(args->m_stdin_file_spec, STDIN_FILENO, O_RDONLY))
+ exit(eDupStdinFailed);
+
+ if (args->m_stdout_file_spec)
+ if (!DupDescriptor(args->m_stdout_file_spec, STDOUT_FILENO, O_WRONLY | O_CREAT | O_TRUNC))
+ exit(eDupStdoutFailed);
+
+ if (args->m_stderr_file_spec)
+ if (!DupDescriptor(args->m_stderr_file_spec, STDERR_FILENO, O_WRONLY | O_CREAT | O_TRUNC))
+ exit(eDupStderrFailed);
+
+ // Close everything besides stdin, stdout, and stderr that has no file
+ // action to avoid leaking
+ for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); ++fd)
+ if (!args->m_launch_info.GetFileActionForFD(fd))
+ close(fd);
+
+ // Change working directory
+ if (working_dir && 0 != ::chdir(working_dir.GetCString()))
+ exit(eChdirFailed);
+
+ // Disable ASLR if requested.
+ if (args->m_launch_info.GetFlags ().Test (lldb::eLaunchFlagDisableASLR))
+ {
+ const int old_personality = personality (LLDB_PERSONALITY_GET_CURRENT_SETTINGS);
+ if (old_personality == -1)
+ {
+ // Can't retrieve Linux personality. Cannot disable ASLR.
+ }
+ else
+ {
+ const int new_personality = personality (ADDR_NO_RANDOMIZE | old_personality);
+ if (new_personality == -1)
+ {
+ // Disabling ASLR failed.
+ }
+ else
+ {
+ // Disabling ASLR succeeded.
+ }
+ }
+ }
+
+ // Clear the signal mask to prevent the child from being affected by
+ // any masking done by the parent.
+ sigset_t set;
+ if (sigemptyset(&set) != 0 || pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
+ exit(eSetSigMaskFailed);
+
+ // Execute. We should never return...
+ execve(argv[0],
+ const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp));
+
+ // ...unless exec fails. In which case we definitely need to end the child here.
+ exit(eExecFailed);
+ }
+
+ //
+ // This is the parent code here.
+ //
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // Wait for the child process to trap on its call to execve.
+ ::pid_t wpid;
+ int status;
+ if ((wpid = waitpid(pid, &status, 0)) < 0)
+ {
+ error.SetErrorToErrno();
+ if (log)
+ log->Printf ("NativeProcessLinux::%s waitpid for inferior failed with %s",
+ __FUNCTION__, error.AsCString ());
+
+ // Mark the inferior as invalid.
+ // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
+ SetState (StateType::eStateInvalid);
+
+ return -1;
+ }
+ else if (WIFEXITED(status))
+ {
+ // open, dup or execve likely failed for some reason.
+ error.SetErrorToGenericError();
+ switch (WEXITSTATUS(status))
+ {
+ case ePtraceFailed:
+ error.SetErrorString("Child ptrace failed.");
+ break;
+ case eDupStdinFailed:
+ error.SetErrorString("Child open stdin failed.");
+ break;
+ case eDupStdoutFailed:
+ error.SetErrorString("Child open stdout failed.");
+ break;
+ case eDupStderrFailed:
+ error.SetErrorString("Child open stderr failed.");
+ break;
+ case eChdirFailed:
+ error.SetErrorString("Child failed to set working directory.");
+ break;
+ case eExecFailed:
+ error.SetErrorString("Child exec failed.");
+ break;
+ case eSetGidFailed:
+ error.SetErrorString("Child setgid failed.");
+ break;
+ case eSetSigMaskFailed:
+ error.SetErrorString("Child failed to set signal mask.");
+ break;
+ default:
+ error.SetErrorString("Child returned unknown exit status.");
+ break;
+ }
+
+ if (log)
+ {
+ log->Printf ("NativeProcessLinux::%s inferior exited with status %d before issuing a STOP",
+ __FUNCTION__,
+ WEXITSTATUS(status));
+ }
+
+ // Mark the inferior as invalid.
+ // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
+ SetState (StateType::eStateInvalid);
+
+ return -1;
+ }
+ assert(WIFSTOPPED(status) && (wpid == static_cast< ::pid_t> (pid)) &&
+ "Could not sync with inferior process.");
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior started, now in stopped state", __FUNCTION__);
+
+ error = SetDefaultPtraceOpts(pid);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior failed to set default ptrace options: %s",
+ __FUNCTION__, error.AsCString ());
+
+ // Mark the inferior as invalid.
+ // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
+ SetState (StateType::eStateInvalid);
+
+ return -1;
+ }
+
+ // Release the master terminal descriptor and pass it off to the
+ // NativeProcessLinux instance. Similarly stash the inferior pid.
+ m_terminal_fd = terminal.ReleaseMasterFileDescriptor();
+ m_pid = pid;
+
+ // Set the terminal fd to be in non blocking mode (it simplifies the
+ // implementation of ProcessLinux::GetSTDOUT to have a non-blocking
+ // descriptor to read from).
+ error = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s inferior EnsureFDFlags failed for ensuring terminal O_NONBLOCK setting: %s",
+ __FUNCTION__, error.AsCString ());
+
+ // Mark the inferior as invalid.
+ // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
+ SetState (StateType::eStateInvalid);
+
+ return -1;
+ }
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() adding pid = %" PRIu64, __FUNCTION__, pid);
+
+ NativeThreadLinuxSP thread_sp = AddThread(pid);
+ assert (thread_sp && "AddThread() returned a nullptr thread");
+ thread_sp->SetStoppedBySignal(SIGSTOP);
+ ThreadWasCreated(*thread_sp);
+
+ // Let our process instance know the thread has stopped.
+ SetCurrentThreadID (thread_sp->GetID ());
+ SetState (StateType::eStateStopped);
+
+ if (log)
+ {
+ if (error.Success ())
+ {
+ log->Printf ("NativeProcessLinux::%s inferior launching succeeded", __FUNCTION__);
+ }
+ else
+ {
+ log->Printf ("NativeProcessLinux::%s inferior launching failed: %s",
+ __FUNCTION__, error.AsCString ());
+ return -1;
+ }
+ }
+ return pid;
+}
+
+::pid_t
+NativeProcessLinux::Attach(lldb::pid_t pid, Error &error)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // Use a map to keep track of the threads which we have attached/need to attach.
+ Host::TidMap tids_to_attach;
+ if (pid <= 1)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Attaching to process 1 is not allowed.");
+ return -1;
+ }
+
+ while (Host::FindProcessThreads(pid, tids_to_attach))
+ {
+ for (Host::TidMap::iterator it = tids_to_attach.begin();
+ it != tids_to_attach.end();)
+ {
+ if (it->second == false)
+ {
+ lldb::tid_t tid = it->first;
+
+ // Attach to the requested process.
+ // An attach will cause the thread to stop with a SIGSTOP.
+ error = PtraceWrapper(PTRACE_ATTACH, tid);
+ if (error.Fail())
+ {
+ // No such thread. The thread may have exited.
+ // More error handling may be needed.
+ if (error.GetError() == ESRCH)
+ {
+ it = tids_to_attach.erase(it);
+ continue;
+ }
+ else
+ return -1;
+ }
+
+ int status;
+ // Need to use __WALL otherwise we receive an error with errno=ECHLD
+ // At this point we should have a thread stopped if waitpid succeeds.
+ if ((status = waitpid(tid, NULL, __WALL)) < 0)
+ {
+ // No such thread. The thread may have exited.
+ // More error handling may be needed.
+ if (errno == ESRCH)
+ {
+ it = tids_to_attach.erase(it);
+ continue;
+ }
+ else
+ {
+ error.SetErrorToErrno();
+ return -1;
+ }
+ }
+
+ error = SetDefaultPtraceOpts(tid);
+ if (error.Fail())
+ return -1;
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() adding tid = %" PRIu64, __FUNCTION__, tid);
+
+ it->second = true;
+
+ // Create the thread, mark it as stopped.
+ NativeThreadLinuxSP thread_sp (AddThread(static_cast<lldb::tid_t>(tid)));
+ assert (thread_sp && "AddThread() returned a nullptr");
+
+ // This will notify this is a new thread and tell the system it is stopped.
+ thread_sp->SetStoppedBySignal(SIGSTOP);
+ ThreadWasCreated(*thread_sp);
+ SetCurrentThreadID (thread_sp->GetID ());
+ }
+
+ // move the loop forward
+ ++it;
+ }
+ }
+
+ if (tids_to_attach.size() > 0)
+ {
+ m_pid = pid;
+ // Let our process instance know the thread has stopped.
+ SetState (StateType::eStateStopped);
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("No such process.");
+ return -1;
+ }
+
+ return pid;
+}
+
+Error
+NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid)
+{
+ long ptrace_opts = 0;
+
+ // Have the child raise an event on exit. This is used to keep the child in
+ // limbo until it is destroyed.
+ ptrace_opts |= PTRACE_O_TRACEEXIT;
+
+ // Have the tracer trace threads which spawn in the inferior process.
+ // TODO: if we want to support tracing the inferiors' child, add the
+ // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK)
+ ptrace_opts |= PTRACE_O_TRACECLONE;
+
+ // Have the tracer notify us before execve returns
+ // (needed to disable legacy SIGTRAP generation)
+ ptrace_opts |= PTRACE_O_TRACEEXEC;
+
+ 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)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // Certain activities differ based on whether the pid is the tid of the main thread.
+ const bool is_main_thread = (pid == GetID ());
+
+ // Handle when the thread exits.
+ if (exited)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() got exit signal(%d) , tid = %" PRIu64 " (%s main thread)", __FUNCTION__, signal, pid, is_main_thread ? "is" : "is not");
+
+ // This is a thread that exited. Ensure we're not tracking it anymore.
+ const bool thread_found = StopTrackingThread (pid);
+
+ if (is_main_thread)
+ {
+ // We only set the exit status and notify the delegate if we haven't already set the process
+ // state to an exited state. We normally should have received a SIGTRAP | (PTRACE_EVENT_EXIT << 8)
+ // for the main thread.
+ const bool already_notified = (GetState() == StateType::eStateExited) || (GetState () == StateType::eStateCrashed);
+ if (!already_notified)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() tid = %" PRIu64 " handling main thread exit (%s), expected exit state already set but state was %s instead, setting exit state now", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found", StateAsCString (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);
+
+ // Notify delegate that our process has exited.
+ SetState (StateType::eStateExited, true);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() tid = %" PRIu64 " main thread now exited (%s)", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found");
+ }
+ }
+ else
+ {
+ // Do we want to report to the delegate in this case? I think not. If this was an orderly
+ // thread exit, we would already have received the SIGTRAP | (PTRACE_EVENT_EXIT << 8) signal,
+ // and we would have done an all-stop then.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() tid = %" PRIu64 " handling non-main thread exit (%s)", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found");
+ }
+ return;
+ }
+
+ siginfo_t info;
+ const auto info_err = GetSignalInfo(pid, &info);
+ auto thread_sp = GetThreadByID(pid);
+
+ if (! thread_sp)
+ {
+ // Normally, the only situation when we cannot find the thread is if we have just
+ // received a new thread notification. This is indicated by GetSignalInfo() returning
+ // si_code == SI_USER and si_pid == 0
+ if (log)
+ log->Printf("NativeProcessLinux::%s received notification about an unknown tid %" PRIu64 ".", __FUNCTION__, pid);
+
+ if (info_err.Fail())
+ {
+ if (log)
+ log->Printf("NativeProcessLinux::%s (tid %" PRIu64 ") GetSignalInfo failed (%s). Ingoring this notification.", __FUNCTION__, pid, info_err.AsCString());
+ return;
+ }
+
+ if (log && (info.si_code != SI_USER || info.si_pid != 0))
+ log->Printf("NativeProcessLinux::%s (tid %" PRIu64 ") unexpected signal info (si_code: %d, si_pid: %d). Treating as a new thread notification anyway.", __FUNCTION__, pid, info.si_code, info.si_pid);
+
+ auto thread_sp = AddThread(pid);
+ // Resume the newly created thread.
+ ResumeThread(*thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
+ ThreadWasCreated(*thread_sp);
+ return;
+ }
+
+ // Get details on the signal raised.
+ if (info_err.Success())
+ {
+ // We have retrieved the signal info. Dispatch appropriately.
+ if (info.si_signo == SIGTRAP)
+ MonitorSIGTRAP(info, *thread_sp);
+ else
+ MonitorSignal(info, *thread_sp, exited);
+ }
+ else
+ {
+ if (info_err.GetError() == EINVAL)
+ {
+ // This is a group stop reception for this tid.
+ // We can reach here if we reinject SIGSTOP, SIGSTP, SIGTTIN or SIGTTOU into the
+ // tracee, triggering the group-stop mechanism. Normally receiving these would stop
+ // the process, pending a SIGCONT. Simulating this state in a debugger is hard and is
+ // generally not needed (one use case is debugging background task being managed by a
+ // shell). For general use, it is sufficient to stop the process in a signal-delivery
+ // stop which happens before the group stop. This done by MonitorSignal and works
+ // correctly for all signals.
+ if (log)
+ log->Printf("NativeProcessLinux::%s received a group stop for pid %" PRIu64 " tid %" PRIu64 ". Transparent handling of group stops not supported, resuming the thread.", __FUNCTION__, GetID (), pid);
+ ResumeThread(*thread_sp, thread_sp->GetState(), LLDB_INVALID_SIGNAL_NUMBER);
+ }
+ else
+ {
+ // ptrace(GETSIGINFO) failed (but not due to group-stop).
+
+ // A return value of ESRCH means the thread/process is no longer on the system,
+ // so it was killed somehow outside of our control. Either way, we can't do anything
+ // with it anymore.
+
+ // Stop tracking the metadata for the thread since it's entirely off the system now.
+ const bool thread_found = StopTrackingThread (pid);
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s GetSignalInfo failed: %s, tid = %" PRIu64 ", signal = %d, status = %d (%s, %s, %s)",
+ __FUNCTION__, info_err.AsCString(), pid, signal, status, info_err.GetError() == ESRCH ? "thread/process killed" : "unknown reason", is_main_thread ? "is main thread" : "is not main thread", thread_found ? "thread metadata removed" : "thread metadata not found");
+
+ if (is_main_thread)
+ {
+ // 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);
+ SetState (StateType::eStateExited, true);
+ }
+ else
+ {
+ // This thread was pulled out from underneath us. Anything to do here? Do we want to do an all stop?
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " non-main thread exit occurred, didn't tell delegate anything since thread disappeared out from underneath us", __FUNCTION__, GetID (), pid);
+ }
+ }
+ }
+}
+
+void
+NativeProcessLinux::WaitForNewThread(::pid_t tid)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ NativeThreadLinuxSP new_thread_sp = GetThreadByID(tid);
+
+ if (new_thread_sp)
+ {
+ // We are already tracking the thread - we got the event on the new thread (see
+ // MonitorSignal) before this one. We are done.
+ return;
+ }
+
+ // The thread is not tracked yet, let's wait for it to appear.
+ int status = -1;
+ ::pid_t wait_pid;
+ do
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received thread creation event for tid %" PRIu32 ". tid not tracked yet, waiting for thread to appear...", __FUNCTION__, tid);
+ wait_pid = waitpid(tid, &status, __WALL);
+ }
+ while (wait_pid == -1 && errno == EINTR);
+ // Since we are waiting on a specific tid, this must be the creation event. But let's do
+ // some checks just in case.
+ if (wait_pid != tid) {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() waiting for tid %" PRIu32 " failed. Assuming the thread has disappeared in the meantime", __FUNCTION__, tid);
+ // The only way I know of this could happen is if the whole process was
+ // SIGKILLed in the mean time. In any case, we can't do anything about that now.
+ return;
+ }
+ if (WIFEXITED(status))
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() waiting for tid %" PRIu32 " returned an 'exited' event. Not tracking the thread.", __FUNCTION__, tid);
+ // Also a very improbable event.
+ return;
+ }
+
+ siginfo_t info;
+ Error error = GetSignalInfo(tid, &info);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() GetSignalInfo for tid %" PRIu32 " failed. Assuming the thread has disappeared in the meantime.", __FUNCTION__, tid);
+ return;
+ }
+
+ if (((info.si_pid != 0) || (info.si_code != SI_USER)) && log)
+ {
+ // We should be getting a thread creation signal here, but we received something
+ // else. There isn't much we can do about it now, so we will just log that. Since the
+ // thread is alive and we are receiving events from it, we shall pretend that it was
+ // created properly.
+ log->Printf ("NativeProcessLinux::%s() GetSignalInfo for tid %" PRIu32 " received unexpected signal with code %d from pid %d.", __FUNCTION__, tid, info.si_code, info.si_pid);
+ }
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 ": tracking new thread tid %" PRIu32,
+ __FUNCTION__, GetID (), tid);
+
+ new_thread_sp = AddThread(tid);
+ ResumeThread(*new_thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
+ ThreadWasCreated(*new_thread_sp);
+}
+
+void
+NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, NativeThreadLinux &thread)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ const bool is_main_thread = (thread.GetID() == GetID ());
+
+ assert(info.si_signo == SIGTRAP && "Unexpected child signal!");
+
+ Mutex::Locker locker (m_threads_mutex);
+
+ switch (info.si_code)
+ {
+ // TODO: these two cases are required if we want to support tracing of the inferiors' children. We'd need this to debug a monitor.
+ // case (SIGTRAP | (PTRACE_EVENT_FORK << 8)):
+ // case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)):
+
+ case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)):
+ {
+ // This is the notification on the parent thread which informs us of new thread
+ // creation.
+ // We don't want to do anything with the parent thread so we just resume it. In case we
+ // want to implement "break on thread creation" functionality, we would need to stop
+ // here.
+
+ unsigned long event_message = 0;
+ if (GetEventMessage(thread.GetID(), &event_message).Fail())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " received thread creation event but GetEventMessage failed so we don't know the new tid", __FUNCTION__, thread.GetID());
+ } else
+ WaitForNewThread(event_message);
+
+ ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER);
+ break;
+ }
+
+ case (SIGTRAP | (PTRACE_EVENT_EXEC << 8)):
+ {
+ NativeThreadLinuxSP main_thread_sp;
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received exec event, code = %d", __FUNCTION__, info.si_code ^ SIGTRAP);
+
+ // Exec clears any pending notifications.
+ m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
+
+ // Remove all but the main thread here. Linux fork creates a new process which only copies the main thread. Mutexes are in undefined state.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s exec received, stop tracking all but main thread", __FUNCTION__);
+
+ for (auto thread_sp : m_threads)
+ {
+ const bool is_main_thread = thread_sp && thread_sp->GetID () == GetID ();
+ if (is_main_thread)
+ {
+ main_thread_sp = std::static_pointer_cast<NativeThreadLinux>(thread_sp);
+ if (log)
+ log->Printf ("NativeProcessLinux::%s found main thread with tid %" PRIu64 ", keeping", __FUNCTION__, main_thread_sp->GetID ());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s discarding non-main-thread tid %" PRIu64 " due to exec", __FUNCTION__, thread_sp->GetID ());
+ }
+ }
+
+ m_threads.clear ();
+
+ if (main_thread_sp)
+ {
+ m_threads.push_back (main_thread_sp);
+ SetCurrentThreadID (main_thread_sp->GetID ());
+ main_thread_sp->SetStoppedByExec();
+ }
+ else
+ {
+ SetCurrentThreadID (LLDB_INVALID_THREAD_ID);
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 "no main thread found, discarded all threads, we're in a no-thread state!", __FUNCTION__, GetID ());
+ }
+
+ // Tell coordinator about about the "new" (since exec) stopped main thread.
+ ThreadWasCreated(*main_thread_sp);
+
+ // Let our delegate know we have just exec'd.
+ NotifyDidExec ();
+
+ // If we have a main thread, indicate we are stopped.
+ assert (main_thread_sp && "exec called during ptraced process but no main thread metadata tracked");
+
+ // Let the process know we're stopped.
+ StopRunningThreads(main_thread_sp->GetID());
+
+ break;
+ }
+
+ case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)):
+ {
+ // The inferior process or one of its threads is about to exit.
+ // We don't want to do anything with the thread so we just resume it. In case we
+ // want to implement "break on thread exit" functionality, we would need to stop
+ // here.
+
+ unsigned long data = 0;
+ if (GetEventMessage(thread.GetID(), &data).Fail())
+ data = -1;
+
+ if (log)
+ {
+ log->Printf ("NativeProcessLinux::%s() received PTRACE_EVENT_EXIT, data = %lx (WIFEXITED=%s,WIFSIGNALED=%s), pid = %" PRIu64 " (%s)",
+ __FUNCTION__,
+ data, WIFEXITED (data) ? "true" : "false", WIFSIGNALED (data) ? "true" : "false",
+ thread.GetID(),
+ is_main_thread ? "is main thread" : "not main thread");
+ }
+
+ if (is_main_thread)
+ {
+ SetExitStatus (convert_pid_status_to_exit_type (data), convert_pid_status_to_return_code (data), nullptr, true);
+ }
+
+ StateType state = thread.GetState();
+ if (! StateIsRunningState(state))
+ {
+ // Due to a kernel bug, we may sometimes get this stop after the inferior gets a
+ // SIGKILL. This confuses our state tracking logic in ResumeThread(), since normally,
+ // we should not be receiving any ptrace events while the inferior is stopped. This
+ // makes sure that the inferior is resumed and exits normally.
+ state = eStateRunning;
+ }
+ ResumeThread(thread, state, LLDB_INVALID_SIGNAL_NUMBER);
+
+ break;
+ }
+
+ case 0:
+ case TRAP_TRACE: // We receive this on single stepping.
+ case TRAP_HWBKPT: // We receive this on watchpoint hit
+ {
+ // If a watchpoint was hit, report it
+ uint32_t wp_index;
+ Error error = thread.GetRegisterContext()->GetWatchpointHitIndex(wp_index, (uintptr_t)info.si_addr);
+ if (error.Fail() && log)
+ log->Printf("NativeProcessLinux::%s() "
+ "received error while checking for watchpoint hits, "
+ "pid = %" PRIu64 " error = %s",
+ __FUNCTION__, thread.GetID(), error.AsCString());
+ if (wp_index != LLDB_INVALID_INDEX32)
+ {
+ MonitorWatchpoint(thread, wp_index);
+ break;
+ }
+
+ // Otherwise, report step over
+ MonitorTrace(thread);
+ break;
+ }
+
+ case SI_KERNEL:
+#if defined __mips__
+ // For mips there is no special signal for watchpoint
+ // So we check for watchpoint in kernel trap
+ {
+ // If a watchpoint was hit, report it
+ uint32_t wp_index;
+ Error error = thread.GetRegisterContext()->GetWatchpointHitIndex(wp_index, LLDB_INVALID_ADDRESS);
+ if (error.Fail() && log)
+ log->Printf("NativeProcessLinux::%s() "
+ "received error while checking for watchpoint hits, "
+ "pid = %" PRIu64 " error = %s",
+ __FUNCTION__, thread.GetID(), error.AsCString());
+ if (wp_index != LLDB_INVALID_INDEX32)
+ {
+ MonitorWatchpoint(thread, wp_index);
+ break;
+ }
+ }
+ // NO BREAK
+#endif
+ case TRAP_BRKPT:
+ MonitorBreakpoint(thread);
+ break;
+
+ case SIGTRAP:
+ case (SIGTRAP | 0x80):
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received unknown SIGTRAP system call stop event, pid %" PRIu64 "tid %" PRIu64 ", resuming", __FUNCTION__, GetID (), thread.GetID());
+
+ // Ignore these signals until we know more about them.
+ ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER);
+ break;
+
+ default:
+ assert(false && "Unexpected SIGTRAP code!");
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 "tid %" PRIu64 " received unhandled SIGTRAP code: 0x%d",
+ __FUNCTION__, GetID(), thread.GetID(), info.si_code);
+ break;
+
+ }
+}
+
+void
+NativeProcessLinux::MonitorTrace(NativeThreadLinux &thread)
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("NativeProcessLinux::%s() received trace event, pid = %" PRIu64 " (single stepping)",
+ __FUNCTION__, thread.GetID());
+
+ // This thread is currently stopped.
+ thread.SetStoppedByTrace();
+
+ StopRunningThreads(thread.GetID());
+}
+
+void
+NativeProcessLinux::MonitorBreakpoint(NativeThreadLinux &thread)
+{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf("NativeProcessLinux::%s() received breakpoint event, pid = %" PRIu64,
+ __FUNCTION__, thread.GetID());
+
+ // Mark the thread as stopped at breakpoint.
+ thread.SetStoppedByBreakpoint();
+ Error error = FixupBreakpointPCAsNeeded(thread);
+ if (error.Fail())
+ if (log)
+ log->Printf("NativeProcessLinux::%s() pid = %" PRIu64 " fixup: %s",
+ __FUNCTION__, thread.GetID(), error.AsCString());
+
+ if (m_threads_stepping_with_breakpoint.find(thread.GetID()) != m_threads_stepping_with_breakpoint.end())
+ thread.SetStoppedByTrace();
+
+ StopRunningThreads(thread.GetID());
+}
+
+void
+NativeProcessLinux::MonitorWatchpoint(NativeThreadLinux &thread, uint32_t wp_index)
+{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf("NativeProcessLinux::%s() received watchpoint event, "
+ "pid = %" PRIu64 ", wp_index = %" PRIu32,
+ __FUNCTION__, thread.GetID(), wp_index);
+
+ // Mark the thread as stopped at watchpoint.
+ // The address is at (lldb::addr_t)info->si_addr if we need it.
+ thread.SetStoppedByWatchpoint(wp_index);
+
+ // We need to tell all other running threads before we notify the delegate about this stop.
+ StopRunningThreads(thread.GetID());
+}
+
+void
+NativeProcessLinux::MonitorSignal(const siginfo_t &info, NativeThreadLinux &thread, bool exited)
+{
+ const int signo = info.si_signo;
+ const bool is_from_llgs = info.si_pid == getpid ();
+
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // POSIX says that process behaviour is undefined after it ignores a SIGFPE,
+ // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a
+ // kill(2) or raise(3). Similarly for tgkill(2) on Linux.
+ //
+ // IOW, user generated signals never generate what we consider to be a
+ // "crash".
+ //
+ // Similarly, ACK signals generated by this monitor.
+
+ Mutex::Locker locker (m_threads_mutex);
+
+ // Handle the signal.
+ if (info.si_code == SI_TKILL || info.si_code == SI_USER)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received signal %s (%d) with code %s, (siginfo pid = %d (%s), waitpid pid = %" PRIu64 ")",
+ __FUNCTION__,
+ Host::GetSignalAsCString(signo),
+ signo,
+ (info.si_code == SI_TKILL ? "SI_TKILL" : "SI_USER"),
+ info.si_pid,
+ is_from_llgs ? "from llgs" : "not from llgs",
+ thread.GetID());
+ }
+
+ // Check for thread stop notification.
+ if (is_from_llgs && (info.si_code == SI_TKILL) && (signo == SIGSTOP))
+ {
+ // This is a tgkill()-based stop.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ", thread stopped",
+ __FUNCTION__,
+ GetID (),
+ thread.GetID());
+
+ // Check that we're not already marked with a stop reason.
+ // Note this thread really shouldn't already be marked as stopped - if we were, that would imply that
+ // the kernel signaled us with the thread stopping which we handled and marked as stopped,
+ // and that, without an intervening resume, we received another stop. It is more likely
+ // that we are missing the marking of a run state somewhere if we find that the thread was
+ // marked as stopped.
+ const StateType thread_state = thread.GetState();
+ if (!StateIsStoppedState (thread_state, false))
+ {
+ // An inferior thread has stopped because of a SIGSTOP we have sent it.
+ // Generally, these are not important stops and we don't want to report them as
+ // they are just used to stop other threads when one thread (the one with the
+ // *real* stop reason) hits a breakpoint (watchpoint, etc...). However, in the
+ // case of an asynchronous Interrupt(), this *is* the real stop reason, so we
+ // leave the signal intact if this is the thread that was chosen as the
+ // triggering thread.
+ if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID)
+ {
+ if (m_pending_notification_tid == thread.GetID())
+ thread.SetStoppedBySignal(SIGSTOP, &info);
+ else
+ thread.SetStoppedWithNoReason();
+
+ SetCurrentThreadID (thread.GetID ());
+ SignalIfAllThreadsStopped();
+ }
+ else
+ {
+ // We can end up here if stop was initiated by LLGS but by this time a
+ // thread stop has occurred - maybe initiated by another event.
+ Error error = ResumeThread(thread, thread.GetState(), 0);
+ if (error.Fail() && log)
+ {
+ log->Printf("NativeProcessLinux::%s failed to resume thread tid %" PRIu64 ": %s",
+ __FUNCTION__, thread.GetID(), error.AsCString());
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ {
+ // Retrieve the signal name if the thread was stopped by a signal.
+ int stop_signo = 0;
+ const bool stopped_by_signal = thread.IsStopped(&stop_signo);
+ const char *signal_name = stopped_by_signal ? Host::GetSignalAsCString(stop_signo) : "<not stopped by signal>";
+ if (!signal_name)
+ signal_name = "<no-signal-name>";
+
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ", thread was already marked as a stopped state (state=%s, signal=%d (%s)), leaving stop signal as is",
+ __FUNCTION__,
+ GetID (),
+ thread.GetID(),
+ StateAsCString (thread_state),
+ stop_signo,
+ signal_name);
+ }
+ SignalIfAllThreadsStopped();
+ }
+
+ // Done handling.
+ return;
+ }
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() received signal %s", __FUNCTION__, Host::GetSignalAsCString(signo));
+
+ // This thread is stopped.
+ thread.SetStoppedBySignal(signo, &info);
+
+ // Send a stop to the debugger after we get all other threads to stop.
+ StopRunningThreads(thread.GetID());
+}
+
+namespace {
+
+struct EmulatorBaton
+{
+ NativeProcessLinux* m_process;
+ NativeRegisterContext* m_reg_context;
+
+ // eRegisterKindDWARF -> RegsiterValue
+ std::unordered_map<uint32_t, RegisterValue> m_register_values;
+
+ EmulatorBaton(NativeProcessLinux* process, NativeRegisterContext* reg_context) :
+ m_process(process), m_reg_context(reg_context) {}
+};
+
+} // anonymous namespace
+
+static size_t
+ReadMemoryCallback (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length)
+{
+ EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+
+ size_t bytes_read;
+ emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read);
+ return bytes_read;
+}
+
+static bool
+ReadRegisterCallback (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value)
+{
+ EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+
+ auto it = emulator_baton->m_register_values.find(reg_info->kinds[eRegisterKindDWARF]);
+ if (it != emulator_baton->m_register_values.end())
+ {
+ reg_value = it->second;
+ return true;
+ }
+
+ // The emulator only fill in the dwarf regsiter numbers (and in some case
+ // the generic register numbers). Get the full register info from the
+ // register context based on the dwarf register numbers.
+ const RegisterInfo* full_reg_info = emulator_baton->m_reg_context->GetRegisterInfo(
+ eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);
+
+ Error error = emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value);
+ if (error.Success())
+ return true;
+
+ return false;
+}
+
+static bool
+WriteRegisterCallback (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value)
+{
+ EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+ emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] = reg_value;
+ return true;
+}
+
+static size_t
+WriteMemoryCallback (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length)
+{
+ return length;
+}
+
+static lldb::addr_t
+ReadFlags (NativeRegisterContext* regsiter_context)
+{
+ const RegisterInfo* flags_info = regsiter_context->GetRegisterInfo(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+ return regsiter_context->ReadRegisterAsUnsigned(flags_info, LLDB_INVALID_ADDRESS);
+}
+
+Error
+NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread)
+{
+ Error error;
+ NativeRegisterContextSP register_context_sp = thread.GetRegisterContext();
+
+ std::unique_ptr<EmulateInstruction> emulator_ap(
+ EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying, nullptr));
+
+ if (emulator_ap == nullptr)
+ return Error("Instruction emulator not found!");
+
+ EmulatorBaton baton(this, register_context_sp.get());
+ emulator_ap->SetBaton(&baton);
+ emulator_ap->SetReadMemCallback(&ReadMemoryCallback);
+ emulator_ap->SetReadRegCallback(&ReadRegisterCallback);
+ emulator_ap->SetWriteMemCallback(&WriteMemoryCallback);
+ emulator_ap->SetWriteRegCallback(&WriteRegisterCallback);
+
+ if (!emulator_ap->ReadInstruction())
+ return Error("Read instruction failed!");
+
+ bool emulation_result = emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
+
+ const RegisterInfo* reg_info_pc = register_context_sp->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ const RegisterInfo* reg_info_flags = register_context_sp->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+
+ auto pc_it = baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);
+ auto flags_it = baton.m_register_values.find(reg_info_flags->kinds[eRegisterKindDWARF]);
+
+ lldb::addr_t next_pc;
+ lldb::addr_t next_flags;
+ if (emulation_result)
+ {
+ assert(pc_it != baton.m_register_values.end() && "Emulation was successfull but PC wasn't updated");
+ next_pc = pc_it->second.GetAsUInt64();
+
+ if (flags_it != baton.m_register_values.end())
+ next_flags = flags_it->second.GetAsUInt64();
+ else
+ next_flags = ReadFlags (register_context_sp.get());
+ }
+ else if (pc_it == baton.m_register_values.end())
+ {
+ // Emulate instruction failed and it haven't changed PC. Advance PC
+ // with the size of the current opcode because the emulation of all
+ // PC modifying instruction should be successful. The failure most
+ // likely caused by a not supported instruction which don't modify PC.
+ next_pc = register_context_sp->GetPC() + emulator_ap->GetOpcode().GetByteSize();
+ next_flags = ReadFlags (register_context_sp.get());
+ }
+ else
+ {
+ // The instruction emulation failed after it modified the PC. It is an
+ // unknown error where we can't continue because the next instruction is
+ // modifying the PC but we don't know how.
+ return Error ("Instruction emulation failed unexpectedly.");
+ }
+
+ if (m_arch.GetMachine() == llvm::Triple::arm)
+ {
+ if (next_flags & 0x20)
+ {
+ // Thumb mode
+ error = SetSoftwareBreakpoint(next_pc, 2);
+ }
+ else
+ {
+ // Arm mode
+ error = SetSoftwareBreakpoint(next_pc, 4);
+ }
+ }
+ else if (m_arch.GetMachine() == llvm::Triple::mips64
+ || m_arch.GetMachine() == llvm::Triple::mips64el
+ || m_arch.GetMachine() == llvm::Triple::mips
+ || m_arch.GetMachine() == llvm::Triple::mipsel)
+ error = SetSoftwareBreakpoint(next_pc, 4);
+ else
+ {
+ // No size hint is given for the next breakpoint
+ error = SetSoftwareBreakpoint(next_pc, 0);
+ }
+
+ if (error.Fail())
+ return error;
+
+ m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
+
+ return Error();
+}
+
+bool
+NativeProcessLinux::SupportHardwareSingleStepping() const
+{
+ if (m_arch.GetMachine() == llvm::Triple::arm
+ || m_arch.GetMachine() == llvm::Triple::mips64 || m_arch.GetMachine() == llvm::Triple::mips64el
+ || m_arch.GetMachine() == llvm::Triple::mips || m_arch.GetMachine() == llvm::Triple::mipsel)
+ return false;
+ return true;
+}
+
+Error
+NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s called: pid %" PRIu64, __FUNCTION__, GetID ());
+
+ bool software_single_step = !SupportHardwareSingleStepping();
+
+ Mutex::Locker locker (m_threads_mutex);
+
+ if (software_single_step)
+ {
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not contain NULL threads");
+
+ const ResumeAction *const action = resume_actions.GetActionForThread (thread_sp->GetID (), true);
+ if (action == nullptr)
+ continue;
+
+ if (action->state == eStateStepping)
+ {
+ Error error = SetupSoftwareSingleStepping(static_cast<NativeThreadLinux &>(*thread_sp));
+ if (error.Fail())
+ return error;
+ }
+ }
+ }
+
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not contain NULL threads");
+
+ const ResumeAction *const action = resume_actions.GetActionForThread (thread_sp->GetID (), true);
+
+ if (action == nullptr)
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s no action specified for pid %" PRIu64 " tid %" PRIu64,
+ __FUNCTION__, GetID (), thread_sp->GetID ());
+ continue;
+ }
+
+ if (log)
+ {
+ log->Printf ("NativeProcessLinux::%s processing resume action state %s for pid %" PRIu64 " tid %" PRIu64,
+ __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ());
+ }
+
+ switch (action->state)
+ {
+ case eStateRunning:
+ case eStateStepping:
+ {
+ // Run the thread, possibly feeding it the signal.
+ const int signo = action->signal;
+ ResumeThread(static_cast<NativeThreadLinux &>(*thread_sp), action->state, signo);
+ break;
+ }
+
+ case eStateSuspended:
+ case eStateStopped:
+ lldbassert(0 && "Unexpected state");
+
+ default:
+ return Error ("NativeProcessLinux::%s (): unexpected state %s specified for pid %" PRIu64 ", tid %" PRIu64,
+ __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ());
+ }
+ }
+
+ return Error();
+}
+
+Error
+NativeProcessLinux::Halt ()
+{
+ Error error;
+
+ if (kill (GetID (), SIGSTOP) != 0)
+ error.SetErrorToErrno ();
+
+ return error;
+}
+
+Error
+NativeProcessLinux::Detach ()
+{
+ Error error;
+
+ // Stop monitoring the inferior.
+ m_sigchld_handle.reset();
+
+ // Tell ptrace to detach from the process.
+ if (GetID () == LLDB_INVALID_PROCESS_ID)
+ return error;
+
+ for (auto thread_sp : m_threads)
+ {
+ Error e = Detach(thread_sp->GetID());
+ if (e.Fail())
+ error = e; // Save the error, but still attempt to detach from other threads.
+ }
+
+ return error;
+}
+
+Error
+NativeProcessLinux::Signal (int signo)
+{
+ Error error;
+
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s: sending signal %d (%s) to pid %" PRIu64,
+ __FUNCTION__, signo, Host::GetSignalAsCString(signo), GetID());
+
+ if (kill(GetID(), signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error
+NativeProcessLinux::Interrupt ()
+{
+ // Pick a running thread (or if none, a not-dead stopped thread) as
+ // the chosen thread that will be the stop-reason thread.
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ NativeThreadProtocolSP running_thread_sp;
+ NativeThreadProtocolSP stopped_thread_sp;
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s selecting running thread for interrupt target", __FUNCTION__);
+
+ Mutex::Locker locker (m_threads_mutex);
+
+ for (auto thread_sp : m_threads)
+ {
+ // The thread shouldn't be null but lets just cover that here.
+ if (!thread_sp)
+ continue;
+
+ // If we have a running or stepping thread, we'll call that the
+ // target of the interrupt.
+ const auto thread_state = thread_sp->GetState ();
+ if (thread_state == eStateRunning ||
+ thread_state == eStateStepping)
+ {
+ running_thread_sp = thread_sp;
+ break;
+ }
+ else if (!stopped_thread_sp && StateIsStoppedState (thread_state, true))
+ {
+ // Remember the first non-dead stopped thread. We'll use that as a backup if there are no running threads.
+ stopped_thread_sp = thread_sp;
+ }
+ }
+
+ if (!running_thread_sp && !stopped_thread_sp)
+ {
+ Error error("found no running/stepping or live stopped threads as target for interrupt");
+ if (log)
+ log->Printf ("NativeProcessLinux::%s skipping due to error: %s", __FUNCTION__, error.AsCString ());
+
+ return error;
+ }
+
+ NativeThreadProtocolSP deferred_signal_thread_sp = running_thread_sp ? running_thread_sp : stopped_thread_sp;
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " %s tid %" PRIu64 " chosen for interrupt target",
+ __FUNCTION__,
+ GetID (),
+ running_thread_sp ? "running" : "stopped",
+ deferred_signal_thread_sp->GetID ());
+
+ StopRunningThreads(deferred_signal_thread_sp->GetID());
+
+ return Error();
+}
+
+Error
+NativeProcessLinux::Kill ()
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s called for PID %" PRIu64, __FUNCTION__, GetID ());
+
+ Error error;
+
+ switch (m_state)
+ {
+ case StateType::eStateInvalid:
+ case StateType::eStateExited:
+ case StateType::eStateCrashed:
+ case StateType::eStateDetached:
+ case StateType::eStateUnloaded:
+ // Nothing to do - the process is already dead.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s ignored for PID %" PRIu64 " due to current state: %s", __FUNCTION__, GetID (), StateAsCString (m_state));
+ return error;
+
+ case StateType::eStateConnected:
+ case StateType::eStateAttaching:
+ case StateType::eStateLaunching:
+ case StateType::eStateStopped:
+ case StateType::eStateRunning:
+ case StateType::eStateStepping:
+ case StateType::eStateSuspended:
+ // We can try to kill a process in these states.
+ break;
+ }
+
+ if (kill (GetID (), SIGKILL) != 0)
+ {
+ error.SetErrorToErrno ();
+ return error;
+ }
+
+ return error;
+}
+
+static Error
+ParseMemoryRegionInfoFromProcMapsLine (const std::string &maps_line, MemoryRegionInfo &memory_region_info)
+{
+ memory_region_info.Clear();
+
+ StringExtractor line_extractor (maps_line.c_str ());
+
+ // Format: {address_start_hex}-{address_end_hex} perms offset dev inode pathname
+ // perms: rwxp (letter is present if set, '-' if not, final character is p=private, s=shared).
+
+ // Parse out the starting address
+ lldb::addr_t start_address = line_extractor.GetHexMaxU64 (false, 0);
+
+ // Parse out hyphen separating start and end address from range.
+ if (!line_extractor.GetBytesLeft () || (line_extractor.GetChar () != '-'))
+ return Error ("malformed /proc/{pid}/maps entry, missing dash between address range");
+
+ // Parse out the ending address
+ lldb::addr_t end_address = line_extractor.GetHexMaxU64 (false, start_address);
+
+ // Parse out the space after the address.
+ if (!line_extractor.GetBytesLeft () || (line_extractor.GetChar () != ' '))
+ return Error ("malformed /proc/{pid}/maps entry, missing space after range");
+
+ // Save the range.
+ memory_region_info.GetRange ().SetRangeBase (start_address);
+ memory_region_info.GetRange ().SetRangeEnd (end_address);
+
+ // Parse out each permission entry.
+ if (line_extractor.GetBytesLeft () < 4)
+ return Error ("malformed /proc/{pid}/maps entry, missing some portion of permissions");
+
+ // Handle read permission.
+ const char read_perm_char = line_extractor.GetChar ();
+ if (read_perm_char == 'r')
+ memory_region_info.SetReadable (MemoryRegionInfo::OptionalBool::eYes);
+ else
+ {
+ assert ( (read_perm_char == '-') && "unexpected /proc/{pid}/maps read permission char" );
+ memory_region_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo);
+ }
+
+ // Handle write permission.
+ const char write_perm_char = line_extractor.GetChar ();
+ if (write_perm_char == 'w')
+ memory_region_info.SetWritable (MemoryRegionInfo::OptionalBool::eYes);
+ else
+ {
+ assert ( (write_perm_char == '-') && "unexpected /proc/{pid}/maps write permission char" );
+ memory_region_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo);
+ }
+
+ // Handle execute permission.
+ const char exec_perm_char = line_extractor.GetChar ();
+ if (exec_perm_char == 'x')
+ memory_region_info.SetExecutable (MemoryRegionInfo::OptionalBool::eYes);
+ else
+ {
+ assert ( (exec_perm_char == '-') && "unexpected /proc/{pid}/maps exec permission char" );
+ memory_region_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo);
+ }
+
+ return Error ();
+}
+
+Error
+NativeProcessLinux::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info)
+{
+ // FIXME review that the final memory region returned extends to the end of the virtual address space,
+ // with no perms if it is not mapped.
+
+ // Use an approach that reads memory regions from /proc/{pid}/maps.
+ // Assume proc maps entries are in ascending order.
+ // FIXME assert if we find differently.
+ Mutex::Locker locker (m_mem_region_cache_mutex);
+
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ Error error;
+
+ if (m_supports_mem_region == LazyBool::eLazyBoolNo)
+ {
+ // We're done.
+ error.SetErrorString ("unsupported");
+ return error;
+ }
+
+ // If our cache is empty, pull the latest. There should always be at least one memory region
+ // if memory region handling is supported.
+ if (m_mem_region_cache.empty ())
+ {
+ error = ProcFileReader::ProcessLineByLine (GetID (), "maps",
+ [&] (const std::string &line) -> bool
+ {
+ MemoryRegionInfo info;
+ const Error parse_error = ParseMemoryRegionInfoFromProcMapsLine (line, info);
+ if (parse_error.Success ())
+ {
+ m_mem_region_cache.push_back (info);
+ return true;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s failed to parse proc maps line '%s': %s", __FUNCTION__, line.c_str (), error.AsCString ());
+ return false;
+ }
+ });
+
+ // If we had an error, we'll mark unsupported.
+ if (error.Fail ())
+ {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ return error;
+ }
+ else if (m_mem_region_cache.empty ())
+ {
+ // No entries after attempting to read them. This shouldn't happen if /proc/{pid}/maps
+ // is supported. Assume we don't support map entries via procfs.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s failed to find any procfs maps entries, assuming no support for memory region metadata retrieval", __FUNCTION__);
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ error.SetErrorString ("not supported");
+ return error;
+ }
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s read %" PRIu64 " memory region entries from /proc/%" PRIu64 "/maps", __FUNCTION__, static_cast<uint64_t> (m_mem_region_cache.size ()), GetID ());
+
+ // We support memory retrieval, remember that.
+ m_supports_mem_region = LazyBool::eLazyBoolYes;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s reusing %" PRIu64 " cached memory region entries", __FUNCTION__, static_cast<uint64_t> (m_mem_region_cache.size ()));
+ }
+
+ lldb::addr_t prev_base_address = 0;
+
+ // FIXME start by finding the last region that is <= target address using binary search. Data is sorted.
+ // There can be a ton of regions on pthreads apps with lots of threads.
+ for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end (); ++it)
+ {
+ MemoryRegionInfo &proc_entry_info = *it;
+
+ // Sanity check assumption that /proc/{pid}/maps entries are ascending.
+ assert ((proc_entry_info.GetRange ().GetRangeBase () >= prev_base_address) && "descending /proc/pid/maps entries detected, unexpected");
+ prev_base_address = proc_entry_info.GetRange ().GetRangeBase ();
+
+ // If the target address comes before this entry, indicate distance to next region.
+ if (load_addr < proc_entry_info.GetRange ().GetRangeBase ())
+ {
+ range_info.GetRange ().SetRangeBase (load_addr);
+ range_info.GetRange ().SetByteSize (proc_entry_info.GetRange ().GetRangeBase () - load_addr);
+ range_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo);
+
+ return error;
+ }
+ else if (proc_entry_info.GetRange ().Contains (load_addr))
+ {
+ // The target address is within the memory region we're processing here.
+ range_info = proc_entry_info;
+ return error;
+ }
+
+ // The target memory address comes somewhere after the region we just parsed.
+ }
+
+ // If we made it here, we didn't find an entry that contained the given address. Return the
+ // load_addr as start and the amount of bytes betwwen load address and the end of the memory as
+ // size.
+ range_info.GetRange ().SetRangeBase (load_addr);
+ switch (m_arch.GetAddressByteSize())
+ {
+ case 4:
+ range_info.GetRange ().SetByteSize (0x100000000ull - load_addr);
+ break;
+ case 8:
+ range_info.GetRange ().SetByteSize (0ull - load_addr);
+ break;
+ default:
+ assert(false && "Unrecognized data byte size");
+ break;
+ }
+ range_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo);
+ return error;
+}
+
+void
+NativeProcessLinux::DoStopIDBumped (uint32_t newBumpId)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s(newBumpId=%" PRIu32 ") called", __FUNCTION__, newBumpId);
+
+ {
+ Mutex::Locker locker (m_mem_region_cache_mutex);
+ if (log)
+ log->Printf ("NativeProcessLinux::%s clearing %" PRIu64 " entries from the cache", __FUNCTION__, static_cast<uint64_t> (m_mem_region_cache.size ()));
+ m_mem_region_cache.clear ();
+ }
+}
+
+Error
+NativeProcessLinux::AllocateMemory(size_t size, uint32_t permissions, lldb::addr_t &addr)
+{
+ // FIXME implementing this requires the equivalent of
+ // InferiorCallPOSIX::InferiorCallMmap, which depends on
+ // functional ThreadPlans working with Native*Protocol.
+#if 1
+ return Error ("not implemented yet");
+#else
+ addr = LLDB_INVALID_ADDRESS;
+
+ unsigned prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ prot |= eMmapProtRead;
+ if (permissions & lldb::ePermissionsWritable)
+ prot |= eMmapProtWrite;
+ if (permissions & lldb::ePermissionsExecutable)
+ prot |= eMmapProtExec;
+
+ // TODO implement this directly in NativeProcessLinux
+ // (and lift to NativeProcessPOSIX if/when that class is
+ // refactored out).
+ if (InferiorCallMmap(this, addr, 0, size, prot,
+ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
+ m_addr_to_mmap_size[addr] = size;
+ return Error ();
+ } else {
+ addr = LLDB_INVALID_ADDRESS;
+ return Error("unable to allocate %" PRIu64 " bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions));
+ }
+#endif
+}
+
+Error
+NativeProcessLinux::DeallocateMemory (lldb::addr_t addr)
+{
+ // FIXME see comments in AllocateMemory - required lower-level
+ // bits not in place yet (ThreadPlans)
+ return Error ("not implemented");
+}
+
+lldb::addr_t
+NativeProcessLinux::GetSharedLibraryInfoAddress ()
+{
+#if 1
+ // punt on this for now
+ return LLDB_INVALID_ADDRESS;
+#else
+ // Return the image info address for the exe module
+#if 1
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ ModuleSP module_sp;
+ Error error = GetExeModuleSP (module_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Warning ("NativeProcessLinux::%s failed to retrieve exe module: %s", __FUNCTION__, error.AsCString ());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ if (module_sp == nullptr)
+ {
+ if (log)
+ log->Warning ("NativeProcessLinux::%s exe module returned was NULL", __FUNCTION__);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ ObjectFileSP object_file_sp = module_sp->GetObjectFile ();
+ if (object_file_sp == nullptr)
+ {
+ if (log)
+ log->Warning ("NativeProcessLinux::%s exe module returned a NULL object file", __FUNCTION__);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ return obj_file_sp->GetImageInfoAddress();
+#else
+ Target *target = &GetTarget();
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress(target);
+
+ if (addr.IsValid())
+ return addr.GetLoadAddress(target);
+ return LLDB_INVALID_ADDRESS;
+#endif
+#endif // punt on this for now
+}
+
+size_t
+NativeProcessLinux::UpdateThreads ()
+{
+ // The NativeProcessLinux monitoring threads are always up to date
+ // with respect to thread state and they keep the thread list
+ // populated properly. All this method needs to do is return the
+ // thread count.
+ Mutex::Locker locker (m_threads_mutex);
+ return m_threads.size ();
+}
+
+bool
+NativeProcessLinux::GetArchitecture (ArchSpec &arch) const
+{
+ arch = m_arch;
+ return true;
+}
+
+Error
+NativeProcessLinux::GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size)
+{
+ // FIXME put this behind a breakpoint protocol class that can be
+ // set per architecture. Need ARM, MIPS support here.
+ static const uint8_t g_i386_opcode [] = { 0xCC };
+
+ switch (m_arch.GetMachine ())
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ actual_opcode_size = static_cast<uint32_t> (sizeof(g_i386_opcode));
+ return Error ();
+
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ // On these architectures the PC don't get updated for breakpoint hits
+ actual_opcode_size = 0;
+ return Error ();
+
+ default:
+ assert(false && "CPU type not supported!");
+ return Error ("CPU type not supported");
+ }
+}
+
+Error
+NativeProcessLinux::SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware)
+{
+ if (hardware)
+ return Error ("NativeProcessLinux does not support hardware breakpoints");
+ else
+ return SetSoftwareBreakpoint (addr, size);
+}
+
+Error
+NativeProcessLinux::GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint,
+ size_t &actual_opcode_size,
+ const uint8_t *&trap_opcode_bytes)
+{
+ // FIXME put this behind a breakpoint protocol class that can be set per
+ // architecture. Need MIPS support here.
+ static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xd4 };
+ // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the
+ // linux kernel does otherwise.
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 };
+ static const uint8_t g_i386_opcode [] = { 0xCC };
+ static const uint8_t g_mips64_opcode[] = { 0x00, 0x00, 0x00, 0x0d };
+ static const uint8_t g_mips64el_opcode[] = { 0x0d, 0x00, 0x00, 0x00 };
+ static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde };
+
+ switch (m_arch.GetMachine ())
+ {
+ case llvm::Triple::aarch64:
+ trap_opcode_bytes = g_aarch64_opcode;
+ actual_opcode_size = sizeof(g_aarch64_opcode);
+ return Error ();
+
+ case llvm::Triple::arm:
+ switch (trap_opcode_size_hint)
+ {
+ case 2:
+ trap_opcode_bytes = g_thumb_breakpoint_opcode;
+ actual_opcode_size = sizeof(g_thumb_breakpoint_opcode);
+ return Error ();
+ case 4:
+ trap_opcode_bytes = g_arm_breakpoint_opcode;
+ actual_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ return Error ();
+ default:
+ assert(false && "Unrecognised trap opcode size hint!");
+ return Error ("Unrecognised trap opcode size hint!");
+ }
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ trap_opcode_bytes = g_i386_opcode;
+ actual_opcode_size = sizeof(g_i386_opcode);
+ return Error ();
+
+ case llvm::Triple::mips:
+ case llvm::Triple::mips64:
+ trap_opcode_bytes = g_mips64_opcode;
+ actual_opcode_size = sizeof(g_mips64_opcode);
+ return Error ();
+
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64el:
+ trap_opcode_bytes = g_mips64el_opcode;
+ actual_opcode_size = sizeof(g_mips64el_opcode);
+ return Error ();
+
+ default:
+ assert(false && "CPU type not supported!");
+ return Error ("CPU type not supported");
+ }
+}
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGSEGV(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGSEGV);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGSEGV");
+ break;
+ case SI_KERNEL:
+ // Linux will occasionally send spurious SI_KERNEL codes.
+ // (this is poorly documented in sigaction)
+ // One way to get this is via unaligned SIMD loads.
+ reason = ProcessMessage::eInvalidAddress; // for lack of anything better
+ break;
+ case SEGV_MAPERR:
+ reason = ProcessMessage::eInvalidAddress;
+ break;
+ case SEGV_ACCERR:
+ reason = ProcessMessage::ePrivilegedAddress;
+ break;
+ }
+
+ return reason;
+}
+#endif
+
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGILL(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGILL);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGILL");
+ break;
+ case ILL_ILLOPC:
+ reason = ProcessMessage::eIllegalOpcode;
+ break;
+ case ILL_ILLOPN:
+ reason = ProcessMessage::eIllegalOperand;
+ break;
+ case ILL_ILLADR:
+ reason = ProcessMessage::eIllegalAddressingMode;
+ break;
+ case ILL_ILLTRP:
+ reason = ProcessMessage::eIllegalTrap;
+ break;
+ case ILL_PRVOPC:
+ reason = ProcessMessage::ePrivilegedOpcode;
+ break;
+ case ILL_PRVREG:
+ reason = ProcessMessage::ePrivilegedRegister;
+ break;
+ case ILL_COPROC:
+ reason = ProcessMessage::eCoprocessorError;
+ break;
+ case ILL_BADSTK:
+ reason = ProcessMessage::eInternalStackError;
+ break;
+ }
+
+ return reason;
+}
+#endif
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGFPE(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGFPE);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGFPE");
+ break;
+ case FPE_INTDIV:
+ reason = ProcessMessage::eIntegerDivideByZero;
+ break;
+ case FPE_INTOVF:
+ reason = ProcessMessage::eIntegerOverflow;
+ break;
+ case FPE_FLTDIV:
+ reason = ProcessMessage::eFloatDivideByZero;
+ break;
+ case FPE_FLTOVF:
+ reason = ProcessMessage::eFloatOverflow;
+ break;
+ case FPE_FLTUND:
+ reason = ProcessMessage::eFloatUnderflow;
+ break;
+ case FPE_FLTRES:
+ reason = ProcessMessage::eFloatInexactResult;
+ break;
+ case FPE_FLTINV:
+ reason = ProcessMessage::eFloatInvalidOperation;
+ break;
+ case FPE_FLTSUB:
+ reason = ProcessMessage::eFloatSubscriptRange;
+ break;
+ }
+
+ return reason;
+}
+#endif
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGBUS(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGBUS);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGBUS");
+ break;
+ case BUS_ADRALN:
+ reason = ProcessMessage::eIllegalAlignment;
+ break;
+ case BUS_ADRERR:
+ reason = ProcessMessage::eIllegalAddress;
+ break;
+ case BUS_OBJERR:
+ reason = ProcessMessage::eHardwareError;
+ break;
+ }
+
+ return reason;
+}
+#endif
+
+Error
+NativeProcessLinux::ReadMemory (lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read)
+{
+ if (ProcessVmReadvSupported()) {
+ // The process_vm_readv path is about 50 times faster than ptrace api. We want to use
+ // this syscall if it is supported.
+
+ const ::pid_t pid = GetID();
+
+ struct iovec local_iov, remote_iov;
+ local_iov.iov_base = buf;
+ local_iov.iov_len = size;
+ remote_iov.iov_base = reinterpret_cast<void *>(addr);
+ remote_iov.iov_len = size;
+
+ bytes_read = process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0);
+ const bool success = bytes_read == size;
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessLinux::%s using process_vm_readv to read %zd bytes from inferior address 0x%" PRIx64": %s",
+ __FUNCTION__, size, addr, success ? "Success" : strerror(errno));
+
+ if (success)
+ return Error();
+ // else
+ // the call failed for some reason, let's retry the read using ptrace api.
+ }
+
+ unsigned char *dst = static_cast<unsigned char*>(buf);
+ size_t remainder;
+ long data;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL));
+ if (log)
+ ProcessPOSIXLog::IncNestLevel();
+ if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY))
+ log->Printf ("NativeProcessLinux::%s(%p, %p, %zd, _)", __FUNCTION__, (void*)addr, buf, size);
+
+ for (bytes_read = 0; bytes_read < size; bytes_read += remainder)
+ {
+ Error error = NativeProcessLinux::PtraceWrapper(PTRACE_PEEKDATA, GetID(), (void*)addr, nullptr, 0, &data);
+ if (error.Fail())
+ {
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return error;
+ }
+
+ remainder = size - bytes_read;
+ remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder;
+
+ // Copy the data into our buffer
+ memcpy(dst, &data, remainder);
+
+ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
+ size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
+ {
+ uintptr_t print_dst = 0;
+ // Format bytes from data by moving into print_dst for log output
+ for (unsigned i = 0; i < remainder; ++i)
+ print_dst |= (((data >> i*8) & 0xFF) << i*8);
+ log->Printf ("NativeProcessLinux::%s() [0x%" PRIx64 "]:0x%" PRIx64 " (0x%" PRIx64 ")",
+ __FUNCTION__, addr, uint64_t(print_dst), uint64_t(data));
+ }
+ addr += k_ptrace_word_size;
+ dst += k_ptrace_word_size;
+ }
+
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return Error();
+}
+
+Error
+NativeProcessLinux::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read)
+{
+ Error error = ReadMemory(addr, buf, size, bytes_read);
+ if (error.Fail()) return error;
+ return m_breakpoint_list.RemoveTrapsFromBuffer(addr, buf, size);
+}
+
+Error
+NativeProcessLinux::WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written)
+{
+ const unsigned char *src = static_cast<const unsigned char*>(buf);
+ size_t remainder;
+ Error error;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL));
+ if (log)
+ ProcessPOSIXLog::IncNestLevel();
+ if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY))
+ log->Printf ("NativeProcessLinux::%s(0x%" PRIx64 ", %p, %zu)", __FUNCTION__, addr, buf, size);
+
+ for (bytes_written = 0; bytes_written < size; bytes_written += remainder)
+ {
+ remainder = size - bytes_written;
+ remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder;
+
+ if (remainder == k_ptrace_word_size)
+ {
+ unsigned long data = 0;
+ memcpy(&data, src, k_ptrace_word_size);
+
+ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
+ size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
+ log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
+ (void*)addr, *(const unsigned long*)src, data);
+
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_POKEDATA, GetID(), (void*)addr, (void*)data);
+ if (error.Fail())
+ {
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return error;
+ }
+ }
+ else
+ {
+ unsigned char buff[8];
+ size_t bytes_read;
+ error = ReadMemory(addr, buff, k_ptrace_word_size, bytes_read);
+ if (error.Fail())
+ {
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return error;
+ }
+
+ memcpy(buff, src, remainder);
+
+ size_t bytes_written_rec;
+ error = WriteMemory(addr, buff, k_ptrace_word_size, bytes_written_rec);
+ if (error.Fail())
+ {
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return error;
+ }
+
+ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
+ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
+ size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
+ log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
+ (void*)addr, *(const unsigned long*)src, *(unsigned long*)buff);
+ }
+
+ addr += k_ptrace_word_size;
+ src += k_ptrace_word_size;
+ }
+ if (log)
+ ProcessPOSIXLog::DecNestLevel();
+ return error;
+}
+
+Error
+NativeProcessLinux::Resume (lldb::tid_t tid, uint32_t signo)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid,
+ Host::GetSignalAsCString(signo));
+
+
+
+ intptr_t data = 0;
+
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = signo;
+
+ Error error = PtraceWrapper(PTRACE_CONT, tid, nullptr, (void*)data);
+
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() resuming thread = %" PRIu64 " result = %s", __FUNCTION__, tid, error.Success() ? "true" : "false");
+ return error;
+}
+
+Error
+NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo)
+{
+ intptr_t data = 0;
+
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = signo;
+
+ // If hardware single-stepping is not supported, we just do a continue. The breakpoint on the
+ // next instruction has been setup in NativeProcessLinux::Resume.
+ return PtraceWrapper(SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT,
+ tid, nullptr, (void*)data);
+}
+
+Error
+NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo)
+{
+ return PtraceWrapper(PTRACE_GETSIGINFO, tid, nullptr, siginfo);
+}
+
+Error
+NativeProcessLinux::GetEventMessage(lldb::tid_t tid, unsigned long *message)
+{
+ return PtraceWrapper(PTRACE_GETEVENTMSG, tid, nullptr, message);
+}
+
+Error
+NativeProcessLinux::Detach(lldb::tid_t tid)
+{
+ if (tid == LLDB_INVALID_THREAD_ID)
+ return Error();
+
+ return PtraceWrapper(PTRACE_DETACH, tid);
+}
+
+bool
+NativeProcessLinux::DupDescriptor(const FileSpec &file_spec, int fd, int flags)
+{
+ int target_fd = open(file_spec.GetCString(), flags, 0666);
+
+ if (target_fd == -1)
+ return false;
+
+ if (dup2(target_fd, fd) == -1)
+ return false;
+
+ return (close(target_fd) == -1) ? false : true;
+}
+
+bool
+NativeProcessLinux::HasThreadNoLock (lldb::tid_t thread_id)
+{
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not contain NULL threads");
+ if (thread_sp->GetID () == thread_id)
+ {
+ // We have this thread.
+ return true;
+ }
+ }
+
+ // We don't have this thread.
+ return false;
+}
+
+bool
+NativeProcessLinux::StopTrackingThread (lldb::tid_t thread_id)
+{
+ Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD);
+
+ if (log)
+ log->Printf("NativeProcessLinux::%s (tid: %" PRIu64 ")", __FUNCTION__, thread_id);
+
+ bool found = false;
+
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto it = m_threads.begin (); it != m_threads.end (); ++it)
+ {
+ if (*it && ((*it)->GetID () == thread_id))
+ {
+ m_threads.erase (it);
+ found = true;
+ break;
+ }
+ }
+
+ SignalIfAllThreadsStopped();
+
+ return found;
+}
+
+NativeThreadLinuxSP
+NativeProcessLinux::AddThread (lldb::tid_t thread_id)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ Mutex::Locker locker (m_threads_mutex);
+
+ if (log)
+ {
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " adding thread with tid %" PRIu64,
+ __FUNCTION__,
+ GetID (),
+ thread_id);
+ }
+
+ assert (!HasThreadNoLock (thread_id) && "attempted to add a thread by id that already exists");
+
+ // If this is the first thread, save it as the current thread
+ if (m_threads.empty ())
+ SetCurrentThreadID (thread_id);
+
+ auto thread_sp = std::make_shared<NativeThreadLinux>(this, thread_id);
+ m_threads.push_back (thread_sp);
+ return thread_sp;
+}
+
+Error
+NativeProcessLinux::FixupBreakpointPCAsNeeded(NativeThreadLinux &thread)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ Error error;
+
+ // Find out the size of a breakpoint (might depend on where we are in the code).
+ NativeRegisterContextSP context_sp = thread.GetRegisterContext();
+ if (!context_sp)
+ {
+ error.SetErrorString ("cannot get a NativeRegisterContext for the thread");
+ if (log)
+ log->Printf ("NativeProcessLinux::%s failed: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ uint32_t breakpoint_size = 0;
+ error = GetSoftwareBreakpointPCOffset(breakpoint_size);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s GetBreakpointSize() failed: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s breakpoint size: %" PRIu32, __FUNCTION__, breakpoint_size);
+ }
+
+ // First try probing for a breakpoint at a software breakpoint location: PC - breakpoint size.
+ const lldb::addr_t initial_pc_addr = context_sp->GetPCfromBreakpointLocation ();
+ lldb::addr_t breakpoint_addr = initial_pc_addr;
+ if (breakpoint_size > 0)
+ {
+ // Do not allow breakpoint probe to wrap around.
+ if (breakpoint_addr >= breakpoint_size)
+ breakpoint_addr -= breakpoint_size;
+ }
+
+ // Check if we stopped because of a breakpoint.
+ NativeBreakpointSP breakpoint_sp;
+ error = m_breakpoint_list.GetBreakpoint (breakpoint_addr, breakpoint_sp);
+ if (!error.Success () || !breakpoint_sp)
+ {
+ // We didn't find one at a software probe location. Nothing to do.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " no lldb breakpoint found at current pc with adjustment: 0x%" PRIx64, __FUNCTION__, GetID (), breakpoint_addr);
+ return Error ();
+ }
+
+ // If the breakpoint is not a software breakpoint, nothing to do.
+ if (!breakpoint_sp->IsSoftwareBreakpoint ())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " breakpoint found at 0x%" PRIx64 ", not software, nothing to adjust", __FUNCTION__, GetID (), breakpoint_addr);
+ return Error ();
+ }
+
+ //
+ // We have a software breakpoint and need to adjust the PC.
+ //
+
+ // Sanity check.
+ if (breakpoint_size == 0)
+ {
+ // Nothing to do! How did we get here?
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " breakpoint found at 0x%" PRIx64 ", it is software, but the size is zero, nothing to do (unexpected)", __FUNCTION__, GetID (), breakpoint_addr);
+ return Error ();
+ }
+
+ // Change the program counter.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": changing PC from 0x%" PRIx64 " to 0x%" PRIx64, __FUNCTION__, GetID(), thread.GetID(), initial_pc_addr, breakpoint_addr);
+
+ error = context_sp->SetPC (breakpoint_addr);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": failed to set PC: %s", __FUNCTION__, GetID(), thread.GetID(), error.AsCString ());
+ return error;
+ }
+
+ return error;
+}
+
+Error
+NativeProcessLinux::GetLoadedModuleFileSpec(const char* module_path, FileSpec& file_spec)
+{
+ FileSpec module_file_spec(module_path, true);
+
+ bool found = false;
+ file_spec.Clear();
+ ProcFileReader::ProcessLineByLine(GetID(), "maps",
+ [&] (const std::string &line)
+ {
+ SmallVector<StringRef, 16> columns;
+ StringRef(line).split(columns, " ", -1, false);
+ if (columns.size() < 6)
+ return true; // continue searching
+
+ FileSpec this_file_spec(columns[5].str().c_str(), false);
+ if (this_file_spec.GetFilename() != module_file_spec.GetFilename())
+ return true; // continue searching
+
+ file_spec = this_file_spec;
+ found = true;
+ return false; // we are done
+ });
+
+ if (! found)
+ return Error("Module file (%s) not found in /proc/%" PRIu64 "/maps file!",
+ module_file_spec.GetFilename().AsCString(), GetID());
+
+ return Error();
+}
+
+Error
+NativeProcessLinux::GetFileLoadAddress(const llvm::StringRef& file_name, lldb::addr_t& load_addr)
+{
+ load_addr = LLDB_INVALID_ADDRESS;
+ Error error = ProcFileReader::ProcessLineByLine (GetID (), "maps",
+ [&] (const std::string &line) -> bool
+ {
+ StringRef maps_row(line);
+
+ SmallVector<StringRef, 16> maps_columns;
+ maps_row.split(maps_columns, StringRef(" "), -1, false);
+
+ if (maps_columns.size() < 6)
+ {
+ // Return true to continue reading the proc file
+ return true;
+ }
+
+ if (maps_columns[5] == file_name)
+ {
+ StringExtractor addr_extractor(maps_columns[0].str().c_str());
+ load_addr = addr_extractor.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+
+ // Return false to stop reading the proc file further
+ return false;
+ }
+
+ // Return true to continue reading the proc file
+ return true;
+ });
+ return error;
+}
+
+NativeThreadLinuxSP
+NativeProcessLinux::GetThreadByID(lldb::tid_t tid)
+{
+ return std::static_pointer_cast<NativeThreadLinux>(NativeProcessProtocol::GetThreadByID(tid));
+}
+
+Error
+NativeProcessLinux::ResumeThread(NativeThreadLinux &thread, lldb::StateType state, int signo)
+{
+ Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD);
+
+ if (log)
+ log->Printf("NativeProcessLinux::%s (tid: %" PRIu64 ")",
+ __FUNCTION__, thread.GetID());
+
+ // Before we do the resume below, first check if we have a pending
+ // stop notification that is currently waiting for
+ // all threads to stop. This is potentially a buggy situation since
+ // we're ostensibly waiting for threads to stop before we send out the
+ // pending notification, and here we are resuming one before we send
+ // out the pending stop notification.
+ if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && log)
+ {
+ log->Printf("NativeProcessLinux::%s about to resume tid %" PRIu64 " per explicit request but we have a pending stop notification (tid %" PRIu64 ") that is actively waiting for this thread to stop. Valid sequence of events?", __FUNCTION__, thread.GetID(), m_pending_notification_tid);
+ }
+
+ // Request a resume. We expect this to be synchronous and the system
+ // to reflect it is running after this completes.
+ switch (state)
+ {
+ case eStateRunning:
+ {
+ thread.SetRunning();
+ const auto resume_result = Resume(thread.GetID(), signo);
+ if (resume_result.Success())
+ SetState(eStateRunning, true);
+ return resume_result;
+ }
+ case eStateStepping:
+ {
+ thread.SetStepping();
+ const auto step_result = SingleStep(thread.GetID(), signo);
+ if (step_result.Success())
+ SetState(eStateRunning, true);
+ return step_result;
+ }
+ default:
+ if (log)
+ log->Printf("NativeProcessLinux::%s Unhandled state %s.",
+ __FUNCTION__, StateAsCString(state));
+ llvm_unreachable("Unhandled state for resume");
+ }
+}
+
+//===----------------------------------------------------------------------===//
+
+void
+NativeProcessLinux::StopRunningThreads(const lldb::tid_t triggering_tid)
+{
+ Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD);
+
+ if (log)
+ {
+ log->Printf("NativeProcessLinux::%s about to process event: (triggering_tid: %" PRIu64 ")",
+ __FUNCTION__, triggering_tid);
+ }
+
+ m_pending_notification_tid = triggering_tid;
+
+ // Request a stop for all the thread stops that need to be stopped
+ // and are not already known to be stopped.
+ for (const auto &thread_sp: m_threads)
+ {
+ if (StateIsRunningState(thread_sp->GetState()))
+ static_pointer_cast<NativeThreadLinux>(thread_sp)->RequestStop();
+ }
+
+ SignalIfAllThreadsStopped();
+
+ if (log)
+ {
+ log->Printf("NativeProcessLinux::%s event processing done", __FUNCTION__);
+ }
+}
+
+void
+NativeProcessLinux::SignalIfAllThreadsStopped()
+{
+ if (m_pending_notification_tid == LLDB_INVALID_THREAD_ID)
+ return; // No pending notification. Nothing to do.
+
+ for (const auto &thread_sp: m_threads)
+ {
+ if (StateIsRunningState(thread_sp->GetState()))
+ return; // Some threads are still running. Don't signal yet.
+ }
+
+ // We have a pending notification and all threads have stopped.
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_BREAKPOINTS));
+
+ // Clear any temporary breakpoints we used to implement software single stepping.
+ for (const auto &thread_info: m_threads_stepping_with_breakpoint)
+ {
+ Error error = RemoveBreakpoint (thread_info.second);
+ if (error.Fail())
+ if (log)
+ log->Printf("NativeProcessLinux::%s() pid = %" PRIu64 " remove stepping breakpoint: %s",
+ __FUNCTION__, thread_info.first, error.AsCString());
+ }
+ m_threads_stepping_with_breakpoint.clear();
+
+ // Notify the delegate about the stop
+ SetCurrentThreadID(m_pending_notification_tid);
+ SetState(StateType::eStateStopped, true);
+ m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
+}
+
+void
+NativeProcessLinux::ThreadWasCreated(NativeThreadLinux &thread)
+{
+ Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD);
+
+ if (log)
+ log->Printf("NativeProcessLinux::%s (tid: %" PRIu64 ")", __FUNCTION__, thread.GetID());
+
+ if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && StateIsRunningState(thread.GetState()))
+ {
+ // We will need to wait for this new thread to stop as well before firing the
+ // notification.
+ thread.RequestStop();
+ }
+}
+
+void
+NativeProcessLinux::SigchldHandler()
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ // Process all pending waitpid notifications.
+ while (true)
+ {
+ int status = -1;
+ ::pid_t wait_pid = waitpid(-1, &status, __WALL | __WNOTHREAD | WNOHANG);
+
+ if (wait_pid == 0)
+ break; // We are done.
+
+ if (wait_pid == -1)
+ {
+ if (errno == EINTR)
+ continue;
+
+ Error error(errno, eErrorTypePOSIX);
+ if (log)
+ log->Printf("NativeProcessLinux::%s waitpid (-1, &status, __WALL | __WNOTHREAD | WNOHANG) failed: %s",
+ __FUNCTION__, error.AsCString());
+ 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 = "(\?\?\?)";
+
+ if (log)
+ log->Printf("NativeProcessLinux::%s: waitpid (-1, &status, __WALL | __WNOTHREAD | WNOHANG)"
+ "=> pid = %" PRIi32 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i",
+ __FUNCTION__, wait_pid, status, status_cstr, signal, exit_status);
+
+ MonitorCallback (wait_pid, exited, signal, exit_status);
+ }
+}
+
+// Wrapper for ptrace to catch errors and log calls.
+// Note that ptrace sets errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*)
+Error
+NativeProcessLinux::PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size, long *result)
+{
+ Error error;
+ long int ret;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PTRACE));
+
+ PtraceDisplayBytes(req, data, data_size);
+
+ errno = 0;
+ if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
+ ret = ptrace(static_cast<__ptrace_request>(req), static_cast< ::pid_t>(pid), *(unsigned int *)addr, data);
+ else
+ ret = ptrace(static_cast<__ptrace_request>(req), static_cast< ::pid_t>(pid), addr, data);
+
+ if (ret == -1)
+ error.SetErrorToErrno();
+
+ if (result)
+ *result = ret;
+
+ if (log)
+ log->Printf("ptrace(%d, %" PRIu64 ", %p, %p, %zu)=%lX", req, pid, addr, data, data_size, ret);
+
+ PtraceDisplayBytes(req, data, data_size);
+
+ if (log && error.GetError() != 0)
+ {
+ const char* str;
+ switch (error.GetError())
+ {
+ case ESRCH: str = "ESRCH"; break;
+ case EINVAL: str = "EINVAL"; break;
+ case EBUSY: str = "EBUSY"; break;
+ case EPERM: str = "EPERM"; break;
+ default: str = error.AsCString();
+ }
+ log->Printf("ptrace() failed; errno=%d (%s)", error.GetError(), str);
+ }
+
+ return error;
+}
diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.h b/source/Plugins/Process/Linux/NativeProcessLinux.h
new file mode 100644
index 000000000000..7bac1dc8dbb7
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -0,0 +1,329 @@
+//===-- NativeProcessLinux.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_NativeProcessLinux_H_
+#define liblldb_NativeProcessLinux_H_
+
+// C++ Includes
+#include <unordered_set>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Debug.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "NativeThreadLinux.h"
+
+namespace lldb_private {
+ class Error;
+ class Module;
+ class Scalar;
+
+namespace process_linux {
+ /// @class NativeProcessLinux
+ /// @brief Manages communication with the inferior (debugee) process.
+ ///
+ /// Upon construction, this class prepares and launches an inferior process for
+ /// debugging.
+ ///
+ /// Changes in the inferior process state are broadcasted.
+ class NativeProcessLinux: public NativeProcessProtocol
+ {
+ friend Error
+ NativeProcessProtocol::Launch (ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate,
+ MainLoop &mainloop,
+ NativeProcessProtocolSP &process_sp);
+
+ friend Error
+ NativeProcessProtocol::Attach (lldb::pid_t pid,
+ NativeProcessProtocol::NativeDelegate &native_delegate,
+ MainLoop &mainloop,
+ NativeProcessProtocolSP &process_sp);
+
+ public:
+ // ---------------------------------------------------------------------
+ // NativeProcessProtocol Interface
+ // ---------------------------------------------------------------------
+ Error
+ Resume (const ResumeActionList &resume_actions) override;
+
+ Error
+ Halt () override;
+
+ Error
+ Detach () override;
+
+ Error
+ Signal (int signo) override;
+
+ Error
+ Interrupt () override;
+
+ Error
+ Kill () override;
+
+ Error
+ GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info) override;
+
+ Error
+ ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) override;
+
+ Error
+ ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) override;
+
+ Error
+ WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) override;
+
+ Error
+ AllocateMemory(size_t size, uint32_t permissions, lldb::addr_t &addr) override;
+
+ Error
+ DeallocateMemory (lldb::addr_t addr) override;
+
+ lldb::addr_t
+ GetSharedLibraryInfoAddress () override;
+
+ size_t
+ UpdateThreads () override;
+
+ bool
+ GetArchitecture (ArchSpec &arch) const override;
+
+ Error
+ SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) override;
+
+ void
+ DoStopIDBumped (uint32_t newBumpId) override;
+
+ Error
+ GetLoadedModuleFileSpec(const char* module_path, FileSpec& file_spec) override;
+
+ Error
+ GetFileLoadAddress(const llvm::StringRef& file_name, lldb::addr_t& load_addr) override;
+
+ NativeThreadLinuxSP
+ GetThreadByID(lldb::tid_t id);
+
+ // ---------------------------------------------------------------------
+ // Interface used by NativeRegisterContext-derived classes.
+ // ---------------------------------------------------------------------
+ static Error
+ PtraceWrapper(int req,
+ lldb::pid_t pid,
+ void *addr = nullptr,
+ void *data = nullptr,
+ size_t data_size = 0,
+ long *result = nullptr);
+
+ protected:
+ // ---------------------------------------------------------------------
+ // NativeProcessProtocol protected interface
+ // ---------------------------------------------------------------------
+ Error
+ GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) override;
+
+ private:
+
+ MainLoop::SignalHandleUP m_sigchld_handle;
+ ArchSpec m_arch;
+
+ LazyBool m_supports_mem_region;
+ std::vector<MemoryRegionInfo> m_mem_region_cache;
+ Mutex m_mem_region_cache_mutex;
+
+ lldb::tid_t m_pending_notification_tid;
+
+ // List of thread ids stepping with a breakpoint with the address of
+ // the relevan breakpoint
+ std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint;
+
+ /// @class LauchArgs
+ ///
+ /// @brief Simple structure to pass data to the thread responsible for
+ /// launching a child process.
+ struct LaunchArgs
+ {
+ LaunchArgs(Module *module,
+ char const **argv,
+ char const **envp,
+ const FileSpec &stdin_file_spec,
+ const FileSpec &stdout_file_spec,
+ const FileSpec &stderr_file_spec,
+ const FileSpec &working_dir,
+ const ProcessLaunchInfo &launch_info);
+
+ ~LaunchArgs();
+
+ Module *m_module; // The executable image to launch.
+ char const **m_argv; // Process arguments.
+ char const **m_envp; // Process environment.
+ const FileSpec m_stdin_file_spec; // Redirect stdin if not empty.
+ const FileSpec m_stdout_file_spec; // Redirect stdout if not empty.
+ const FileSpec m_stderr_file_spec; // Redirect stderr if not empty.
+ const FileSpec m_working_dir; // Working directory or empty.
+ const ProcessLaunchInfo &m_launch_info;
+ };
+
+ typedef std::function< ::pid_t(Error &)> InitialOperation;
+
+ // ---------------------------------------------------------------------
+ // Private Instance Methods
+ // ---------------------------------------------------------------------
+ NativeProcessLinux ();
+
+ /// Launches an inferior process ready for debugging. Forms the
+ /// implementation of Process::DoLaunch.
+ void
+ LaunchInferior (
+ MainLoop &mainloop,
+ Module *module,
+ char const *argv[],
+ char const *envp[],
+ const FileSpec &stdin_file_spec,
+ const FileSpec &stdout_file_spec,
+ const FileSpec &stderr_file_spec,
+ const FileSpec &working_dir,
+ const ProcessLaunchInfo &launch_info,
+ Error &error);
+
+ /// Attaches to an existing process. Forms the
+ /// implementation of Process::DoAttach
+ void
+ AttachToInferior (MainLoop &mainloop, lldb::pid_t pid, Error &error);
+
+ ::pid_t
+ Launch(LaunchArgs *args, Error &error);
+
+ ::pid_t
+ Attach(lldb::pid_t pid, Error &error);
+
+ static Error
+ SetDefaultPtraceOpts(const lldb::pid_t);
+
+ static bool
+ DupDescriptor(const FileSpec &file_spec, int fd, int flags);
+
+ static void *
+ MonitorThread(void *baton);
+
+ void
+ MonitorCallback(lldb::pid_t pid, bool exited, int signal, int status);
+
+ void
+ WaitForNewThread(::pid_t tid);
+
+ void
+ MonitorSIGTRAP(const siginfo_t &info, NativeThreadLinux &thread);
+
+ void
+ MonitorTrace(NativeThreadLinux &thread);
+
+ void
+ MonitorBreakpoint(NativeThreadLinux &thread);
+
+ void
+ MonitorWatchpoint(NativeThreadLinux &thread, uint32_t wp_index);
+
+ void
+ MonitorSignal(const siginfo_t &info, NativeThreadLinux &thread, bool exited);
+
+ bool
+ SupportHardwareSingleStepping() const;
+
+ Error
+ SetupSoftwareSingleStepping(NativeThreadLinux &thread);
+
+#if 0
+ static ::ProcessMessage::CrashReason
+ GetCrashReasonForSIGSEGV(const siginfo_t *info);
+
+ static ::ProcessMessage::CrashReason
+ GetCrashReasonForSIGILL(const siginfo_t *info);
+
+ static ::ProcessMessage::CrashReason
+ GetCrashReasonForSIGFPE(const siginfo_t *info);
+
+ static ::ProcessMessage::CrashReason
+ GetCrashReasonForSIGBUS(const siginfo_t *info);
+#endif
+
+ bool
+ HasThreadNoLock (lldb::tid_t thread_id);
+
+ bool
+ StopTrackingThread (lldb::tid_t thread_id);
+
+ NativeThreadLinuxSP
+ AddThread (lldb::tid_t thread_id);
+
+ Error
+ GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size);
+
+ Error
+ FixupBreakpointPCAsNeeded(NativeThreadLinux &thread);
+
+ /// Writes a siginfo_t structure corresponding to the given thread ID to the
+ /// memory region pointed to by @p siginfo.
+ Error
+ GetSignalInfo(lldb::tid_t tid, void *siginfo);
+
+ /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
+ /// corresponding to the given thread ID to the memory pointed to by @p
+ /// message.
+ Error
+ GetEventMessage(lldb::tid_t tid, unsigned long *message);
+
+ /// Resumes the given thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ Error
+ Resume(lldb::tid_t tid, uint32_t signo);
+
+ /// Single steps the given thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ Error
+ SingleStep(lldb::tid_t tid, uint32_t signo);
+
+ void
+ NotifyThreadDeath (lldb::tid_t tid);
+
+ Error
+ Detach(lldb::tid_t tid);
+
+
+ // This method is requests a stop on all threads which are still running. It sets up a
+ // deferred delegate notification, which will fire once threads report as stopped. The
+ // triggerring_tid will be set as the current thread (main stop reason).
+ void
+ StopRunningThreads(lldb::tid_t triggering_tid);
+
+ // Notify the delegate if all threads have stopped.
+ void SignalIfAllThreadsStopped();
+
+ // Resume the given thread, optionally passing it the given signal. The type of resume
+ // operation (continue, single-step) depends on the state parameter.
+ Error
+ ResumeThread(NativeThreadLinux &thread, lldb::StateType state, int signo);
+
+ void
+ ThreadWasCreated(NativeThreadLinux &thread);
+
+ void
+ SigchldHandler();
+ };
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeProcessLinux_H_
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp
new file mode 100644
index 000000000000..df0a008ff5f7
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp
@@ -0,0 +1,230 @@
+//===-- NativeRegisterContextLinux.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextLinux.h"
+
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+#include "lldb/Host/linux/Ptrace.h"
+
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_linux;
+
+NativeRegisterContextLinux::NativeRegisterContextLinux(NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *reg_info_interface_p) :
+ NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx, reg_info_interface_p)
+{}
+
+lldb::ByteOrder
+NativeRegisterContextLinux::GetByteOrder() const
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ return byte_order;
+
+ if (!process_sp->GetByteOrder (byte_order))
+ {
+ // FIXME log here
+ }
+
+ return byte_order;
+}
+
+Error
+NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index, RegisterValue &reg_value)
+{
+ const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ return Error("register %" PRIu32 " not found", reg_index);
+
+ return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, reg_info->byte_size, reg_value);
+}
+
+Error
+NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index, const RegisterValue &reg_value)
+{
+ uint32_t reg_to_write = reg_index;
+ RegisterValue value_to_write = reg_value;
+
+ // Check if this is a subregister of a full register.
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
+ if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
+ {
+ Error error;
+
+ RegisterValue full_value;
+ uint32_t full_reg = reg_info->invalidate_regs[0];
+ const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+ // Read the full register.
+ error = ReadRegister(full_reg_info, full_value);
+ if (error.Fail ())
+ return error;
+
+ lldb::ByteOrder byte_order = GetByteOrder();
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the full register.
+ const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
+ dst,
+ sizeof(dst),
+ byte_order,
+ error);
+ if (error.Success() && dest_size)
+ {
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the source data.
+ const uint32_t src_size = reg_value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
+ if (error.Success() && src_size && (src_size < dest_size))
+ {
+ // Copy the src bytes to the destination.
+ memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
+ // Set this full register as the value to write.
+ value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
+ value_to_write.SetType(full_reg_info);
+ reg_to_write = full_reg;
+ }
+ }
+ }
+
+ const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write);
+ assert (register_to_write_info_p && "register to write does not have valid RegisterInfo");
+ if (!register_to_write_info_p)
+ return Error("NativeRegisterContextLinux::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
+
+ return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value);
+}
+
+Error
+NativeRegisterContextLinux::ReadGPR()
+{
+ void* buf = GetGPRBuffer();
+ if (!buf)
+ return Error("GPR buffer is NULL");
+ size_t buf_size = GetGPRSize();
+
+ return DoReadGPR(buf, buf_size);
+}
+
+Error
+NativeRegisterContextLinux::WriteGPR()
+{
+ void* buf = GetGPRBuffer();
+ if (!buf)
+ return Error("GPR buffer is NULL");
+ size_t buf_size = GetGPRSize();
+
+ return DoWriteGPR(buf, buf_size);
+}
+
+Error
+NativeRegisterContextLinux::ReadFPR()
+{
+ void* buf = GetFPRBuffer();
+ if (!buf)
+ return Error("FPR buffer is NULL");
+ size_t buf_size = GetFPRSize();
+
+ return DoReadFPR(buf, buf_size);
+}
+
+Error
+NativeRegisterContextLinux::WriteFPR()
+{
+ void* buf = GetFPRBuffer();
+ if (!buf)
+ return Error("FPR buffer is NULL");
+ size_t buf_size = GetFPRSize();
+
+ return DoWriteFPR(buf, buf_size);
+}
+
+Error
+NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset)
+{
+ return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
+ static_cast<void *>(&regset), buf, buf_size);
+}
+
+Error
+NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset)
+{
+ return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
+ static_cast<void *>(&regset), buf, buf_size);
+}
+
+Error
+NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset,
+ const char* reg_name,
+ uint32_t size,
+ RegisterValue &value)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
+
+ long data;
+ Error error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), nullptr, 0, &data);
+
+ if (error.Success())
+ // First cast to an unsigned of the same size to avoid sign extension.
+ value.SetUInt64(static_cast<unsigned long>(data));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux::%s() reg %s: 0x%lx", __FUNCTION__, reg_name, data);
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux::DoWriteRegisterValue(uint32_t offset,
+ const char* reg_name,
+ const RegisterValue &value)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
+
+ void* buf = reinterpret_cast<void *>(value.GetAsUInt64());
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux::%s() reg %s: %p", __FUNCTION__, reg_name, buf);
+
+ return NativeProcessLinux::PtraceWrapper(
+ PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf);
+}
+
+Error
+NativeRegisterContextLinux::DoReadGPR(void *buf, size_t buf_size)
+{
+ return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), nullptr, buf, buf_size);
+}
+
+Error
+NativeRegisterContextLinux::DoWriteGPR(void *buf, size_t buf_size)
+{
+ return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), nullptr, buf, buf_size);
+}
+
+Error
+NativeRegisterContextLinux::DoReadFPR(void *buf, size_t buf_size)
+{
+ return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), nullptr, buf, buf_size);
+}
+
+Error
+NativeRegisterContextLinux::DoWriteFPR(void *buf, size_t buf_size)
+{
+ return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), nullptr, buf, buf_size);
+}
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux.h
new file mode 100644
index 000000000000..0b0b747984b4
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux.h
@@ -0,0 +1,107 @@
+//===-- NativeRegisterContextLinux.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_NativeRegisterContextLinux_h
+#define lldb_NativeRegisterContextLinux_h
+
+#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "Plugins/Process/Linux/NativeProcessLinux.h"
+
+namespace lldb_private {
+namespace process_linux {
+
+class NativeRegisterContextLinux : public NativeRegisterContextRegisterInfo
+{
+public:
+ NativeRegisterContextLinux(NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *reg_info_interface_p);
+
+ // This function is implemented in the NativeRegisterContextLinux_* subclasses to create a new
+ // instance of the host specific NativeRegisterContextLinux. The implementations can't collide
+ // as only one NativeRegisterContextLinux_* variant should be compiled into the final
+ // executable.
+ static NativeRegisterContextLinux*
+ CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx);
+
+protected:
+ lldb::ByteOrder
+ GetByteOrder() const;
+
+ virtual Error
+ ReadRegisterRaw(uint32_t reg_index, RegisterValue& reg_value);
+
+ virtual Error
+ WriteRegisterRaw(uint32_t reg_index, const RegisterValue& reg_value);
+
+ virtual Error
+ ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset);
+
+ virtual Error
+ WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset);
+
+ virtual Error
+ ReadGPR();
+
+ virtual Error
+ WriteGPR();
+
+ virtual Error
+ ReadFPR();
+
+ virtual Error
+ WriteFPR();
+
+ virtual void*
+ GetGPRBuffer() { return nullptr; }
+
+ virtual size_t
+ GetGPRSize() { return GetRegisterInfoInterface().GetGPRSize(); }
+
+ virtual void*
+ GetFPRBuffer() { return nullptr; }
+
+ virtual size_t
+ GetFPRSize() { return 0; }
+
+
+ // The Do*** functions are executed on the privileged thread and can perform ptrace
+ // operations directly.
+ virtual Error
+ DoReadRegisterValue(uint32_t offset,
+ const char* reg_name,
+ uint32_t size,
+ RegisterValue &value);
+
+ virtual Error
+ DoWriteRegisterValue(uint32_t offset,
+ const char* reg_name,
+ const RegisterValue &value);
+
+ virtual Error
+ DoReadGPR(void *buf, size_t buf_size);
+
+ virtual Error
+ DoWriteGPR(void *buf, size_t buf_size);
+
+ virtual Error
+ DoReadFPR(void *buf, size_t buf_size);
+
+ virtual Error
+ DoWriteFPR(void *buf, size_t buf_size);
+};
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextLinux_h
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
new file mode 100644
index 000000000000..31752fed5b42
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
@@ -0,0 +1,1017 @@
+//===-- NativeRegisterContextLinux_arm.cpp --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__arm__)
+
+#include "NativeRegisterContextLinux_arm.h"
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+
+#include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
+
+#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
+
+#ifndef PTRACE_GETVFPREGS
+ #define PTRACE_GETVFPREGS 27
+ #define PTRACE_SETVFPREGS 28
+#endif
+#ifndef PTRACE_GETHBPREGS
+ #define PTRACE_GETHBPREGS 29
+ #define PTRACE_SETHBPREGS 30
+#endif
+#if !defined(PTRACE_TYPE_ARG3)
+ #define PTRACE_TYPE_ARG3 void *
+#endif
+#if !defined(PTRACE_TYPE_ARG4)
+ #define PTRACE_TYPE_ARG4 void *
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_linux;
+
+// arm general purpose registers.
+static const uint32_t g_gpr_regnums_arm[] =
+{
+ gpr_r0_arm,
+ gpr_r1_arm,
+ gpr_r2_arm,
+ gpr_r3_arm,
+ gpr_r4_arm,
+ gpr_r5_arm,
+ gpr_r6_arm,
+ gpr_r7_arm,
+ gpr_r8_arm,
+ gpr_r9_arm,
+ gpr_r10_arm,
+ gpr_r11_arm,
+ gpr_r12_arm,
+ gpr_sp_arm,
+ gpr_lr_arm,
+ gpr_pc_arm,
+ gpr_cpsr_arm,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \
+ "g_gpr_regnums_arm has wrong number of register infos");
+
+// arm floating point registers.
+static const uint32_t g_fpu_regnums_arm[] =
+{
+ fpu_s0_arm,
+ fpu_s1_arm,
+ fpu_s2_arm,
+ fpu_s3_arm,
+ fpu_s4_arm,
+ fpu_s5_arm,
+ fpu_s6_arm,
+ fpu_s7_arm,
+ fpu_s8_arm,
+ fpu_s9_arm,
+ fpu_s10_arm,
+ fpu_s11_arm,
+ fpu_s12_arm,
+ fpu_s13_arm,
+ fpu_s14_arm,
+ fpu_s15_arm,
+ fpu_s16_arm,
+ fpu_s17_arm,
+ fpu_s18_arm,
+ fpu_s19_arm,
+ fpu_s20_arm,
+ fpu_s21_arm,
+ fpu_s22_arm,
+ fpu_s23_arm,
+ fpu_s24_arm,
+ fpu_s25_arm,
+ fpu_s26_arm,
+ fpu_s27_arm,
+ fpu_s28_arm,
+ fpu_s29_arm,
+ fpu_s30_arm,
+ fpu_s31_arm,
+ fpu_fpscr_arm,
+ fpu_d0_arm,
+ fpu_d1_arm,
+ fpu_d2_arm,
+ fpu_d3_arm,
+ fpu_d4_arm,
+ fpu_d5_arm,
+ fpu_d6_arm,
+ fpu_d7_arm,
+ fpu_d8_arm,
+ fpu_d9_arm,
+ fpu_d10_arm,
+ fpu_d11_arm,
+ fpu_d12_arm,
+ fpu_d13_arm,
+ fpu_d14_arm,
+ fpu_d15_arm,
+ fpu_d16_arm,
+ fpu_d17_arm,
+ fpu_d18_arm,
+ fpu_d19_arm,
+ fpu_d20_arm,
+ fpu_d21_arm,
+ fpu_d22_arm,
+ fpu_d23_arm,
+ fpu_d24_arm,
+ fpu_d25_arm,
+ fpu_d26_arm,
+ fpu_d27_arm,
+ fpu_d28_arm,
+ fpu_d29_arm,
+ fpu_d30_arm,
+ fpu_d31_arm,
+ fpu_q0_arm,
+ fpu_q1_arm,
+ fpu_q2_arm,
+ fpu_q3_arm,
+ fpu_q4_arm,
+ fpu_q5_arm,
+ fpu_q6_arm,
+ fpu_q7_arm,
+ fpu_q8_arm,
+ fpu_q9_arm,
+ fpu_q10_arm,
+ fpu_q11_arm,
+ fpu_q12_arm,
+ fpu_q13_arm,
+ fpu_q14_arm,
+ fpu_q15_arm,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \
+ "g_fpu_regnums_arm has wrong number of register infos");
+
+namespace {
+ // Number of register sets provided by this context.
+ enum
+ {
+ k_num_register_sets = 2
+ };
+}
+
+// Register sets for arm.
+static const RegisterSet
+g_reg_sets_arm[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm }
+};
+
+NativeRegisterContextLinux*
+NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx)
+{
+ return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx);
+}
+
+NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx) :
+ NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm(target_arch))
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ m_reg_info.num_registers = k_num_registers_arm;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_arm;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_arm;
+ m_reg_info.last_gpr = k_last_gpr_arm;
+ m_reg_info.first_fpr = k_first_fpr_arm;
+ m_reg_info.last_fpr = k_last_fpr_arm;
+ m_reg_info.first_fpr_v = fpu_s0_arm;
+ m_reg_info.last_fpr_v = fpu_s31_arm;
+ m_reg_info.gpr_flags = gpr_cpsr_arm;
+ break;
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+
+ ::memset(&m_fpr, 0, sizeof (m_fpr));
+ ::memset(&m_gpr_arm, 0, sizeof (m_gpr_arm));
+ ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs));
+
+ // 16 is just a maximum value, query hardware for actual watchpoint count
+ m_max_hwp_supported = 16;
+ m_max_hbp_supported = 16;
+ m_refresh_hwdebug_info = true;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm::GetRegisterSetCount () const
+{
+ return k_num_register_sets;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm::GetUserRegisterCount() const
+{
+ uint32_t count = 0;
+ for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
+ count += g_reg_sets_arm[set_index].num_registers;
+ return count;
+}
+
+const RegisterSet *
+NativeRegisterContextLinux_arm::GetRegisterSet (uint32_t set_index) const
+{
+ if (set_index < k_num_register_sets)
+ return &g_reg_sets_arm[set_index];
+
+ return nullptr;
+}
+
+Error
+NativeRegisterContextLinux_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ Error error;
+
+ if (!reg_info)
+ {
+ error.SetErrorString ("reg_info NULL");
+ return error;
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (IsFPR(reg))
+ {
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+ }
+ else
+ {
+ uint32_t full_reg = reg;
+ bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
+
+ if (is_subreg)
+ {
+ // Read the full aligned 64-bit register.
+ full_reg = reg_info->invalidate_regs[0];
+ }
+
+ error = ReadRegisterRaw(full_reg, reg_value);
+
+ if (error.Success ())
+ {
+ // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
+ if (is_subreg && (reg_info->byte_offset & 0x1))
+ reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
+
+ // If our return byte size was greater than the return value reg size, then
+ // use the type specified by reg_info rather than the uint64_t default
+ if (reg_value.GetByteSize() > reg_info->byte_size)
+ reg_value.SetType(reg_info);
+ }
+ return error;
+ }
+
+ // Get pointer to m_fpr variable and set the data from it.
+ uint32_t fpr_offset = CalculateFprOffset(reg_info);
+ assert (fpr_offset < sizeof m_fpr);
+ uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
+ switch (reg_info->byte_size)
+ {
+ case 2:
+ reg_value.SetUInt16(*(uint16_t *)src);
+ break;
+ case 4:
+ reg_value.SetUInt32(*(uint32_t *)src);
+ break;
+ case 8:
+ reg_value.SetUInt64(*(uint64_t *)src);
+ break;
+ case 16:
+ reg_value.SetBytes(src, 16, GetByteOrder());
+ break;
+ default:
+ assert(false && "Unhandled data size.");
+ error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
+ break;
+ }
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_arm::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ if (!reg_info)
+ return Error ("reg_info NULL");
+
+ const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg_index == LLDB_INVALID_REGNUM)
+ return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
+
+ if (IsGPR(reg_index))
+ return WriteRegisterRaw(reg_index, reg_value);
+
+ if (IsFPR(reg_index))
+ {
+ // Get pointer to m_fpr variable and set the data to it.
+ uint32_t fpr_offset = CalculateFprOffset(reg_info);
+ assert (fpr_offset < sizeof m_fpr);
+ uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
+ switch (reg_info->byte_size)
+ {
+ case 2:
+ *(uint16_t *)dst = reg_value.GetAsUInt16();
+ break;
+ case 4:
+ *(uint32_t *)dst = reg_value.GetAsUInt32();
+ break;
+ case 8:
+ *(uint64_t *)dst = reg_value.GetAsUInt64();
+ break;
+ default:
+ assert(false && "Unhandled data size.");
+ return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
+ }
+
+ Error error = WriteFPR();
+ if (error.Fail())
+ return error;
+
+ return Error ();
+ }
+
+ return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
+}
+
+Error
+NativeRegisterContextLinux_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ Error error;
+
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (!data_sp)
+ return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, (uint64_t)REG_CONTEXT_SIZE);
+
+ error = ReadGPR();
+ if (error.Fail())
+ return error;
+
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+
+ uint8_t *dst = data_sp->GetBytes ();
+ if (dst == nullptr)
+ {
+ error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", (uint64_t)REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ ::memcpy (dst, &m_gpr_arm, GetGPRSize());
+ dst += GetGPRSize();
+ ::memcpy (dst, &m_fpr, sizeof(m_fpr));
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ Error error;
+
+ if (!data_sp)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize ());
+ return error;
+ }
+
+
+ uint8_t *src = data_sp->GetBytes ();
+ if (src == nullptr)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
+ return error;
+ }
+ ::memcpy (&m_gpr_arm, src, GetRegisterInfoInterface ().GetGPRSize ());
+
+ error = WriteGPR();
+ if (error.Fail())
+ return error;
+
+ src += GetRegisterInfoInterface ().GetGPRSize ();
+ ::memcpy (&m_fpr, src, sizeof(m_fpr));
+
+ error = WriteFPR();
+ if (error.Fail())
+ return error;
+
+ return error;
+}
+
+bool
+NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const
+{
+ return reg <= m_reg_info.last_gpr; // GPR's come first.
+}
+
+bool
+NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const
+{
+ return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
+}
+
+uint32_t
+NativeRegisterContextLinux_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return LLDB_INVALID_INDEX32;
+
+ uint32_t control_value = 0, bp_index = 0;
+
+ // Check if size has a valid hardware breakpoint length.
+ // Thumb instructions are 2-bytes but we have no way here to determine
+ // if target address is a thumb or arm instruction.
+ // TODO: Add support for setting thumb mode hardware breakpoints
+ if (size != 4 && size != 2)
+ return LLDB_INVALID_INDEX32;
+
+ // Setup control value
+ // Make the byte_mask into a valid Byte Address Select mask
+ control_value = 0xfu << 5;
+
+ // Enable this breakpoint and make it stop in privileged or user mode;
+ control_value |= 7;
+
+ // Make sure bits 1:0 are clear in our address
+ // This should be different once we support thumb here.
+ addr &= ~((lldb::addr_t)3);
+
+ // Iterate over stored hardware breakpoints
+ // Find a free bp_index or update reference count if duplicate.
+ bp_index = LLDB_INVALID_INDEX32;
+
+ for (uint32_t i = 0; i < m_max_hbp_supported; i++)
+ {
+ if ((m_hbr_regs[i].control & 1) == 0)
+ {
+ bp_index = i; // Mark last free slot
+ }
+ else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
+ {
+ bp_index = i; // Mark duplicate index
+ break; // Stop searching here
+ }
+ }
+
+ if (bp_index == LLDB_INVALID_INDEX32)
+ return LLDB_INVALID_INDEX32;
+
+ // Add new or update existing breakpoint
+ if ((m_hbr_regs[bp_index].control & 1) == 0)
+ {
+ m_hbr_regs[bp_index].address = addr;
+ m_hbr_regs[bp_index].control = control_value;
+ m_hbr_regs[bp_index].refcount = 1;
+
+ // PTRACE call to set corresponding hardware breakpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
+
+ if (error.Fail())
+ {
+ m_hbr_regs[bp_index].address = 0;
+ m_hbr_regs[bp_index].control &= ~1;
+ m_hbr_regs[bp_index].refcount = 0;
+
+ return LLDB_INVALID_INDEX32;
+ }
+ }
+ else
+ m_hbr_regs[bp_index].refcount++;
+
+ return bp_index;
+}
+
+bool
+NativeRegisterContextLinux_arm::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return false;
+
+ if (hw_idx >= m_max_hbp_supported)
+ return false;
+
+ // Update reference count if multiple references.
+ if (m_hbr_regs[hw_idx].refcount > 1)
+ {
+ m_hbr_regs[hw_idx].refcount--;
+ return true;
+ }
+ else if (m_hbr_regs[hw_idx].refcount == 1)
+ {
+ // Create a backup we can revert to in case of failure.
+ lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
+ uint32_t tempControl = m_hbr_regs[hw_idx].control;
+ uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount;
+
+ m_hbr_regs[hw_idx].control &= ~1;
+ m_hbr_regs[hw_idx].address = 0;
+ m_hbr_regs[hw_idx].refcount = 0;
+
+ // PTRACE call to clear corresponding hardware breakpoint register.
+ WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
+
+ if (error.Fail())
+ {
+ m_hbr_regs[hw_idx].control = tempControl;
+ m_hbr_regs[hw_idx].address = tempAddr;
+ m_hbr_regs[hw_idx].refcount = tempRefCount;
+
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return LLDB_INVALID_INDEX32;
+
+ return m_max_hwp_supported;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return LLDB_INVALID_INDEX32;
+
+ uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
+
+ // Check if we are setting watchpoint other than read/write/access
+ // Also update watchpoint flag to match Arm write-read bit configuration.
+ switch (watch_flags)
+ {
+ case 1:
+ watch_flags = 2;
+ break;
+ case 2:
+ watch_flags = 1;
+ break;
+ case 3:
+ break;
+ default:
+ return LLDB_INVALID_INDEX32;
+ }
+
+ // Can't watch zero bytes
+ // Can't watch more than 4 bytes per WVR/WCR pair
+
+ if (size == 0 || size > 4)
+ return LLDB_INVALID_INDEX32;
+
+ // We can only watch up to four bytes that follow a 4 byte aligned address
+ // per watchpoint register pair, so make sure we can properly encode this.
+ addr_word_offset = addr % 4;
+ byte_mask = ((1u << size) - 1u) << addr_word_offset;
+
+ // Check if we need multiple watchpoint register
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Setup control value
+ // Make the byte_mask into a valid Byte Address Select mask
+ control_value = byte_mask << 5;
+
+ //Turn on appropriate watchpoint flags read or write
+ control_value |= (watch_flags << 3);
+
+ // Enable this watchpoint and make it stop in privileged or user mode;
+ control_value |= 7;
+
+ // Make sure bits 1:0 are clear in our address
+ addr &= ~((lldb::addr_t)3);
+
+ // Iterate over stored watchpoints
+ // Find a free wp_index or update reference count if duplicate.
+ wp_index = LLDB_INVALID_INDEX32;
+ for (uint32_t i = 0; i < m_max_hwp_supported; i++)
+ {
+ if ((m_hwp_regs[i].control & 1) == 0)
+ {
+ wp_index = i; // Mark last free slot
+ }
+ else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
+ {
+ wp_index = i; // Mark duplicate index
+ break; // Stop searching here
+ }
+ }
+
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return LLDB_INVALID_INDEX32;
+
+ // Add new or update existing watchpoint
+ if ((m_hwp_regs[wp_index].control & 1) == 0)
+ {
+ // Update watchpoint in local cache
+ m_hwp_regs[wp_index].address = addr;
+ m_hwp_regs[wp_index].control = control_value;
+ m_hwp_regs[wp_index].refcount = 1;
+
+ // PTRACE call to set corresponding watchpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
+
+ if (error.Fail())
+ {
+ m_hwp_regs[wp_index].address = 0;
+ m_hwp_regs[wp_index].control &= ~1;
+ m_hwp_regs[wp_index].refcount = 0;
+
+ return LLDB_INVALID_INDEX32;
+ }
+ }
+ else
+ m_hwp_regs[wp_index].refcount++;
+
+ return wp_index;
+}
+
+bool
+NativeRegisterContextLinux_arm::ClearHardwareWatchpoint (uint32_t wp_index)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return false;
+
+ if (wp_index >= m_max_hwp_supported)
+ return false;
+
+ // Update reference count if multiple references.
+ if (m_hwp_regs[wp_index].refcount > 1)
+ {
+ m_hwp_regs[wp_index].refcount--;
+ return true;
+ }
+ else if (m_hwp_regs[wp_index].refcount == 1)
+ {
+ // Create a backup we can revert to in case of failure.
+ lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
+ uint32_t tempControl = m_hwp_regs[wp_index].control;
+ uint32_t tempRefCount = m_hwp_regs[wp_index].refcount;
+
+ // Update watchpoint in local cache
+ m_hwp_regs[wp_index].control &= ~1;
+ m_hwp_regs[wp_index].address = 0;
+ m_hwp_regs[wp_index].refcount = 0;
+
+ // Ptrace call to update hardware debug registers
+ error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
+
+ if (error.Fail())
+ {
+ m_hwp_regs[wp_index].control = tempControl;
+ m_hwp_regs[wp_index].address = tempAddr;
+ m_hwp_regs[wp_index].refcount = tempRefCount;
+
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+Error
+NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return error;
+
+ lldb::addr_t tempAddr = 0;
+ uint32_t tempControl = 0, tempRefCount = 0;
+
+ for (uint32_t i = 0; i < m_max_hwp_supported; i++)
+ {
+ if (m_hwp_regs[i].control & 0x01)
+ {
+ // Create a backup we can revert to in case of failure.
+ tempAddr = m_hwp_regs[i].address;
+ tempControl = m_hwp_regs[i].control;
+ tempRefCount = m_hwp_regs[i].refcount;
+
+ // Clear watchpoints in local cache
+ m_hwp_regs[i].control &= ~1;
+ m_hwp_regs[i].address = 0;
+ m_hwp_regs[i].refcount = 0;
+
+ // Ptrace call to update hardware debug registers
+ error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
+
+ if (error.Fail())
+ {
+ m_hwp_regs[i].control = tempControl;
+ m_hwp_regs[i].address = tempAddr;
+ m_hwp_regs[i].refcount = tempRefCount;
+
+ return error;
+ }
+ }
+ }
+
+ return Error();
+}
+
+uint32_t
+NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f)
+ {
+ case 0x01:
+ return 1;
+ case 0x03:
+ return 2;
+ case 0x07:
+ return 3;
+ case 0x0f:
+ return 4;
+ default:
+ return 0;
+ }
+}
+bool
+NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
+ return true;
+ else
+ return false;
+}
+
+Error
+NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ uint32_t watch_size;
+ lldb::addr_t watch_addr;
+
+ for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
+ {
+ watch_size = GetWatchpointSize (wp_index);
+ watch_addr = m_hwp_regs[wp_index].address;
+
+ if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
+ && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
+ {
+ return Error();
+ }
+ }
+
+ wp_index = LLDB_INVALID_INDEX32;
+ return Error();
+}
+
+lldb::addr_t
+NativeRegisterContextLinux_arm::GetWatchpointAddress (uint32_t wp_index)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
+
+ if (wp_index >= m_max_hwp_supported)
+ return LLDB_INVALID_ADDRESS;
+
+ if (WatchpointIsEnabled(wp_index))
+ return m_hwp_regs[wp_index].address;
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+Error
+NativeRegisterContextLinux_arm::ReadHardwareDebugInfo()
+{
+ Error error;
+
+ if (!m_refresh_hwdebug_info)
+ {
+ return Error();
+ }
+
+ unsigned int cap_val;
+
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), nullptr, &cap_val, sizeof(unsigned int));
+
+ if (error.Fail())
+ return error;
+
+ m_max_hwp_supported = (cap_val >> 8) & 0xff;
+ m_max_hbp_supported = cap_val & 0xff;
+ m_refresh_hwdebug_info = false;
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, int hwb_index)
+{
+ Error error;
+
+ lldb::addr_t *addr_buf;
+ uint32_t *ctrl_buf;
+
+ if (hwbType == eDREGTypeWATCH)
+ {
+ addr_buf = &m_hwp_regs[hwb_index].address;
+ ctrl_buf = &m_hwp_regs[hwb_index].control;
+
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
+ m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 1),
+ addr_buf, sizeof(unsigned int));
+
+ if (error.Fail())
+ return error;
+
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
+ m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 2),
+ ctrl_buf, sizeof(unsigned int));
+ }
+ else
+ {
+ addr_buf = &m_hwp_regs[hwb_index].address;
+ ctrl_buf = &m_hwp_regs[hwb_index].control;
+
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
+ m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 1),
+ addr_buf, sizeof(unsigned int));
+
+ if (error.Fail())
+ return error;
+
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
+ m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 2),
+ ctrl_buf, sizeof(unsigned int));
+
+ }
+
+ return error;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm::CalculateFprOffset(const RegisterInfo* reg_info) const
+{
+ return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
+}
+
+Error
+NativeRegisterContextLinux_arm::DoWriteRegisterValue(uint32_t offset,
+ const char* reg_name,
+ const RegisterValue &value)
+{
+ // PTRACE_POKEUSER don't work in the aarch64 liux kernel used on android devices (always return
+ // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR register set, modify
+ // the requested register and write it back. This approach is about 4 times slower but the
+ // performance overhead is negligible in comparision to processing time in lldb-server.
+ assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
+ if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
+ return Error("Register isn't fit into the size of the GPR area");
+
+ Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm));
+ if (error.Fail())
+ return error;
+
+ uint32_t reg_value = value.GetAsUInt32();
+ // As precaution for an undefined behavior encountered while setting PC we
+ // will clear thumb bit of new PC if we are already in thumb mode; that is
+ // CPSR thumb mode bit is set.
+ if (offset / sizeof(uint32_t) == gpr_pc_arm)
+ {
+ // Check if we are already in thumb mode and
+ // thumb bit of current PC is read out to be zero and
+ // thumb bit of next PC is read out to be one.
+ if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) &&
+ !(m_gpr_arm[gpr_pc_arm] & 0x01) &&
+ (value.GetAsUInt32() & 0x01))
+ {
+ reg_value &= (~1ull);
+ }
+ }
+
+ m_gpr_arm[offset / sizeof(uint32_t)] = reg_value;
+ return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm));
+}
+
+Error
+NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size)
+{
+ return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS,
+ m_thread.GetID(),
+ nullptr,
+ buf,
+ buf_size);
+}
+
+Error
+NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size)
+{
+ return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS,
+ m_thread.GetID(),
+ nullptr,
+ buf,
+ buf_size);
+}
+
+#endif // defined(__arm__)
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
new file mode 100644
index 000000000000..611b36ad4db1
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
@@ -0,0 +1,185 @@
+//===-- NativeRegisterContextLinux_arm.h ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__arm__) // arm register context only needed on arm devices
+
+#ifndef lldb_NativeRegisterContextLinux_arm_h
+#define lldb_NativeRegisterContextLinux_arm_h
+
+#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
+#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
+
+namespace lldb_private {
+namespace process_linux {
+
+ class NativeProcessLinux;
+
+ class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux
+ {
+ public:
+ NativeRegisterContextLinux_arm (const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx);
+
+ uint32_t
+ GetRegisterSetCount () const override;
+
+ const RegisterSet *
+ GetRegisterSet (uint32_t set_index) const override;
+
+ uint32_t
+ GetUserRegisterCount() const override;
+
+ Error
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value) override;
+
+ Error
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
+
+ Error
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override;
+
+ Error
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
+
+ //------------------------------------------------------------------
+ // Hardware breakpoints/watchpoint mangement functions
+ //------------------------------------------------------------------
+
+ uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size) override;
+
+ bool
+ ClearHardwareBreakpoint (uint32_t hw_idx) override;
+
+ uint32_t
+ NumSupportedHardwareWatchpoints () override;
+
+ uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) override;
+
+ bool
+ ClearHardwareWatchpoint (uint32_t hw_index) override;
+
+ Error
+ ClearAllHardwareWatchpoints () override;
+
+ Error
+ GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override;
+
+ lldb::addr_t
+ GetWatchpointAddress (uint32_t wp_index) override;
+
+ uint32_t
+ GetWatchpointSize(uint32_t wp_index);
+
+ bool
+ WatchpointIsEnabled(uint32_t wp_index);
+
+ // Debug register type select
+ enum DREGType
+ {
+ eDREGTypeWATCH = 0,
+ eDREGTypeBREAK
+ };
+
+ protected:
+ Error
+ DoWriteRegisterValue(uint32_t offset,
+ const char* reg_name,
+ const RegisterValue &value) override;
+
+ Error
+ DoReadFPR(void *buf, size_t buf_size) override;
+
+ Error
+ DoWriteFPR(void *buf, size_t buf_size) override;
+
+ void*
+ GetGPRBuffer() override { return &m_gpr_arm; }
+
+ void*
+ GetFPRBuffer() override { return &m_fpr; }
+
+ size_t
+ GetFPRSize() override { return sizeof(m_fpr); }
+
+ private:
+ struct RegInfo
+ {
+ uint32_t num_registers;
+ uint32_t num_gpr_registers;
+ uint32_t num_fpr_registers;
+
+ uint32_t last_gpr;
+ uint32_t first_fpr;
+ uint32_t last_fpr;
+
+ uint32_t first_fpr_v;
+ uint32_t last_fpr_v;
+
+ uint32_t gpr_flags;
+ };
+
+ struct QReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ union {
+ uint32_t s[32];
+ uint64_t d[32];
+ QReg q[16]; // the 128-bit NEON registers
+ } floats;
+ uint32_t fpscr;
+ };
+
+ uint32_t m_gpr_arm[k_num_gpr_registers_arm];
+ RegInfo m_reg_info;
+ FPU m_fpr;
+
+ // Debug register info for hardware breakpoints and watchpoints management.
+ struct DREG
+ {
+ lldb::addr_t address; // Breakpoint/watchpoint address value.
+ uint32_t control; // Breakpoint/watchpoint control value.
+ uint32_t refcount; // Serves as enable/disable and refernce counter.
+ };
+
+ struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints
+ struct DREG m_hwp_regs[16]; // Arm native linux hardware watchpoints
+
+ uint32_t m_max_hwp_supported;
+ uint32_t m_max_hbp_supported;
+ bool m_refresh_hwdebug_info;
+
+ bool
+ IsGPR(unsigned reg) const;
+
+ bool
+ IsFPR(unsigned reg) const;
+
+ Error
+ ReadHardwareDebugInfo();
+
+ Error
+ WriteHardwareDebugRegs(int hwbType, int hwb_index);
+
+ uint32_t
+ CalculateFprOffset(const RegisterInfo* reg_info) const;
+ };
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextLinux_arm_h
+
+#endif // defined(__arm__)
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
new file mode 100644
index 000000000000..e4d26fc640f3
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -0,0 +1,1042 @@
+//===-- NativeRegisterContextLinux_arm64.cpp --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__arm64__) || defined (__aarch64__)
+
+#include "NativeRegisterContextLinux_arm64.h"
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+
+#include "Plugins/Process/Linux/NativeProcessLinux.h"
+#include "Plugins/Process/Linux/Procfs.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
+
+// System includes - They have to be included after framework includes because they define some
+// macros which collide with variable names in other modules
+#include <sys/socket.h>
+// NT_PRSTATUS and NT_FPREGSET definition
+#include <elf.h>
+
+#define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_linux;
+
+// ARM64 general purpose registers.
+static const uint32_t g_gpr_regnums_arm64[] =
+{
+ gpr_x0_arm64,
+ gpr_x1_arm64,
+ gpr_x2_arm64,
+ gpr_x3_arm64,
+ gpr_x4_arm64,
+ gpr_x5_arm64,
+ gpr_x6_arm64,
+ gpr_x7_arm64,
+ gpr_x8_arm64,
+ gpr_x9_arm64,
+ gpr_x10_arm64,
+ gpr_x11_arm64,
+ gpr_x12_arm64,
+ gpr_x13_arm64,
+ gpr_x14_arm64,
+ gpr_x15_arm64,
+ gpr_x16_arm64,
+ gpr_x17_arm64,
+ gpr_x18_arm64,
+ gpr_x19_arm64,
+ gpr_x20_arm64,
+ gpr_x21_arm64,
+ gpr_x22_arm64,
+ gpr_x23_arm64,
+ gpr_x24_arm64,
+ gpr_x25_arm64,
+ gpr_x26_arm64,
+ gpr_x27_arm64,
+ gpr_x28_arm64,
+ gpr_fp_arm64,
+ gpr_lr_arm64,
+ gpr_sp_arm64,
+ gpr_pc_arm64,
+ gpr_cpsr_arm64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \
+ "g_gpr_regnums_arm64 has wrong number of register infos");
+
+// ARM64 floating point registers.
+static const uint32_t g_fpu_regnums_arm64[] =
+{
+ fpu_v0_arm64,
+ fpu_v1_arm64,
+ fpu_v2_arm64,
+ fpu_v3_arm64,
+ fpu_v4_arm64,
+ fpu_v5_arm64,
+ fpu_v6_arm64,
+ fpu_v7_arm64,
+ fpu_v8_arm64,
+ fpu_v9_arm64,
+ fpu_v10_arm64,
+ fpu_v11_arm64,
+ fpu_v12_arm64,
+ fpu_v13_arm64,
+ fpu_v14_arm64,
+ fpu_v15_arm64,
+ fpu_v16_arm64,
+ fpu_v17_arm64,
+ fpu_v18_arm64,
+ fpu_v19_arm64,
+ fpu_v20_arm64,
+ fpu_v21_arm64,
+ fpu_v22_arm64,
+ fpu_v23_arm64,
+ fpu_v24_arm64,
+ fpu_v25_arm64,
+ fpu_v26_arm64,
+ fpu_v27_arm64,
+ fpu_v28_arm64,
+ fpu_v29_arm64,
+ fpu_v30_arm64,
+ fpu_v31_arm64,
+ fpu_fpsr_arm64,
+ fpu_fpcr_arm64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \
+ "g_fpu_regnums_arm64 has wrong number of register infos");
+
+namespace {
+ // Number of register sets provided by this context.
+ enum
+ {
+ k_num_register_sets = 2
+ };
+}
+
+// Register sets for ARM64.
+static const RegisterSet
+g_reg_sets_arm64[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 }
+};
+
+NativeRegisterContextLinux*
+NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx)
+{
+ return new NativeRegisterContextLinux_arm64(target_arch, native_thread, concrete_frame_idx);
+}
+
+NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx) :
+ NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm64(target_arch))
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ m_reg_info.num_registers = k_num_registers_arm64;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64;
+ m_reg_info.last_gpr = k_last_gpr_arm64;
+ m_reg_info.first_fpr = k_first_fpr_arm64;
+ m_reg_info.last_fpr = k_last_fpr_arm64;
+ m_reg_info.first_fpr_v = fpu_v0_arm64;
+ m_reg_info.last_fpr_v = fpu_v31_arm64;
+ m_reg_info.gpr_flags = gpr_cpsr_arm64;
+ break;
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+
+ ::memset(&m_fpr, 0, sizeof (m_fpr));
+ ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64));
+ ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs));
+
+ // 16 is just a maximum value, query hardware for actual watchpoint count
+ m_max_hwp_supported = 16;
+ m_max_hbp_supported = 16;
+ m_refresh_hwdebug_info = true;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm64::GetRegisterSetCount () const
+{
+ return k_num_register_sets;
+}
+
+const RegisterSet *
+NativeRegisterContextLinux_arm64::GetRegisterSet (uint32_t set_index) const
+{
+ if (set_index < k_num_register_sets)
+ return &g_reg_sets_arm64[set_index];
+
+ return nullptr;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm64::GetUserRegisterCount() const
+{
+ uint32_t count = 0;
+ for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
+ count += g_reg_sets_arm64[set_index].num_registers;
+ return count;
+}
+
+Error
+NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ Error error;
+
+ if (!reg_info)
+ {
+ error.SetErrorString ("reg_info NULL");
+ return error;
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (IsFPR(reg))
+ {
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+ }
+ else
+ {
+ uint32_t full_reg = reg;
+ bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
+
+ if (is_subreg)
+ {
+ // Read the full aligned 64-bit register.
+ full_reg = reg_info->invalidate_regs[0];
+ }
+
+ error = ReadRegisterRaw(full_reg, reg_value);
+
+ if (error.Success ())
+ {
+ // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
+ if (is_subreg && (reg_info->byte_offset & 0x1))
+ reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
+
+ // If our return byte size was greater than the return value reg size, then
+ // use the type specified by reg_info rather than the uint64_t default
+ if (reg_value.GetByteSize() > reg_info->byte_size)
+ reg_value.SetType(reg_info);
+ }
+ return error;
+ }
+
+ // Get pointer to m_fpr variable and set the data from it.
+ uint32_t fpr_offset = CalculateFprOffset(reg_info);
+ assert (fpr_offset < sizeof m_fpr);
+ uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
+ reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, eByteOrderLittle, error);
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ if (!reg_info)
+ return Error ("reg_info NULL");
+
+ const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg_index == LLDB_INVALID_REGNUM)
+ return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
+
+ if (IsGPR(reg_index))
+ return WriteRegisterRaw(reg_index, reg_value);
+
+ if (IsFPR(reg_index))
+ {
+ // Get pointer to m_fpr variable and set the data to it.
+ uint32_t fpr_offset = CalculateFprOffset(reg_info);
+ assert (fpr_offset < sizeof m_fpr);
+ uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
+ switch (reg_info->byte_size)
+ {
+ case 2:
+ *(uint16_t *)dst = reg_value.GetAsUInt16();
+ break;
+ case 4:
+ *(uint32_t *)dst = reg_value.GetAsUInt32();
+ break;
+ case 8:
+ *(uint64_t *)dst = reg_value.GetAsUInt64();
+ break;
+ default:
+ assert(false && "Unhandled data size.");
+ return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
+ }
+
+ Error error = WriteFPR();
+ if (error.Fail())
+ return error;
+
+ return Error ();
+ }
+
+ return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
+}
+
+Error
+NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ Error error;
+
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (!data_sp)
+ return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
+
+ error = ReadGPR();
+ if (error.Fail())
+ return error;
+
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+
+ uint8_t *dst = data_sp->GetBytes ();
+ if (dst == nullptr)
+ {
+ error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
+ dst += GetGPRSize();
+ ::memcpy (dst, &m_fpr, sizeof(m_fpr));
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ Error error;
+
+ if (!data_sp)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
+ return error;
+ }
+
+
+ uint8_t *src = data_sp->GetBytes ();
+ if (src == nullptr)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
+ return error;
+ }
+ ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ());
+
+ error = WriteGPR();
+ if (error.Fail())
+ return error;
+
+ src += GetRegisterInfoInterface ().GetGPRSize ();
+ ::memcpy (&m_fpr, src, sizeof(m_fpr));
+
+ error = WriteFPR();
+ if (error.Fail())
+ return error;
+
+ return error;
+}
+
+bool
+NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const
+{
+ return reg <= m_reg_info.last_gpr; // GPR's come first.
+}
+
+bool
+NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const
+{
+ return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
+}
+
+uint32_t
+NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return LLDB_INVALID_INDEX32;
+
+ uint32_t control_value = 0, bp_index = 0;
+
+ // Check if size has a valid hardware breakpoint length.
+ if (size != 4)
+ return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware breakpoint
+
+ // Check 4-byte alignment for hardware breakpoint target address.
+ if (addr & 0x03)
+ return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
+
+ // Setup control value
+ control_value = 0;
+ control_value |= ((1 << size) - 1) << 5;
+ control_value |= (2 << 1) | 1;
+
+ // Iterate over stored hardware breakpoints
+ // Find a free bp_index or update reference count if duplicate.
+ bp_index = LLDB_INVALID_INDEX32;
+ for (uint32_t i = 0; i < m_max_hbp_supported; i++)
+ {
+ if ((m_hbr_regs[i].control & 1) == 0)
+ {
+ bp_index = i; // Mark last free slot
+ }
+ else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
+ {
+ bp_index = i; // Mark duplicate index
+ break; // Stop searching here
+ }
+ }
+
+ if (bp_index == LLDB_INVALID_INDEX32)
+ return LLDB_INVALID_INDEX32;
+
+ // Add new or update existing breakpoint
+ if ((m_hbr_regs[bp_index].control & 1) == 0)
+ {
+ m_hbr_regs[bp_index].address = addr;
+ m_hbr_regs[bp_index].control = control_value;
+ m_hbr_regs[bp_index].refcount = 1;
+
+ // PTRACE call to set corresponding hardware breakpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+ if (error.Fail())
+ {
+ m_hbr_regs[bp_index].address = 0;
+ m_hbr_regs[bp_index].control &= ~1;
+ m_hbr_regs[bp_index].refcount = 0;
+
+ return LLDB_INVALID_INDEX32;
+ }
+ }
+ else
+ m_hbr_regs[bp_index].refcount++;
+
+ return bp_index;
+}
+
+bool
+NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return false;
+
+ if (hw_idx >= m_max_hbp_supported)
+ return false;
+
+ // Update reference count if multiple references.
+ if (m_hbr_regs[hw_idx].refcount > 1)
+ {
+ m_hbr_regs[hw_idx].refcount--;
+ return true;
+ }
+ else if (m_hbr_regs[hw_idx].refcount == 1)
+ {
+ // Create a backup we can revert to in case of failure.
+ lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
+ uint32_t tempControl = m_hbr_regs[hw_idx].control;
+ uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount;
+
+ m_hbr_regs[hw_idx].control &= ~1;
+ m_hbr_regs[hw_idx].address = 0;
+ m_hbr_regs[hw_idx].refcount = 0;
+
+ // PTRACE call to clear corresponding hardware breakpoint register.
+ WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+ if (error.Fail())
+ {
+ m_hbr_regs[hw_idx].control = tempControl;
+ m_hbr_regs[hw_idx].address = tempAddr;
+ m_hbr_regs[hw_idx].refcount = tempRefCount;
+
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return LLDB_INVALID_INDEX32;
+
+ return m_max_hwp_supported;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return LLDB_INVALID_INDEX32;
+
+ uint32_t control_value = 0, wp_index = 0;
+
+ // Check if we are setting watchpoint other than read/write/access
+ // Also update watchpoint flag to match AArch64 write-read bit configuration.
+ switch (watch_flags)
+ {
+ case 1:
+ watch_flags = 2;
+ break;
+ case 2:
+ watch_flags = 1;
+ break;
+ case 3:
+ break;
+ default:
+ return LLDB_INVALID_INDEX32;
+ }
+
+ // Check if size has a valid hardware watchpoint length.
+ if (size != 1 && size != 2 && size != 4 && size != 8)
+ return LLDB_INVALID_INDEX32;
+
+ // Check 8-byte alignment for hardware watchpoint target address.
+ // TODO: Add support for watching un-aligned addresses
+ if (addr & 0x07)
+ return LLDB_INVALID_INDEX32;
+
+ // Setup control value
+ control_value = watch_flags << 3;
+ control_value |= ((1 << size) - 1) << 5;
+ control_value |= (2 << 1) | 1;
+
+ // Iterate over stored watchpoints
+ // Find a free wp_index or update reference count if duplicate.
+ wp_index = LLDB_INVALID_INDEX32;
+ for (uint32_t i = 0; i < m_max_hwp_supported; i++)
+ {
+ if ((m_hwp_regs[i].control & 1) == 0)
+ {
+ wp_index = i; // Mark last free slot
+ }
+ else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
+ {
+ wp_index = i; // Mark duplicate index
+ break; // Stop searching here
+ }
+ }
+
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return LLDB_INVALID_INDEX32;
+
+ // Add new or update existing watchpoint
+ if ((m_hwp_regs[wp_index].control & 1) == 0)
+ {
+ // Update watchpoint in local cache
+ m_hwp_regs[wp_index].address = addr;
+ m_hwp_regs[wp_index].control = control_value;
+ m_hwp_regs[wp_index].refcount = 1;
+
+ // PTRACE call to set corresponding watchpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+ if (error.Fail())
+ {
+ m_hwp_regs[wp_index].address = 0;
+ m_hwp_regs[wp_index].control &= ~1;
+ m_hwp_regs[wp_index].refcount = 0;
+
+ return LLDB_INVALID_INDEX32;
+ }
+ }
+ else
+ m_hwp_regs[wp_index].refcount++;
+
+ return wp_index;
+}
+
+bool
+NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return false;
+
+ if (wp_index >= m_max_hwp_supported)
+ return false;
+
+ // Update reference count if multiple references.
+ if (m_hwp_regs[wp_index].refcount > 1)
+ {
+ m_hwp_regs[wp_index].refcount--;
+ return true;
+ }
+ else if (m_hwp_regs[wp_index].refcount == 1)
+ {
+ // Create a backup we can revert to in case of failure.
+ lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
+ uint32_t tempControl = m_hwp_regs[wp_index].control;
+ uint32_t tempRefCount = m_hwp_regs[wp_index].refcount;
+
+ // Update watchpoint in local cache
+ m_hwp_regs[wp_index].control &= ~1;
+ m_hwp_regs[wp_index].address = 0;
+ m_hwp_regs[wp_index].refcount = 0;
+
+ // Ptrace call to update hardware debug registers
+ error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+ if (error.Fail())
+ {
+ m_hwp_regs[wp_index].control = tempControl;
+ m_hwp_regs[wp_index].address = tempAddr;
+ m_hwp_regs[wp_index].refcount = tempRefCount;
+
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+Error
+NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ Error error;
+
+ // Read hardware breakpoint and watchpoint information.
+ error = ReadHardwareDebugInfo ();
+
+ if (error.Fail())
+ return error;
+
+ lldb::addr_t tempAddr = 0;
+ uint32_t tempControl = 0, tempRefCount = 0;
+
+ for (uint32_t i = 0; i < m_max_hwp_supported; i++)
+ {
+ if (m_hwp_regs[i].control & 0x01)
+ {
+ // Create a backup we can revert to in case of failure.
+ tempAddr = m_hwp_regs[i].address;
+ tempControl = m_hwp_regs[i].control;
+ tempRefCount = m_hwp_regs[i].refcount;
+
+ // Clear watchpoints in local cache
+ m_hwp_regs[i].control &= ~1;
+ m_hwp_regs[i].address = 0;
+ m_hwp_regs[i].refcount = 0;
+
+ // Ptrace call to update hardware debug registers
+ error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+ if (error.Fail())
+ {
+ m_hwp_regs[i].control = tempControl;
+ m_hwp_regs[i].address = tempAddr;
+ m_hwp_regs[i].refcount = tempRefCount;
+
+ return error;
+ }
+ }
+ }
+
+ return Error();
+}
+
+uint32_t
+NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+ switch ((m_hwp_regs[wp_index].control >> 5) & 0xff)
+ {
+ case 0x01:
+ return 1;
+ case 0x03:
+ return 2;
+ case 0x0f:
+ return 4;
+ case 0xff:
+ return 8;
+ default:
+ return 0;
+ }
+}
+bool
+NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
+ return true;
+ else
+ return false;
+}
+
+Error
+NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ uint32_t watch_size;
+ lldb::addr_t watch_addr;
+
+ for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
+ {
+ watch_size = GetWatchpointSize (wp_index);
+ watch_addr = m_hwp_regs[wp_index].address;
+
+ if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
+ && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
+ {
+ return Error();
+ }
+ }
+
+ wp_index = LLDB_INVALID_INDEX32;
+ return Error();
+}
+
+lldb::addr_t
+NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+ if (wp_index >= m_max_hwp_supported)
+ return LLDB_INVALID_ADDRESS;
+
+ if (WatchpointIsEnabled(wp_index))
+ return m_hwp_regs[wp_index].address;
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+Error
+NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo()
+{
+ if (!m_refresh_hwdebug_info)
+ {
+ return Error();
+ }
+
+ ::pid_t tid = m_thread.GetID();
+
+ int regset = NT_ARM_HW_WATCH;
+ struct iovec ioVec;
+ struct user_hwdebug_state dreg_state;
+ Error error;
+
+ ioVec.iov_base = &dreg_state;
+ ioVec.iov_len = sizeof (dreg_state);
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
+
+ if (error.Fail())
+ return error;
+
+ m_max_hwp_supported = dreg_state.dbg_info & 0xff;
+
+ regset = NT_ARM_HW_BREAK;
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
+
+ if (error.Fail())
+ return error;
+
+ m_max_hbp_supported = dreg_state.dbg_info & 0xff;
+ m_refresh_hwdebug_info = false;
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType)
+{
+ struct iovec ioVec;
+ struct user_hwdebug_state dreg_state;
+ Error error;
+
+ memset (&dreg_state, 0, sizeof (dreg_state));
+ ioVec.iov_base = &dreg_state;
+
+ if (hwbType == eDREGTypeWATCH)
+ {
+ hwbType = NT_ARM_HW_WATCH;
+ ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad)
+ + (sizeof (dreg_state.dbg_regs [0]) * m_max_hwp_supported);
+
+ for (uint32_t i = 0; i < m_max_hwp_supported; i++)
+ {
+ dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
+ dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
+ }
+ }
+ else
+ {
+ hwbType = NT_ARM_HW_BREAK;
+ ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad)
+ + (sizeof (dreg_state.dbg_regs [0]) * m_max_hbp_supported);
+
+ for (uint32_t i = 0; i < m_max_hbp_supported; i++)
+ {
+ dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address;
+ dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control;
+ }
+ }
+
+ return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len);
+}
+
+Error
+NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset,
+ const char* reg_name,
+ uint32_t size,
+ RegisterValue &value)
+{
+ Error error;
+ if (offset > sizeof(struct user_pt_regs))
+ {
+ uintptr_t offset = offset - sizeof(struct user_pt_regs);
+ if (offset > sizeof(struct user_fpsimd_state))
+ {
+ error.SetErrorString("invalid offset value");
+ return error;
+ }
+ elf_fpregset_t regs;
+ int regset = NT_FPREGSET;
+ struct iovec ioVec;
+
+ ioVec.iov_base = &regs;
+ ioVec.iov_len = sizeof regs;
+ error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
+ if (error.Success())
+ {
+ ArchSpec arch;
+ if (m_thread.GetProcess()->GetArchitecture(arch))
+ value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16, arch.GetByteOrder());
+ else
+ error.SetErrorString("failed to get architecture");
+ }
+ }
+ else
+ {
+ elf_gregset_t regs;
+ int regset = NT_PRSTATUS;
+ struct iovec ioVec;
+
+ ioVec.iov_base = &regs;
+ ioVec.iov_len = sizeof regs;
+ error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
+ if (error.Success())
+ {
+ ArchSpec arch;
+ if (m_thread.GetProcess()->GetArchitecture(arch))
+ value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder());
+ else
+ error.SetErrorString("failed to get architecture");
+ }
+ }
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset,
+ const char* reg_name,
+ const RegisterValue &value)
+{
+ Error error;
+ ::pid_t tid = m_thread.GetID();
+ if (offset > sizeof(struct user_pt_regs))
+ {
+ uintptr_t offset = offset - sizeof(struct user_pt_regs);
+ if (offset > sizeof(struct user_fpsimd_state))
+ {
+ error.SetErrorString("invalid offset value");
+ return error;
+ }
+ elf_fpregset_t regs;
+ int regset = NT_FPREGSET;
+ struct iovec ioVec;
+
+ ioVec.iov_base = &regs;
+ ioVec.iov_len = sizeof regs;
+ error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
+
+ if (error.Success())
+ {
+ ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 16);
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
+ }
+ }
+ else
+ {
+ elf_gregset_t regs;
+ int regset = NT_PRSTATUS;
+ struct iovec ioVec;
+
+ ioVec.iov_base = &regs;
+ ioVec.iov_len = sizeof regs;
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
+ if (error.Success())
+ {
+ ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 8);
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
+ }
+ }
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size)
+{
+ int regset = NT_PRSTATUS;
+ struct iovec ioVec;
+ Error error;
+
+ ioVec.iov_base = buf;
+ ioVec.iov_len = buf_size;
+ return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
+}
+
+Error
+NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size)
+{
+ int regset = NT_PRSTATUS;
+ struct iovec ioVec;
+ Error error;
+
+ ioVec.iov_base = buf;
+ ioVec.iov_len = buf_size;
+ return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
+}
+
+Error
+NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size)
+{
+ int regset = NT_FPREGSET;
+ struct iovec ioVec;
+ Error error;
+
+ ioVec.iov_base = buf;
+ ioVec.iov_len = buf_size;
+ return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
+}
+
+Error
+NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size)
+{
+ int regset = NT_FPREGSET;
+ struct iovec ioVec;
+ Error error;
+
+ ioVec.iov_base = buf;
+ ioVec.iov_len = buf_size;
+ return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
+}
+
+uint32_t
+NativeRegisterContextLinux_arm64::CalculateFprOffset(const RegisterInfo* reg_info) const
+{
+ return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
+}
+
+#endif // defined (__arm64__) || defined (__aarch64__)
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
new file mode 100644
index 000000000000..c60baa637b8a
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
@@ -0,0 +1,196 @@
+//===-- NativeRegisterContextLinux_arm64.h ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__arm64__) || defined (__aarch64__)
+
+#ifndef lldb_NativeRegisterContextLinux_arm64_h
+#define lldb_NativeRegisterContextLinux_arm64_h
+
+#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
+#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
+
+namespace lldb_private {
+namespace process_linux {
+
+ class NativeProcessLinux;
+
+ class NativeRegisterContextLinux_arm64 : public NativeRegisterContextLinux
+ {
+ public:
+ NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx);
+
+ uint32_t
+ GetRegisterSetCount () const override;
+
+ uint32_t
+ GetUserRegisterCount() const override;
+
+ const RegisterSet *
+ GetRegisterSet (uint32_t set_index) const override;
+
+ Error
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value) override;
+
+ Error
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
+
+ Error
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override;
+
+ Error
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
+
+ //------------------------------------------------------------------
+ // Hardware breakpoints/watchpoint mangement functions
+ //------------------------------------------------------------------
+
+ uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size) override;
+
+ bool
+ ClearHardwareBreakpoint (uint32_t hw_idx) override;
+
+ uint32_t
+ NumSupportedHardwareWatchpoints () override;
+
+ uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) override;
+
+ bool
+ ClearHardwareWatchpoint (uint32_t hw_index) override;
+
+ Error
+ ClearAllHardwareWatchpoints () override;
+
+ Error
+ GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override;
+
+ lldb::addr_t
+ GetWatchpointAddress (uint32_t wp_index) override;
+
+ uint32_t
+ GetWatchpointSize(uint32_t wp_index);
+
+ bool
+ WatchpointIsEnabled(uint32_t wp_index);
+
+ // Debug register type select
+ enum DREGType
+ {
+ eDREGTypeWATCH = 0,
+ eDREGTypeBREAK
+ };
+
+ protected:
+ Error
+ DoReadRegisterValue(uint32_t offset,
+ const char* reg_name,
+ uint32_t size,
+ RegisterValue &value) override;
+
+ Error
+ DoWriteRegisterValue(uint32_t offset,
+ const char* reg_name,
+ const RegisterValue &value) override;
+
+ Error
+ DoReadGPR(void *buf, size_t buf_size) override;
+
+ Error
+ DoWriteGPR(void *buf, size_t buf_size) override;
+
+ Error
+ DoReadFPR(void *buf, size_t buf_size) override;
+
+ Error
+ DoWriteFPR(void *buf, size_t buf_size) override;
+
+ void*
+ GetGPRBuffer() override { return &m_gpr_arm64; }
+
+ void*
+ GetFPRBuffer() override { return &m_fpr; }
+
+ size_t
+ GetFPRSize() override { return sizeof(m_fpr); }
+
+ private:
+ struct RegInfo
+ {
+ uint32_t num_registers;
+ uint32_t num_gpr_registers;
+ uint32_t num_fpr_registers;
+
+ uint32_t last_gpr;
+ uint32_t first_fpr;
+ uint32_t last_fpr;
+
+ uint32_t first_fpr_v;
+ uint32_t last_fpr_v;
+
+ uint32_t gpr_flags;
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct VReg
+ {
+ uint8_t bytes[16];
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct FPU
+ {
+ VReg v[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ };
+
+ uint64_t m_gpr_arm64[k_num_gpr_registers_arm64]; // 64-bit general purpose registers.
+ RegInfo m_reg_info;
+ FPU m_fpr; // floating-point registers including extended register sets.
+
+ // Debug register info for hardware breakpoints and watchpoints management.
+ struct DREG
+ {
+ lldb::addr_t address; // Breakpoint/watchpoint address value.
+ uint32_t control; // Breakpoint/watchpoint control value.
+ uint32_t refcount; // Serves as enable/disable and refernce counter.
+ };
+
+ struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints
+ struct DREG m_hwp_regs[16]; // Arm native linux hardware watchpoints
+
+ uint32_t m_max_hwp_supported;
+ uint32_t m_max_hbp_supported;
+ bool m_refresh_hwdebug_info;
+
+ bool
+ IsGPR(unsigned reg) const;
+
+ bool
+ IsFPR(unsigned reg) const;
+
+ Error
+ ReadHardwareDebugInfo();
+
+ Error
+ WriteHardwareDebugRegs(int hwbType);
+
+ uint32_t
+ CalculateFprOffset(const RegisterInfo* reg_info) const;
+ };
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextLinux_arm64_h
+
+#endif // defined (__arm64__) || defined (__aarch64__)
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
new file mode 100644
index 000000000000..3cfeaf5546bc
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
@@ -0,0 +1,1431 @@
+//===-- NativeRegisterContextLinux_mips64.cpp ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__mips__)
+
+#include "NativeRegisterContextLinux_mips64.h"
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "Plugins/Process/Linux/NativeProcessLinux.h"
+#include "Plugins/Process/Linux/Procfs.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_mips64.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_mips.h"
+#define NT_MIPS_MSA 0x600
+#define CONFIG5_FRE (1 << 8)
+#define SR_FR (1 << 26)
+#define NUM_REGISTERS 32
+
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#ifndef PTRACE_GET_WATCH_REGS
+enum pt_watch_style
+{
+ pt_watch_style_mips32,
+ pt_watch_style_mips64
+};
+struct mips32_watch_regs
+{
+ uint32_t watchlo[8];
+ uint16_t watchhi[8];
+ uint16_t watch_masks[8];
+ uint32_t num_valid;
+} __attribute__((aligned(8)));
+
+struct mips64_watch_regs
+{
+ uint64_t watchlo[8];
+ uint16_t watchhi[8];
+ uint16_t watch_masks[8];
+ uint32_t num_valid;
+} __attribute__((aligned(8)));
+
+struct pt_watch_regs
+{
+ enum pt_watch_style style;
+ union
+ {
+ struct mips32_watch_regs mips32;
+ struct mips64_watch_regs mips64;
+ };
+};
+
+#define PTRACE_GET_WATCH_REGS 0xd0
+#define PTRACE_SET_WATCH_REGS 0xd1
+#endif
+
+#define W (1 << 0)
+#define R (1 << 1)
+#define I (1 << 2)
+
+#define IRW (I | R | W)
+
+struct pt_watch_regs default_watch_regs;
+
+using namespace lldb_private;
+using namespace lldb_private::process_linux;
+
+// ----------------------------------------------------------------------------
+// Private namespace.
+// ----------------------------------------------------------------------------
+
+namespace
+{
+ // mips general purpose registers.
+ const uint32_t
+ g_gp_regnums_mips[] =
+ {
+ gpr_zero_mips,
+ gpr_r1_mips,
+ gpr_r2_mips,
+ gpr_r3_mips,
+ gpr_r4_mips,
+ gpr_r5_mips,
+ gpr_r6_mips,
+ gpr_r7_mips,
+ gpr_r8_mips,
+ gpr_r9_mips,
+ gpr_r10_mips,
+ gpr_r11_mips,
+ gpr_r12_mips,
+ gpr_r13_mips,
+ gpr_r14_mips,
+ gpr_r15_mips,
+ gpr_r16_mips,
+ gpr_r17_mips,
+ gpr_r18_mips,
+ gpr_r19_mips,
+ gpr_r20_mips,
+ gpr_r21_mips,
+ gpr_r22_mips,
+ gpr_r23_mips,
+ gpr_r24_mips,
+ gpr_r25_mips,
+ gpr_r26_mips,
+ gpr_r27_mips,
+ gpr_gp_mips,
+ gpr_sp_mips,
+ gpr_r30_mips,
+ gpr_ra_mips,
+ gpr_sr_mips,
+ gpr_mullo_mips,
+ gpr_mulhi_mips,
+ gpr_badvaddr_mips,
+ gpr_cause_mips,
+ gpr_pc_mips,
+ gpr_config5_mips,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+
+ static_assert((sizeof(g_gp_regnums_mips) / sizeof(g_gp_regnums_mips[0])) - 1 == k_num_gpr_registers_mips,
+ "g_gp_regnums_mips has wrong number of register infos");
+
+ // mips floating point registers.
+ const uint32_t
+ g_fp_regnums_mips[] =
+ {
+ fpr_f0_mips,
+ fpr_f1_mips,
+ fpr_f2_mips,
+ fpr_f3_mips,
+ fpr_f4_mips,
+ fpr_f5_mips,
+ fpr_f6_mips,
+ fpr_f7_mips,
+ fpr_f8_mips,
+ fpr_f9_mips,
+ fpr_f10_mips,
+ fpr_f11_mips,
+ fpr_f12_mips,
+ fpr_f13_mips,
+ fpr_f14_mips,
+ fpr_f15_mips,
+ fpr_f16_mips,
+ fpr_f17_mips,
+ fpr_f18_mips,
+ fpr_f19_mips,
+ fpr_f20_mips,
+ fpr_f21_mips,
+ fpr_f22_mips,
+ fpr_f23_mips,
+ fpr_f24_mips,
+ fpr_f25_mips,
+ fpr_f26_mips,
+ fpr_f27_mips,
+ fpr_f28_mips,
+ fpr_f29_mips,
+ fpr_f30_mips,
+ fpr_f31_mips,
+ fpr_fcsr_mips,
+ fpr_fir_mips,
+ fpr_config5_mips,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+
+ static_assert((sizeof(g_fp_regnums_mips) / sizeof(g_fp_regnums_mips[0])) - 1 == k_num_fpr_registers_mips,
+ "g_fp_regnums_mips has wrong number of register infos");
+
+ // mips MSA registers.
+ const uint32_t
+ g_msa_regnums_mips[] =
+ {
+ msa_w0_mips,
+ msa_w1_mips,
+ msa_w2_mips,
+ msa_w3_mips,
+ msa_w4_mips,
+ msa_w5_mips,
+ msa_w6_mips,
+ msa_w7_mips,
+ msa_w8_mips,
+ msa_w9_mips,
+ msa_w10_mips,
+ msa_w11_mips,
+ msa_w12_mips,
+ msa_w13_mips,
+ msa_w14_mips,
+ msa_w15_mips,
+ msa_w16_mips,
+ msa_w17_mips,
+ msa_w18_mips,
+ msa_w19_mips,
+ msa_w20_mips,
+ msa_w21_mips,
+ msa_w22_mips,
+ msa_w23_mips,
+ msa_w24_mips,
+ msa_w25_mips,
+ msa_w26_mips,
+ msa_w27_mips,
+ msa_w28_mips,
+ msa_w29_mips,
+ msa_w30_mips,
+ msa_w31_mips,
+ msa_fcsr_mips,
+ msa_fir_mips,
+ msa_mcsr_mips,
+ msa_mir_mips,
+ msa_config5_mips,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+
+ static_assert((sizeof(g_msa_regnums_mips) / sizeof(g_msa_regnums_mips[0])) - 1 == k_num_msa_registers_mips,
+ "g_msa_regnums_mips has wrong number of register infos");
+
+ // mips64 general purpose registers.
+ const uint32_t
+ g_gp_regnums_mips64[] =
+ {
+ gpr_zero_mips64,
+ gpr_r1_mips64,
+ gpr_r2_mips64,
+ gpr_r3_mips64,
+ gpr_r4_mips64,
+ gpr_r5_mips64,
+ gpr_r6_mips64,
+ gpr_r7_mips64,
+ gpr_r8_mips64,
+ gpr_r9_mips64,
+ gpr_r10_mips64,
+ gpr_r11_mips64,
+ gpr_r12_mips64,
+ gpr_r13_mips64,
+ gpr_r14_mips64,
+ gpr_r15_mips64,
+ gpr_r16_mips64,
+ gpr_r17_mips64,
+ gpr_r18_mips64,
+ gpr_r19_mips64,
+ gpr_r20_mips64,
+ gpr_r21_mips64,
+ gpr_r22_mips64,
+ gpr_r23_mips64,
+ gpr_r24_mips64,
+ gpr_r25_mips64,
+ gpr_r26_mips64,
+ gpr_r27_mips64,
+ gpr_gp_mips64,
+ gpr_sp_mips64,
+ gpr_r30_mips64,
+ gpr_ra_mips64,
+ gpr_sr_mips64,
+ gpr_mullo_mips64,
+ gpr_mulhi_mips64,
+ gpr_badvaddr_mips64,
+ gpr_cause_mips64,
+ gpr_pc_mips64,
+ gpr_config5_mips64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+
+ static_assert((sizeof(g_gp_regnums_mips64) / sizeof(g_gp_regnums_mips64[0])) - 1 == k_num_gpr_registers_mips64,
+ "g_gp_regnums_mips64 has wrong number of register infos");
+
+ // mips64 floating point registers.
+ const uint32_t
+ g_fp_regnums_mips64[] =
+ {
+ fpr_f0_mips64,
+ fpr_f1_mips64,
+ fpr_f2_mips64,
+ fpr_f3_mips64,
+ fpr_f4_mips64,
+ fpr_f5_mips64,
+ fpr_f6_mips64,
+ fpr_f7_mips64,
+ fpr_f8_mips64,
+ fpr_f9_mips64,
+ fpr_f10_mips64,
+ fpr_f11_mips64,
+ fpr_f12_mips64,
+ fpr_f13_mips64,
+ fpr_f14_mips64,
+ fpr_f15_mips64,
+ fpr_f16_mips64,
+ fpr_f17_mips64,
+ fpr_f18_mips64,
+ fpr_f19_mips64,
+ fpr_f20_mips64,
+ fpr_f21_mips64,
+ fpr_f22_mips64,
+ fpr_f23_mips64,
+ fpr_f24_mips64,
+ fpr_f25_mips64,
+ fpr_f26_mips64,
+ fpr_f27_mips64,
+ fpr_f28_mips64,
+ fpr_f29_mips64,
+ fpr_f30_mips64,
+ fpr_f31_mips64,
+ fpr_fcsr_mips64,
+ fpr_fir_mips64,
+ fpr_config5_mips64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+
+ static_assert((sizeof(g_fp_regnums_mips64) / sizeof(g_fp_regnums_mips64[0])) - 1 == k_num_fpr_registers_mips64,
+ "g_fp_regnums_mips64 has wrong number of register infos");
+
+ // mips64 MSA registers.
+ const uint32_t
+ g_msa_regnums_mips64[] =
+ {
+ msa_w0_mips64,
+ msa_w1_mips64,
+ msa_w2_mips64,
+ msa_w3_mips64,
+ msa_w4_mips64,
+ msa_w5_mips64,
+ msa_w6_mips64,
+ msa_w7_mips64,
+ msa_w8_mips64,
+ msa_w9_mips64,
+ msa_w10_mips64,
+ msa_w11_mips64,
+ msa_w12_mips64,
+ msa_w13_mips64,
+ msa_w14_mips64,
+ msa_w15_mips64,
+ msa_w16_mips64,
+ msa_w17_mips64,
+ msa_w18_mips64,
+ msa_w19_mips64,
+ msa_w20_mips64,
+ msa_w21_mips64,
+ msa_w22_mips64,
+ msa_w23_mips64,
+ msa_w24_mips64,
+ msa_w25_mips64,
+ msa_w26_mips64,
+ msa_w27_mips64,
+ msa_w28_mips64,
+ msa_w29_mips64,
+ msa_w30_mips64,
+ msa_w31_mips64,
+ msa_fcsr_mips64,
+ msa_fir_mips64,
+ msa_mcsr_mips64,
+ msa_mir_mips64,
+ msa_config5_mips64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+
+ static_assert((sizeof(g_msa_regnums_mips64) / sizeof(g_msa_regnums_mips64[0])) - 1 == k_num_msa_registers_mips64,
+ "g_msa_regnums_mips64 has wrong number of register infos");
+
+ // Number of register sets provided by this context.
+ enum
+ {
+ k_num_register_sets = 3
+ };
+
+ // Register sets for mips.
+ static const RegisterSet
+ g_reg_sets_mips[k_num_register_sets] =
+ {
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_mips, g_gp_regnums_mips },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_mips, g_fp_regnums_mips },
+ { "MSA Registers", "msa", k_num_msa_registers_mips, g_msa_regnums_mips }
+ };
+
+ // Register sets for mips64.
+ static const RegisterSet
+ g_reg_sets_mips64[k_num_register_sets] =
+ {
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_mips64, g_gp_regnums_mips64 },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_mips64, g_fp_regnums_mips64 },
+ { "MSA Registers", "msa", k_num_msa_registers_mips64, g_msa_regnums_mips64 },
+ };
+
+} // end of anonymous namespace
+
+NativeRegisterContextLinux*
+NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx)
+{
+ return new NativeRegisterContextLinux_mips64(target_arch, native_thread, concrete_frame_idx);
+}
+
+#define REG_CONTEXT_SIZE (GetRegisterInfoInterface ().GetGPRSize () + sizeof(FPR_linux_mips) + sizeof(MSA_linux_mips))
+
+// ----------------------------------------------------------------------------
+// NativeRegisterContextLinux_mips64 members.
+// ----------------------------------------------------------------------------
+
+static RegisterInfoInterface*
+CreateRegisterInfoInterface(const ArchSpec& target_arch)
+{
+ if (HostInfo::GetArchitecture().GetAddressByteSize() == 4)
+ {
+ // 32-bit hosts run with a RegisterContextLinux_mips context.
+ return new RegisterContextLinux_mips(target_arch, NativeRegisterContextLinux_mips64::IsMSAAvailable());
+ }
+ else
+ {
+ assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
+ "Register setting path assumes this is a 64-bit host");
+ // mips64 hosts know how to work with 64-bit and 32-bit EXEs using the mips64 register context.
+ return new RegisterContextLinux_mips64 (target_arch, NativeRegisterContextLinux_mips64::IsMSAAvailable());
+ }
+}
+
+NativeRegisterContextLinux_mips64::NativeRegisterContextLinux_mips64 (const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx) :
+ NativeRegisterContextLinux (native_thread, concrete_frame_idx, CreateRegisterInfoInterface(target_arch))
+{
+ switch (target_arch.GetMachine ())
+ {
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ m_reg_info.num_registers = k_num_registers_mips;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_mips;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_mips;
+ m_reg_info.last_gpr = k_last_gpr_mips;
+ m_reg_info.first_fpr = k_first_fpr_mips;
+ m_reg_info.last_fpr = k_last_fpr_mips;
+ m_reg_info.first_msa = k_first_msa_mips;
+ m_reg_info.last_msa = k_last_msa_mips;
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ m_reg_info.num_registers = k_num_registers_mips64;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_mips64;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_mips64;
+ m_reg_info.last_gpr = k_last_gpr_mips64;
+ m_reg_info.first_fpr = k_first_fpr_mips64;
+ m_reg_info.last_fpr = k_last_fpr_mips64;
+ m_reg_info.first_msa = k_first_msa_mips64;
+ m_reg_info.last_msa = k_last_msa_mips64;
+ break;
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+
+ // Initialize m_iovec to point to the buffer and buffer size
+ // using the conventions of Berkeley style UIO structures, as required
+ // by PTRACE extensions.
+ m_iovec.iov_base = &m_msa;
+ m_iovec.iov_len = sizeof(MSA_linux_mips);
+
+ // init h/w watchpoint addr map
+ for (int index = 0;index <= MAX_NUM_WP; index++)
+ hw_addr_map[index] = LLDB_INVALID_ADDRESS;
+
+ ::memset(&m_gpr, 0, sizeof(GPR_linux_mips));
+ ::memset(&m_fpr, 0, sizeof(FPR_linux_mips));
+ ::memset(&m_msa, 0, sizeof(MSA_linux_mips));
+}
+
+uint32_t
+NativeRegisterContextLinux_mips64::GetRegisterSetCount () const
+{
+ return k_num_register_sets;
+}
+
+lldb::addr_t
+NativeRegisterContextLinux_mips64::GetPCfromBreakpointLocation (lldb::addr_t fail_value)
+{
+ Error error;
+ RegisterValue pc_value;
+ lldb::addr_t pc = fail_value;
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_mips64::%s Reading PC from breakpoint location", __FUNCTION__);
+
+ // PC register is at index 34 of the register array
+ const RegisterInfo *const pc_info_p = GetRegisterInfoAtIndex (gpr_pc_mips64);
+
+ error = ReadRegister (pc_info_p, pc_value);
+ if (error.Success ())
+ {
+ pc = pc_value.GetAsUInt64 ();
+
+ // CAUSE register is at index 37 of the register array
+ const RegisterInfo *const cause_info_p = GetRegisterInfoAtIndex (gpr_cause_mips64);
+ RegisterValue cause_value;
+
+ ReadRegister (cause_info_p, cause_value);
+
+ uint64_t cause = cause_value.GetAsUInt64 ();
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_mips64::%s PC 0x%" PRIx64 " Cause 0x%" PRIx64, __FUNCTION__, pc, cause);
+
+ /*
+ * The breakpoint might be in a delay slot. In this case PC points
+ * to the delayed branch instruction rather then the instruction
+ * in the delay slot. If the CAUSE.BD flag is set then adjust the
+ * PC based on the size of the branch instruction.
+ */
+ if ((cause & (1 << 31)) != 0)
+ {
+ lldb::addr_t branch_delay = 0;
+ branch_delay = 4; // FIXME - Adjust according to size of branch instruction at PC
+ pc = pc + branch_delay;
+ pc_value.SetUInt64 (pc);
+ WriteRegister (pc_info_p, pc_value);
+
+ if (log)
+ log->Printf ("NativeRegisterContextLinux_mips64::%s New PC 0x%" PRIx64, __FUNCTION__, pc);
+ }
+ }
+
+ return pc;
+}
+
+const RegisterSet *
+NativeRegisterContextLinux_mips64::GetRegisterSet (uint32_t set_index) const
+{
+ if (set_index >= k_num_register_sets)
+ return nullptr;
+
+ switch (GetRegisterInfoInterface ().GetTargetArchitecture ().GetMachine ())
+ {
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ return &g_reg_sets_mips64[set_index];
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return &g_reg_sets_mips[set_index];
+ default:
+ assert (false && "Unhandled target architecture.");
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_mips64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ Error error;
+
+ if (!reg_info)
+ {
+ error.SetErrorString ("reg_info NULL");
+ return error;
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM)
+ {
+ // This is likely an internal register for lldb use only and should not be directly queried.
+ error.SetErrorStringWithFormat ("register \"%s\" is an internal-only lldb register, cannot read directly", reg_info->name);
+ return error;
+ }
+
+ if (IsMSA(reg) && !IsMSAAvailable())
+ {
+ error.SetErrorString ("MSA not available on this processor");
+ return error;
+ }
+
+ if (IsMSA(reg) || IsFPR(reg))
+ {
+ uint8_t *src;
+
+ error = ReadCP1();
+
+ if (!error.Success())
+ {
+ error.SetErrorString ("failed to read co-processor 1 register");
+ return error;
+ }
+
+ if (IsFPR(reg))
+ {
+ assert (reg_info->byte_offset < sizeof(UserArea));
+ src = (uint8_t *)&m_fpr + reg_info->byte_offset - (sizeof(m_gpr));
+ }
+ else
+ {
+ assert (reg_info->byte_offset < sizeof(UserArea));
+ src = (uint8_t *)&m_msa + reg_info->byte_offset - (sizeof(m_gpr) + sizeof(m_fpr));
+ }
+ switch (reg_info->byte_size)
+ {
+ case 4:
+ reg_value.SetUInt32(*(uint32_t *)src);
+ break;
+ case 8:
+ reg_value.SetUInt64(*(uint64_t *)src);
+ break;
+ case 16:
+ reg_value.SetBytes((const void *)src, 16, GetByteOrder());
+ break;
+ default:
+ assert(false && "Unhandled data size.");
+ error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
+ break;
+ }
+ }
+ else
+ {
+ error = ReadRegisterRaw(reg, reg_value);
+ }
+
+ return error;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_mips64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ Error error;
+
+ assert (reg_info && "reg_info is null");
+
+ const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (reg_index == LLDB_INVALID_REGNUM)
+ return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
+
+ if (IsMSA(reg_index) && !IsMSAAvailable())
+ {
+ error.SetErrorString ("MSA not available on this processor");
+ return error;
+ }
+
+ if (IsFPR(reg_index) || IsMSA(reg_index))
+ {
+ uint8_t *dst;
+ uint64_t *src;
+
+ // Initialise the FP and MSA buffers by reading all co-processor 1 registers
+ ReadCP1();
+
+ if (IsFPR(reg_index))
+ {
+ assert (reg_info->byte_offset < sizeof(UserArea));
+ dst = (uint8_t *)&m_fpr + reg_info->byte_offset - (sizeof(m_gpr));
+ }
+ else
+ {
+ assert (reg_info->byte_offset < sizeof(UserArea));
+ dst = (uint8_t *)&m_msa + reg_info->byte_offset - (sizeof(m_gpr) + sizeof(m_fpr));
+ }
+ switch (reg_info->byte_size)
+ {
+ case 4:
+ *(uint32_t *)dst = reg_value.GetAsUInt32();
+ break;
+ case 8:
+ *(uint64_t *)dst = reg_value.GetAsUInt64();
+ break;
+ case 16:
+ src = (uint64_t *)reg_value.GetBytes();
+ *(uint64_t *)dst = *src;
+ *(uint64_t *)(dst + 8) = *(src + 1);
+ break;
+ default:
+ assert(false && "Unhandled data size.");
+ error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
+ break;
+ }
+ error = WriteCP1();
+ if (!error.Success())
+ {
+ error.SetErrorString ("failed to write co-processor 1 register");
+ return error;
+ }
+ }
+ else
+ {
+ error = WriteRegisterRaw(reg_index, reg_value);
+ }
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_mips64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ Error error;
+
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (!data_sp)
+ {
+ error.SetErrorStringWithFormat ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ error = ReadGPR();
+ if (!error.Success())
+ {
+ error.SetErrorString ("ReadGPR() failed");
+ return error;
+ }
+
+ error = ReadCP1();
+ if (!error.Success())
+ {
+ error.SetErrorString ("ReadCP1() failed");
+ return error;
+ }
+
+ uint8_t *dst = data_sp->GetBytes ();
+ if (dst == nullptr)
+ {
+ error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ ::memcpy (dst, &m_gpr, GetRegisterInfoInterface ().GetGPRSize ());
+ dst += GetRegisterInfoInterface ().GetGPRSize ();
+
+ ::memcpy (dst, &m_fpr, GetFPRSize ());
+ dst += GetFPRSize ();
+
+ ::memcpy (dst, &m_msa, sizeof(MSA_linux_mips));
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_mips64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ Error error;
+
+ if (!data_sp)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s invalid data_sp provided", __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
+ return error;
+ }
+
+
+ uint8_t *src = data_sp->GetBytes ();
+ if (src == nullptr)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
+ return error;
+ }
+
+ ::memcpy (&m_gpr, src, GetRegisterInfoInterface ().GetGPRSize ());
+ src += GetRegisterInfoInterface ().GetGPRSize ();
+
+ ::memcpy (&m_fpr, src, GetFPRSize ());
+ src += GetFPRSize ();
+
+ ::memcpy (&m_msa, src, sizeof(MSA_linux_mips));
+
+ error = WriteGPR();
+ if (!error.Success())
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s WriteGPR() failed", __FUNCTION__);
+ return error;
+ }
+
+ error = WriteCP1();
+ if (!error.Success())
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s WriteCP1() failed", __FUNCTION__);
+ return error;
+ }
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_mips64::ReadCP1()
+{
+ Error error;
+
+ uint8_t *src, *dst;
+
+ lldb::ByteOrder byte_order = GetByteOrder();
+
+ uint32_t IsBigEndian = (byte_order == lldb::eByteOrderBig);
+
+ if (IsMSAAvailable())
+ {
+ error = NativeRegisterContextLinux::ReadRegisterSet(&m_iovec, sizeof(MSA_linux_mips), NT_MIPS_MSA);
+ src = (uint8_t *)&m_msa + (IsBigEndian * 8);
+ dst = (uint8_t *)&m_fpr;
+ for ( int i = 0; i < NUM_REGISTERS; i++)
+ {
+ // Copy fp values from msa buffer fetched via ptrace
+ *(uint64_t *) dst = *(uint64_t *) src;
+ src = src + 16;
+ dst = dst + 8;
+ }
+ m_fpr.fir = m_msa.fir;
+ m_fpr.fcsr = m_msa.fcsr;
+ m_fpr.config5 = m_msa.config5;
+ }
+ else
+ {
+ error = NativeRegisterContextLinux::ReadFPR();
+ }
+
+ if (IsFR0() || IsFRE())
+ {
+ src = (uint8_t *)&m_fpr + 4 + (IsBigEndian * 4);
+ dst = (uint8_t *)&m_fpr + 8 + (IsBigEndian * 4);
+ for (int i = 0; i < (NUM_REGISTERS / 2); i++)
+ {
+ // copy odd single from top of neighbouring even double
+ *(uint32_t *) dst = *(uint32_t *) src;
+ src = src + 16;
+ dst = dst + 16;
+ }
+ }
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_mips64::WriteCP1()
+{
+ Error error;
+
+ uint8_t *src, *dst;
+
+ lldb::ByteOrder byte_order = GetByteOrder();
+
+ uint32_t IsBigEndian = (byte_order == lldb::eByteOrderBig);
+
+ if (IsFR0() || IsFRE())
+ {
+ src = (uint8_t *)&m_fpr + 8 + (IsBigEndian * 4);
+ dst = (uint8_t *)&m_fpr + 4 + (IsBigEndian * 4);
+ for (int i = 0; i < (NUM_REGISTERS / 2); i++)
+ {
+ // copy odd single to top of neighbouring even double
+ *(uint32_t *) dst = *(uint32_t *) src;
+ src = src + 16;
+ dst = dst + 16;
+ }
+ }
+
+ if (IsMSAAvailable())
+ {
+ dst = (uint8_t *)&m_msa + (IsBigEndian * 8);
+ src = (uint8_t *)&m_fpr;
+ for (int i = 0; i < NUM_REGISTERS; i++)
+ {
+ // Copy fp values to msa buffer for ptrace
+ *(uint64_t *) dst = *(uint64_t *) src;
+ dst = dst + 16;
+ src = src + 8;
+ }
+ m_msa.fir = m_fpr.fir;
+ m_msa.fcsr = m_fpr.fcsr;
+ m_msa.config5 = m_fpr.config5;
+ error = NativeRegisterContextLinux::WriteRegisterSet(&m_iovec, sizeof(MSA_linux_mips), NT_MIPS_MSA);
+ }
+ else
+ {
+ error = NativeRegisterContextLinux::WriteFPR();
+ }
+
+ return error;
+}
+
+bool
+NativeRegisterContextLinux_mips64::IsFR0()
+{
+ const RegisterInfo *const reg_info_p = GetRegisterInfoAtIndex (gpr_sr_mips64);
+
+ RegisterValue reg_value;
+ ReadRegister (reg_info_p, reg_value);
+
+ uint64_t value = reg_value.GetAsUInt64();
+
+ return (!(value & SR_FR));
+}
+
+bool
+NativeRegisterContextLinux_mips64::IsFRE()
+{
+ const RegisterInfo *const reg_info_p = GetRegisterInfoAtIndex (gpr_config5_mips64);
+
+ RegisterValue reg_value;
+ ReadRegister (reg_info_p, reg_value);
+
+ uint64_t config5 = reg_value.GetAsUInt64();
+
+ return (config5 & CONFIG5_FRE);
+}
+
+bool
+NativeRegisterContextLinux_mips64::IsFPR(uint32_t reg_index) const
+{
+ return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr);
+}
+
+static uint32_t
+GetWatchHi (struct pt_watch_regs *regs, uint32_t index)
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (regs->style == pt_watch_style_mips32)
+ return regs->mips32.watchhi[index];
+ else if (regs->style == pt_watch_style_mips64)
+ return regs->mips64.watchhi[index];
+ if(log)
+ log->Printf("Invalid watch register style");
+ return 0;
+}
+
+static void
+SetWatchHi (struct pt_watch_regs *regs, uint32_t index, uint16_t value)
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (regs->style == pt_watch_style_mips32)
+ regs->mips32.watchhi[index] = value;
+ else if (regs->style == pt_watch_style_mips64)
+ regs->mips64.watchhi[index] = value;
+ if(log)
+ log->Printf("Invalid watch register style");
+ return;
+}
+
+static lldb::addr_t
+GetWatchLo (struct pt_watch_regs *regs, uint32_t index)
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (regs->style == pt_watch_style_mips32)
+ return regs->mips32.watchlo[index];
+ else if (regs->style == pt_watch_style_mips64)
+ return regs->mips64.watchlo[index];
+ if(log)
+ log->Printf("Invalid watch register style");
+ return LLDB_INVALID_ADDRESS;
+}
+
+static void
+SetWatchLo (struct pt_watch_regs *regs, uint32_t index, uint64_t value)
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (regs->style == pt_watch_style_mips32)
+ regs->mips32.watchlo[index] = (uint32_t) value;
+ else if (regs->style == pt_watch_style_mips64)
+ regs->mips64.watchlo[index] = value;
+ if(log)
+ log->Printf("Invalid watch register style");
+ return;
+}
+
+static uint32_t
+GetIRWMask (struct pt_watch_regs *regs, uint32_t index)
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (regs->style == pt_watch_style_mips32)
+ return regs->mips32.watch_masks[index] & IRW;
+ else if (regs->style == pt_watch_style_mips64)
+ return regs->mips64.watch_masks[index] & IRW;
+ if(log)
+ log->Printf("Invalid watch register style");
+ return 0;
+}
+
+static uint32_t
+GetRegMask (struct pt_watch_regs *regs, uint32_t index)
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (regs->style == pt_watch_style_mips32)
+ return regs->mips32.watch_masks[index] & ~IRW;
+ else if (regs->style == pt_watch_style_mips64)
+ return regs->mips64.watch_masks[index] & ~IRW;
+ if(log)
+ log->Printf("Invalid watch register style");
+ return 0;
+}
+
+static lldb::addr_t
+GetRangeMask (lldb::addr_t mask)
+{
+ lldb::addr_t mask_bit = 1;
+ while (mask_bit < mask)
+ {
+ mask = mask | mask_bit;
+ mask_bit <<= 1;
+ }
+ return mask;
+}
+
+static int
+GetVacantWatchIndex (struct pt_watch_regs *regs, lldb::addr_t addr, uint32_t size, uint32_t irw, uint32_t num_valid)
+{
+ lldb::addr_t last_byte = addr + size - 1;
+ lldb::addr_t mask = GetRangeMask (addr ^ last_byte) | IRW;
+ lldb::addr_t base_addr = addr & ~mask;
+
+ // Check if this address is already watched by previous watch points.
+ lldb::addr_t lo;
+ uint16_t hi;
+ uint32_t vacant_watches = 0;
+ for (uint32_t index = 0; index < num_valid; index++)
+ {
+ lo = GetWatchLo (regs, index);
+ if (lo != 0 && irw == ((uint32_t) lo & irw))
+ {
+ hi = GetWatchHi (regs, index) | IRW;
+ lo &= ~(lldb::addr_t) hi;
+ if (addr >= lo && last_byte <= (lo + hi))
+ return index;
+ }
+ else
+ vacant_watches++;
+ }
+
+ // Now try to find a vacant index
+ if(vacant_watches > 0)
+ {
+ vacant_watches = 0;
+ for (uint32_t index = 0; index < num_valid; index++)
+ {
+ lo = GetWatchLo (regs, index);
+ if (lo == 0
+ && irw == (GetIRWMask (regs, index) & irw))
+ {
+ if (mask <= (GetRegMask (regs, index) | IRW))
+ {
+ // It fits, we can use it.
+ SetWatchLo (regs, index, base_addr | irw);
+ SetWatchHi (regs, index, mask & ~IRW);
+ return index;
+ }
+ else
+ {
+ // It doesn't fit, but has the proper IRW capabilities
+ vacant_watches++;
+ }
+ }
+ }
+
+ if (vacant_watches > 1)
+ {
+ // Split this watchpoint accross several registers
+ struct pt_watch_regs regs_copy;
+ regs_copy = *regs;
+ lldb::addr_t break_addr;
+ uint32_t segment_size;
+ for (uint32_t index = 0; index < num_valid; index++)
+ {
+ lo = GetWatchLo (&regs_copy, index);
+ hi = GetRegMask (&regs_copy, index) | IRW;
+ if (lo == 0 && irw == (hi & irw))
+ {
+ lo = addr & ~(lldb::addr_t) hi;
+ break_addr = lo + hi + 1;
+ if (break_addr >= addr + size)
+ segment_size = size;
+ else
+ segment_size = break_addr - addr;
+ mask = GetRangeMask (addr ^ (addr + segment_size - 1));
+ SetWatchLo (&regs_copy, index, (addr & ~mask) | irw);
+ SetWatchHi (&regs_copy, index, mask & ~IRW);
+ if (break_addr >= addr + size)
+ {
+ *regs = regs_copy;
+ return index;
+ }
+ size = addr + size - break_addr;
+ addr = break_addr;
+ }
+ }
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContextLinux_mips64::IsMSA(uint32_t reg_index) const
+{
+ return (m_reg_info.first_msa <= reg_index && reg_index <= m_reg_info.last_msa);
+}
+
+bool
+NativeRegisterContextLinux_mips64::IsMSAAvailable()
+{
+ MSA_linux_mips msa_buf;
+ unsigned int regset = NT_MIPS_MSA;
+
+ Error error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, Host::GetCurrentProcessID(), static_cast<void *>(&regset), &msa_buf, sizeof(MSA_linux_mips));
+
+ if (error.Success() && msa_buf.mir)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+Error
+NativeRegisterContextLinux_mips64::IsWatchpointHit (uint32_t wp_index, bool &is_hit)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Error("Watchpoint index out of range");
+
+ // reading the current state of watch regs
+ struct pt_watch_regs watch_readback;
+ Error error = DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&watch_readback));
+
+ if (GetWatchHi (&watch_readback, wp_index) & (IRW))
+ {
+ // clear hit flag in watchhi
+ SetWatchHi (&watch_readback, wp_index, (GetWatchHi (&watch_readback, wp_index) & ~(IRW)));
+ DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&watch_readback));
+
+ is_hit = true;
+ return error;
+ }
+ is_hit = false;
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_mips64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) {
+ uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+ for (wp_index = 0; wp_index < num_hw_wps; ++wp_index)
+ {
+ bool is_hit;
+ Error error = IsWatchpointHit(wp_index, is_hit);
+ if (error.Fail()) {
+ wp_index = LLDB_INVALID_INDEX32;
+ } else if (is_hit) {
+ return error;
+ }
+ }
+ wp_index = LLDB_INVALID_INDEX32;
+ return Error();
+}
+
+Error
+NativeRegisterContextLinux_mips64::IsWatchpointVacant (uint32_t wp_index, bool &is_vacant)
+{
+ is_vacant = false;
+ return Error("MIPS TODO: NativeRegisterContextLinux_mips64::IsWatchpointVacant not implemented");
+}
+
+bool
+NativeRegisterContextLinux_mips64::ClearHardwareWatchpoint(uint32_t wp_index)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return false;
+
+ struct pt_watch_regs regs;
+ // First reading the current state of watch regs
+ DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void*>(&regs));
+
+ if (regs.style == pt_watch_style_mips32)
+ {
+ regs.mips32.watchlo[wp_index] = default_watch_regs.mips32.watchlo[wp_index];
+ regs.mips32.watchhi[wp_index] = default_watch_regs.mips32.watchhi[wp_index];
+ regs.mips32.watch_masks[wp_index] = default_watch_regs.mips32.watch_masks[wp_index];
+ }
+ else // pt_watch_style_mips64
+ {
+ regs.mips64.watchlo[wp_index] = default_watch_regs.mips64.watchlo[wp_index];
+ regs.mips64.watchhi[wp_index] = default_watch_regs.mips64.watchhi[wp_index];
+ regs.mips64.watch_masks[wp_index] = default_watch_regs.mips64.watch_masks[wp_index];
+ }
+
+ Error error = DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&regs));
+ if(!error.Fail())
+ {
+ hw_addr_map[wp_index] = LLDB_INVALID_ADDRESS;
+ return true;
+ }
+ return false;
+}
+
+Error
+NativeRegisterContextLinux_mips64::ClearAllHardwareWatchpoints()
+{
+ return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&default_watch_regs));
+}
+
+Error
+NativeRegisterContextLinux_mips64::SetHardwareWatchpointWithIndex (
+ lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index)
+{
+ Error error;
+ error.SetErrorString ("MIPS TODO: NativeRegisterContextLinux_mips64::SetHardwareWatchpointWithIndex not implemented");
+ return error;
+}
+
+uint32_t
+NativeRegisterContextLinux_mips64::SetHardwareWatchpoint (
+ lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+ struct pt_watch_regs regs;
+
+ // First reading the current state of watch regs
+ DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&regs));
+
+ // Try if a new watch point fits in this state
+ int index = GetVacantWatchIndex (&regs, addr, size, watch_flags, NumSupportedHardwareWatchpoints());
+
+ // New watchpoint doesn't fit
+ if (index == LLDB_INVALID_INDEX32)
+ return LLDB_INVALID_INDEX32;
+
+
+ // It fits, so we go ahead with updating the state of watch regs
+ DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&regs));
+
+ // Storing exact address
+ hw_addr_map[index] = addr;
+ return index;
+}
+
+lldb::addr_t
+NativeRegisterContextLinux_mips64::GetWatchpointAddress (uint32_t wp_index)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return LLDB_INVALID_ADDRESS;
+
+ return hw_addr_map[wp_index];
+}
+
+struct EmulatorBaton
+{
+ lldb::addr_t m_watch_hit_addr;
+ NativeProcessLinux* m_process;
+ NativeRegisterContext* m_reg_context;
+
+ EmulatorBaton(NativeProcessLinux* process, NativeRegisterContext* reg_context) :
+ m_watch_hit_addr(LLDB_INVALID_ADDRESS),
+ m_process(process),
+ m_reg_context(reg_context)
+ {}
+};
+
+static size_t
+ReadMemoryCallback (EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context, lldb::addr_t addr,
+ void *dst, size_t length)
+{
+ size_t bytes_read;
+ EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+ emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read);
+ return bytes_read;
+}
+
+static size_t
+WriteMemoryCallback (EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr, const void *dst, size_t length)
+{
+ return length;
+}
+
+static bool
+ReadRegisterCallback (EmulateInstruction *instruction, void *baton,
+ const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+
+ const RegisterInfo* full_reg_info = emulator_baton->m_reg_context->GetRegisterInfo(
+ lldb::eRegisterKindDWARF, reg_info->kinds[lldb::eRegisterKindDWARF]);
+
+ Error error = emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value);
+ if (error.Success())
+ return true;
+
+ return false;
+}
+
+static bool
+WriteRegisterCallback (EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context,
+ const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ if (reg_info->kinds[lldb::eRegisterKindDWARF] == dwarf_bad_mips64)
+ {
+ EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+ emulator_baton->m_watch_hit_addr = reg_value.GetAsUInt64 ();
+ }
+
+ return true;
+}
+
+/*
+ * MIPS Linux kernel returns a masked address (last 3bits are masked)
+ * when a HW watchpoint is hit. However user may not have set a watchpoint
+ * on this address. Emulate instruction at PC and find the base address of
+ * the load/store instruction. This will give the exact address used to
+ * read/write the variable. Send this exact address to client so that
+ * it can decide to stop or continue the thread.
+*/
+lldb::addr_t
+NativeRegisterContextLinux_mips64::GetWatchpointHitAddress (uint32_t wp_index)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return LLDB_INVALID_ADDRESS;
+
+ lldb_private::ArchSpec arch;
+ arch = GetRegisterInfoInterface().GetTargetArchitecture();
+ std::unique_ptr<EmulateInstruction> emulator_ap(
+ EmulateInstruction::FindPlugin(arch, lldb_private::eInstructionTypeAny, nullptr));
+
+ if (emulator_ap == nullptr)
+ return LLDB_INVALID_ADDRESS;
+
+ EmulatorBaton baton(static_cast<NativeProcessLinux*>(m_thread.GetProcess().get()), this);
+ emulator_ap->SetBaton (&baton);
+ emulator_ap->SetReadMemCallback (&ReadMemoryCallback);
+ emulator_ap->SetReadRegCallback (&ReadRegisterCallback);
+ emulator_ap->SetWriteMemCallback (&WriteMemoryCallback);
+ emulator_ap->SetWriteRegCallback (&WriteRegisterCallback);
+
+ if (!emulator_ap->ReadInstruction())
+ return LLDB_INVALID_ADDRESS;
+
+ if (emulator_ap->EvaluateInstruction(lldb::eEmulateInstructionOptionNone))
+ return baton.m_watch_hit_addr;
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+uint32_t
+NativeRegisterContextLinux_mips64::NumSupportedHardwareWatchpoints ()
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ struct pt_watch_regs regs;
+ static int num_valid = 0;
+ if (!num_valid)
+ {
+ DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&regs));
+ default_watch_regs = regs; // Keeping default watch regs values for future use
+ switch (regs.style)
+ {
+ case pt_watch_style_mips32:
+ num_valid = regs.mips32.num_valid; // Using num_valid as cache
+ return num_valid;
+ case pt_watch_style_mips64:
+ num_valid = regs.mips64.num_valid;
+ return num_valid;
+ default:
+ if(log)
+ log->Printf("NativeRegisterContextLinux_mips64::%s Error: Unrecognized watch register style", __FUNCTION__);
+ }
+ return 0;
+ }
+ return num_valid;
+}
+Error
+NativeRegisterContextLinux_mips64::DoReadRegisterValue(uint32_t offset,
+ const char* reg_name,
+ uint32_t size,
+ RegisterValue &value)
+{
+ GPR_linux_mips regs;
+ ::memset(&regs, 0, sizeof(GPR_linux_mips));
+
+ // Clear all bits in RegisterValue before writing actual value read from ptrace to avoid garbage value in 32-bit MSB
+ value.SetBytes((void *)(((unsigned char *)&regs) + offset), 8, GetByteOrder());
+ Error error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), NULL, &regs, sizeof regs);
+ if (error.Success())
+ {
+ lldb_private::ArchSpec arch;
+ if (m_thread.GetProcess()->GetArchitecture(arch))
+ value.SetBytes((void *)(((unsigned char *)&regs) + offset + 4 * (arch.GetMachine() == llvm::Triple::mips)), arch.GetFlags() & lldb_private::ArchSpec::eMIPSABI_O32 ? 4 : 8, arch.GetByteOrder());
+ else
+ error.SetErrorString("failed to get architecture");
+ }
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_mips64::DoWriteRegisterValue(uint32_t offset,
+ const char* reg_name,
+ const RegisterValue &value)
+{
+ GPR_linux_mips regs;
+ Error error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), NULL, &regs, sizeof regs);
+ if (error.Success())
+ {
+ lldb_private::ArchSpec arch;
+ if (m_thread.GetProcess()->GetArchitecture(arch))
+ {
+ ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), arch.GetFlags() & lldb_private::ArchSpec::eMIPSABI_O32 ? 4 : 8);
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), NULL, &regs, sizeof regs);
+ }
+ else
+ error.SetErrorString("failed to get architecture");
+ }
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_mips64::DoReadWatchPointRegisterValue(lldb::tid_t tid, void* watch_readback)
+{
+ return NativeProcessLinux::PtraceWrapper( PTRACE_GET_WATCH_REGS, m_thread.GetID(), watch_readback);
+}
+
+Error
+NativeRegisterContextLinux_mips64::DoWriteWatchPointRegisterValue(lldb::tid_t tid, void* watch_reg_value)
+{
+ return NativeProcessLinux::PtraceWrapper(PTRACE_SET_WATCH_REGS, m_thread.GetID(), watch_reg_value);
+}
+
+#endif // defined (__mips__)
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h
new file mode 100644
index 000000000000..9368645116e9
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h
@@ -0,0 +1,167 @@
+//===-- NativeRegisterContextLinux_mips64.h ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__mips__)
+
+#ifndef lldb_NativeRegisterContextLinux_mips64_h
+#define lldb_NativeRegisterContextLinux_mips64_h
+
+#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
+#include "Plugins/Process/Utility/RegisterContext_mips.h"
+#include "Plugins/Process/Utility/lldb-mips-linux-register-enums.h"
+
+#define MAX_NUM_WP 8
+
+namespace lldb_private {
+namespace process_linux {
+
+ class NativeProcessLinux;
+
+ class NativeRegisterContextLinux_mips64 : public NativeRegisterContextLinux
+ {
+ public:
+ NativeRegisterContextLinux_mips64 (const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx);
+
+ uint32_t
+ GetRegisterSetCount () const override;
+
+ lldb::addr_t
+ GetPCfromBreakpointLocation (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS) override;
+
+ lldb::addr_t
+ GetWatchpointHitAddress (uint32_t wp_index) override;
+
+ const RegisterSet *
+ GetRegisterSet (uint32_t set_index) const override;
+
+ Error
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value) override;
+
+ Error
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
+
+ Error
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override;
+
+ Error
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
+
+ Error
+ ReadCP1();
+
+ Error
+ WriteCP1();
+
+ Error
+ IsWatchpointHit (uint32_t wp_index, bool &is_hit) override;
+
+ Error
+ GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override;
+
+ Error
+ IsWatchpointVacant (uint32_t wp_index, bool &is_vacant) override;
+
+ bool
+ ClearHardwareWatchpoint (uint32_t wp_index) override;
+
+ Error
+ ClearAllHardwareWatchpoints () override;
+
+ Error
+ SetHardwareWatchpointWithIndex (lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, uint32_t wp_index);
+
+ uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size,
+ uint32_t watch_flags) override;
+
+ lldb::addr_t
+ GetWatchpointAddress (uint32_t wp_index) override;
+
+ uint32_t
+ NumSupportedHardwareWatchpoints () override;
+
+ static bool
+ IsMSAAvailable();
+
+ protected:
+ Error
+ DoReadRegisterValue(uint32_t offset,
+ const char* reg_name,
+ uint32_t size,
+ RegisterValue &value) override;
+
+ Error
+ DoWriteRegisterValue(uint32_t offset,
+ const char* reg_name,
+ const RegisterValue &value) override;
+
+ Error
+ DoReadWatchPointRegisterValue(lldb::tid_t tid, void* watch_readback);
+
+ Error
+ DoWriteWatchPointRegisterValue(lldb::tid_t tid, void* watch_readback);
+
+ bool
+ IsFR0();
+
+ bool
+ IsFRE();
+
+ bool
+ IsFPR(uint32_t reg_index) const;
+
+ bool
+ IsMSA(uint32_t reg_index) const;
+
+ void*
+ GetGPRBuffer() override { return &m_gpr; }
+
+ void*
+ GetFPRBuffer() override { return &m_fpr; }
+
+ size_t
+ GetFPRSize() override { return sizeof(FPR_linux_mips); }
+
+ private:
+ // Info about register ranges.
+ struct RegInfo
+ {
+ uint32_t num_registers;
+ uint32_t num_gpr_registers;
+ uint32_t num_fpr_registers;
+
+ uint32_t last_gpr;
+ uint32_t first_fpr;
+ uint32_t last_fpr;
+ uint32_t first_msa;
+ uint32_t last_msa;
+ };
+
+ RegInfo m_reg_info;
+
+ GPR_linux_mips m_gpr;
+
+ FPR_linux_mips m_fpr;
+
+ MSA_linux_mips m_msa;
+
+ lldb::addr_t hw_addr_map[MAX_NUM_WP];
+
+ IOVEC_mips m_iovec;
+ };
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextLinux_mips64_h
+
+#endif // defined (__mips__)
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
new file mode 100755
index 000000000000..2080d2ede372
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
@@ -0,0 +1,1239 @@
+//===-- NativeRegisterContextLinux_x86_64.cpp ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include "NativeRegisterContextLinux_x86_64.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/HostInfo.h"
+
+#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_linux;
+
+// ----------------------------------------------------------------------------
+// Private namespace.
+// ----------------------------------------------------------------------------
+
+namespace
+{
+ // x86 32-bit general purpose registers.
+ const uint32_t
+ g_gpr_regnums_i386[] =
+ {
+ lldb_eax_i386,
+ lldb_ebx_i386,
+ lldb_ecx_i386,
+ lldb_edx_i386,
+ lldb_edi_i386,
+ lldb_esi_i386,
+ lldb_ebp_i386,
+ lldb_esp_i386,
+ lldb_eip_i386,
+ lldb_eflags_i386,
+ lldb_cs_i386,
+ lldb_fs_i386,
+ lldb_gs_i386,
+ lldb_ss_i386,
+ lldb_ds_i386,
+ lldb_es_i386,
+ lldb_ax_i386,
+ lldb_bx_i386,
+ lldb_cx_i386,
+ lldb_dx_i386,
+ lldb_di_i386,
+ lldb_si_i386,
+ lldb_bp_i386,
+ lldb_sp_i386,
+ lldb_ah_i386,
+ lldb_bh_i386,
+ lldb_ch_i386,
+ lldb_dh_i386,
+ lldb_al_i386,
+ lldb_bl_i386,
+ lldb_cl_i386,
+ lldb_dl_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - 1 == k_num_gpr_registers_i386,
+ "g_gpr_regnums_i386 has wrong number of register infos");
+
+ // x86 32-bit floating point registers.
+ const uint32_t
+ g_fpu_regnums_i386[] =
+ {
+ lldb_fctrl_i386,
+ lldb_fstat_i386,
+ lldb_ftag_i386,
+ lldb_fop_i386,
+ lldb_fiseg_i386,
+ lldb_fioff_i386,
+ lldb_foseg_i386,
+ lldb_fooff_i386,
+ lldb_mxcsr_i386,
+ lldb_mxcsrmask_i386,
+ lldb_st0_i386,
+ lldb_st1_i386,
+ lldb_st2_i386,
+ lldb_st3_i386,
+ lldb_st4_i386,
+ lldb_st5_i386,
+ lldb_st6_i386,
+ lldb_st7_i386,
+ lldb_mm0_i386,
+ lldb_mm1_i386,
+ lldb_mm2_i386,
+ lldb_mm3_i386,
+ lldb_mm4_i386,
+ lldb_mm5_i386,
+ lldb_mm6_i386,
+ lldb_mm7_i386,
+ lldb_xmm0_i386,
+ lldb_xmm1_i386,
+ lldb_xmm2_i386,
+ lldb_xmm3_i386,
+ lldb_xmm4_i386,
+ lldb_xmm5_i386,
+ lldb_xmm6_i386,
+ lldb_xmm7_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - 1 == k_num_fpr_registers_i386,
+ "g_fpu_regnums_i386 has wrong number of register infos");
+
+ // x86 32-bit AVX registers.
+ const uint32_t
+ g_avx_regnums_i386[] =
+ {
+ lldb_ymm0_i386,
+ lldb_ymm1_i386,
+ lldb_ymm2_i386,
+ lldb_ymm3_i386,
+ lldb_ymm4_i386,
+ lldb_ymm5_i386,
+ lldb_ymm6_i386,
+ lldb_ymm7_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386,
+ " g_avx_regnums_i386 has wrong number of register infos");
+
+ // x86 64-bit general purpose registers.
+ static const
+ uint32_t g_gpr_regnums_x86_64[] =
+ {
+ lldb_rax_x86_64,
+ lldb_rbx_x86_64,
+ lldb_rcx_x86_64,
+ lldb_rdx_x86_64,
+ lldb_rdi_x86_64,
+ lldb_rsi_x86_64,
+ lldb_rbp_x86_64,
+ lldb_rsp_x86_64,
+ lldb_r8_x86_64,
+ lldb_r9_x86_64,
+ lldb_r10_x86_64,
+ lldb_r11_x86_64,
+ lldb_r12_x86_64,
+ lldb_r13_x86_64,
+ lldb_r14_x86_64,
+ lldb_r15_x86_64,
+ lldb_rip_x86_64,
+ lldb_rflags_x86_64,
+ lldb_cs_x86_64,
+ lldb_fs_x86_64,
+ lldb_gs_x86_64,
+ lldb_ss_x86_64,
+ lldb_ds_x86_64,
+ lldb_es_x86_64,
+ lldb_eax_x86_64,
+ lldb_ebx_x86_64,
+ lldb_ecx_x86_64,
+ lldb_edx_x86_64,
+ lldb_edi_x86_64,
+ lldb_esi_x86_64,
+ lldb_ebp_x86_64,
+ lldb_esp_x86_64,
+ lldb_r8d_x86_64, // Low 32 bits or r8
+ lldb_r9d_x86_64, // Low 32 bits or r9
+ lldb_r10d_x86_64, // Low 32 bits or r10
+ lldb_r11d_x86_64, // Low 32 bits or r11
+ lldb_r12d_x86_64, // Low 32 bits or r12
+ lldb_r13d_x86_64, // Low 32 bits or r13
+ lldb_r14d_x86_64, // Low 32 bits or r14
+ lldb_r15d_x86_64, // Low 32 bits or r15
+ lldb_ax_x86_64,
+ lldb_bx_x86_64,
+ lldb_cx_x86_64,
+ lldb_dx_x86_64,
+ lldb_di_x86_64,
+ lldb_si_x86_64,
+ lldb_bp_x86_64,
+ lldb_sp_x86_64,
+ lldb_r8w_x86_64, // Low 16 bits or r8
+ lldb_r9w_x86_64, // Low 16 bits or r9
+ lldb_r10w_x86_64, // Low 16 bits or r10
+ lldb_r11w_x86_64, // Low 16 bits or r11
+ lldb_r12w_x86_64, // Low 16 bits or r12
+ lldb_r13w_x86_64, // Low 16 bits or r13
+ lldb_r14w_x86_64, // Low 16 bits or r14
+ lldb_r15w_x86_64, // Low 16 bits or r15
+ lldb_ah_x86_64,
+ lldb_bh_x86_64,
+ lldb_ch_x86_64,
+ lldb_dh_x86_64,
+ lldb_al_x86_64,
+ lldb_bl_x86_64,
+ lldb_cl_x86_64,
+ lldb_dl_x86_64,
+ lldb_dil_x86_64,
+ lldb_sil_x86_64,
+ lldb_bpl_x86_64,
+ lldb_spl_x86_64,
+ lldb_r8l_x86_64, // Low 8 bits or r8
+ lldb_r9l_x86_64, // Low 8 bits or r9
+ lldb_r10l_x86_64, // Low 8 bits or r10
+ lldb_r11l_x86_64, // Low 8 bits or r11
+ lldb_r12l_x86_64, // Low 8 bits or r12
+ lldb_r13l_x86_64, // Low 8 bits or r13
+ lldb_r14l_x86_64, // Low 8 bits or r14
+ lldb_r15l_x86_64, // Low 8 bits or r15
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 1 == k_num_gpr_registers_x86_64,
+ "g_gpr_regnums_x86_64 has wrong number of register infos");
+
+ // x86 64-bit floating point registers.
+ static const uint32_t
+ g_fpu_regnums_x86_64[] =
+ {
+ lldb_fctrl_x86_64,
+ lldb_fstat_x86_64,
+ lldb_ftag_x86_64,
+ lldb_fop_x86_64,
+ lldb_fiseg_x86_64,
+ lldb_fioff_x86_64,
+ lldb_foseg_x86_64,
+ lldb_fooff_x86_64,
+ lldb_mxcsr_x86_64,
+ lldb_mxcsrmask_x86_64,
+ lldb_st0_x86_64,
+ lldb_st1_x86_64,
+ lldb_st2_x86_64,
+ lldb_st3_x86_64,
+ lldb_st4_x86_64,
+ lldb_st5_x86_64,
+ lldb_st6_x86_64,
+ lldb_st7_x86_64,
+ lldb_mm0_x86_64,
+ lldb_mm1_x86_64,
+ lldb_mm2_x86_64,
+ lldb_mm3_x86_64,
+ lldb_mm4_x86_64,
+ lldb_mm5_x86_64,
+ lldb_mm6_x86_64,
+ lldb_mm7_x86_64,
+ lldb_xmm0_x86_64,
+ lldb_xmm1_x86_64,
+ lldb_xmm2_x86_64,
+ lldb_xmm3_x86_64,
+ lldb_xmm4_x86_64,
+ lldb_xmm5_x86_64,
+ lldb_xmm6_x86_64,
+ lldb_xmm7_x86_64,
+ lldb_xmm8_x86_64,
+ lldb_xmm9_x86_64,
+ lldb_xmm10_x86_64,
+ lldb_xmm11_x86_64,
+ lldb_xmm12_x86_64,
+ lldb_xmm13_x86_64,
+ lldb_xmm14_x86_64,
+ lldb_xmm15_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64,
+ "g_fpu_regnums_x86_64 has wrong number of register infos");
+
+ // x86 64-bit AVX registers.
+ static const uint32_t
+ g_avx_regnums_x86_64[] =
+ {
+ lldb_ymm0_x86_64,
+ lldb_ymm1_x86_64,
+ lldb_ymm2_x86_64,
+ lldb_ymm3_x86_64,
+ lldb_ymm4_x86_64,
+ lldb_ymm5_x86_64,
+ lldb_ymm6_x86_64,
+ lldb_ymm7_x86_64,
+ lldb_ymm8_x86_64,
+ lldb_ymm9_x86_64,
+ lldb_ymm10_x86_64,
+ lldb_ymm11_x86_64,
+ lldb_ymm12_x86_64,
+ lldb_ymm13_x86_64,
+ lldb_ymm14_x86_64,
+ lldb_ymm15_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+ };
+ static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1 == k_num_avx_registers_x86_64,
+ "g_avx_regnums_x86_64 has wrong number of register infos");
+
+ // Number of register sets provided by this context.
+ enum
+ {
+ k_num_extended_register_sets = 1,
+ k_num_register_sets = 3
+ };
+
+ // Register sets for x86 32-bit.
+ static const RegisterSet
+ g_reg_sets_i386[k_num_register_sets] =
+ {
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_i386, g_gpr_regnums_i386 },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386 },
+ { "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 }
+ };
+
+ // Register sets for x86 64-bit.
+ static const RegisterSet
+ g_reg_sets_x86_64[k_num_register_sets] =
+ {
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64 },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64 },
+ { "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 }
+ };
+}
+
+#define REG_CONTEXT_SIZE (GetRegisterInfoInterface ().GetGPRSize () + sizeof(FPR))
+
+// ----------------------------------------------------------------------------
+// Required ptrace defines.
+// ----------------------------------------------------------------------------
+
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef NT_X86_XSTATE
+#define NT_X86_XSTATE 0x202
+#endif
+#ifndef NT_PRXFPREG
+#define NT_PRXFPREG 0x46e62b7f
+#endif
+
+NativeRegisterContextLinux*
+NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx)
+{
+ return new NativeRegisterContextLinux_x86_64(target_arch, native_thread, concrete_frame_idx);
+}
+
+// ----------------------------------------------------------------------------
+// NativeRegisterContextLinux_x86_64 members.
+// ----------------------------------------------------------------------------
+
+static RegisterInfoInterface*
+CreateRegisterInfoInterface(const ArchSpec& target_arch)
+{
+ if (HostInfo::GetArchitecture().GetAddressByteSize() == 4)
+ {
+ // 32-bit hosts run with a RegisterContextLinux_i386 context.
+ return new RegisterContextLinux_i386(target_arch);
+ }
+ else
+ {
+ assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
+ "Register setting path assumes this is a 64-bit host");
+ // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context.
+ return new RegisterContextLinux_x86_64 (target_arch);
+ }
+}
+
+NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx) :
+ NativeRegisterContextLinux (native_thread, concrete_frame_idx, CreateRegisterInfoInterface(target_arch)),
+ m_fpr_type (eFPRTypeNotValid),
+ m_fpr (),
+ m_iovec (),
+ m_ymm_set (),
+ m_reg_info (),
+ m_gpr_x86_64 ()
+{
+ // Set up data about ranges of valid registers.
+ switch (target_arch.GetMachine ())
+ {
+ case llvm::Triple::x86:
+ m_reg_info.num_registers = k_num_registers_i386;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_i386;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_i386;
+ m_reg_info.num_avx_registers = k_num_avx_registers_i386;
+ m_reg_info.last_gpr = k_last_gpr_i386;
+ m_reg_info.first_fpr = k_first_fpr_i386;
+ m_reg_info.last_fpr = k_last_fpr_i386;
+ m_reg_info.first_st = lldb_st0_i386;
+ m_reg_info.last_st = lldb_st7_i386;
+ m_reg_info.first_mm = lldb_mm0_i386;
+ m_reg_info.last_mm = lldb_mm7_i386;
+ m_reg_info.first_xmm = lldb_xmm0_i386;
+ m_reg_info.last_xmm = lldb_xmm7_i386;
+ m_reg_info.first_ymm = lldb_ymm0_i386;
+ m_reg_info.last_ymm = lldb_ymm7_i386;
+ m_reg_info.first_dr = lldb_dr0_i386;
+ m_reg_info.gpr_flags = lldb_eflags_i386;
+ break;
+ case llvm::Triple::x86_64:
+ m_reg_info.num_registers = k_num_registers_x86_64;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64;
+ m_reg_info.num_avx_registers = k_num_avx_registers_x86_64;
+ m_reg_info.last_gpr = k_last_gpr_x86_64;
+ m_reg_info.first_fpr = k_first_fpr_x86_64;
+ m_reg_info.last_fpr = k_last_fpr_x86_64;
+ m_reg_info.first_st = lldb_st0_x86_64;
+ m_reg_info.last_st = lldb_st7_x86_64;
+ m_reg_info.first_mm = lldb_mm0_x86_64;
+ m_reg_info.last_mm = lldb_mm7_x86_64;
+ m_reg_info.first_xmm = lldb_xmm0_x86_64;
+ m_reg_info.last_xmm = lldb_xmm15_x86_64;
+ m_reg_info.first_ymm = lldb_ymm0_x86_64;
+ m_reg_info.last_ymm = lldb_ymm15_x86_64;
+ m_reg_info.first_dr = lldb_dr0_x86_64;
+ m_reg_info.gpr_flags = lldb_rflags_x86_64;
+ break;
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+
+ // Initialize m_iovec to point to the buffer and buffer size
+ // using the conventions of Berkeley style UIO structures, as required
+ // by PTRACE extensions.
+ m_iovec.iov_base = &m_fpr.xstate.xsave;
+ m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
+
+ // Clear out the FPR state.
+ ::memset(&m_fpr, 0, sizeof(FPR));
+
+ // Store byte offset of fctrl (i.e. first register of FPR)
+ const RegisterInfo *reg_info_fctrl = GetRegisterInfoByName("fctrl");
+ m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset;
+}
+
+// CONSIDER after local and llgs debugging are merged, register set support can
+// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
+uint32_t
+NativeRegisterContextLinux_x86_64::GetRegisterSetCount () const
+{
+ uint32_t sets = 0;
+ for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
+ {
+ if (IsRegisterSetAvailable (set_index))
+ ++sets;
+ }
+
+ return sets;
+}
+
+uint32_t
+NativeRegisterContextLinux_x86_64::GetUserRegisterCount() const
+{
+ uint32_t count = 0;
+ for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
+ {
+ const RegisterSet* set = GetRegisterSet(set_index);
+ if (set)
+ count += set->num_registers;
+ }
+ return count;
+}
+
+const RegisterSet *
+NativeRegisterContextLinux_x86_64::GetRegisterSet (uint32_t set_index) const
+{
+ if (!IsRegisterSetAvailable (set_index))
+ return nullptr;
+
+ switch (GetRegisterInfoInterface ().GetTargetArchitecture ().GetMachine ())
+ {
+ case llvm::Triple::x86:
+ return &g_reg_sets_i386[set_index];
+ case llvm::Triple::x86_64:
+ return &g_reg_sets_x86_64[set_index];
+ default:
+ assert (false && "Unhandled target architecture.");
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+Error
+NativeRegisterContextLinux_x86_64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ Error error;
+
+ if (!reg_info)
+ {
+ error.SetErrorString ("reg_info NULL");
+ return error;
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM)
+ {
+ // This is likely an internal register for lldb use only and should not be directly queried.
+ error.SetErrorStringWithFormat ("register \"%s\" is an internal-only lldb register, cannot read directly", reg_info->name);
+ return error;
+ }
+
+ if (IsFPR(reg, GetFPRType()))
+ {
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+ }
+ else
+ {
+ uint32_t full_reg = reg;
+ bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
+
+ if (is_subreg)
+ {
+ // Read the full aligned 64-bit register.
+ full_reg = reg_info->invalidate_regs[0];
+ }
+
+ error = ReadRegisterRaw(full_reg, reg_value);
+
+ if (error.Success ())
+ {
+ // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
+ if (is_subreg && (reg_info->byte_offset & 0x1))
+ reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
+
+ // If our return byte size was greater than the return value reg size, then
+ // use the type specified by reg_info rather than the uint64_t default
+ if (reg_value.GetByteSize() > reg_info->byte_size)
+ reg_value.SetType(reg_info);
+ }
+ return error;
+ }
+
+ if (reg_info->encoding == lldb::eEncodingVector)
+ {
+ lldb::ByteOrder byte_order = GetByteOrder();
+
+ if (byte_order != lldb::eByteOrderInvalid)
+ {
+ if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
+ reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order);
+ if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
+ reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order);
+ if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
+ reg_value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order);
+ if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm)
+ {
+ // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
+ if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoYMM(reg, byte_order))
+ reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order);
+ else
+ {
+ error.SetErrorString ("failed to copy ymm register value");
+ return error;
+ }
+ }
+
+ if (reg_value.GetType() != RegisterValue::eTypeBytes)
+ error.SetErrorString ("write failed - type was expected to be RegisterValue::eTypeBytes");
+
+ return error;
+ }
+
+ error.SetErrorString ("byte order is invalid");
+ return error;
+ }
+
+ // Get pointer to m_fpr.xstate.fxsave variable and set the data from it.
+
+ // Byte offsets of all registers are calculated wrt 'UserArea' structure.
+ // However, ReadFPR() reads fpu registers {using ptrace(PTRACE_GETFPREGS,..)}
+ // and stores them in 'm_fpr' (of type FPR structure). To extract values of fpu
+ // registers, m_fpr should be read at byte offsets calculated wrt to FPR structure.
+
+ // Since, FPR structure is also one of the member of UserArea structure.
+ // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - byte_offset(fctrl wrt UserArea)
+ assert ( (reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr));
+ uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea;
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ reg_value.SetUInt8(*(uint8_t *)src);
+ break;
+ case 2:
+ reg_value.SetUInt16(*(uint16_t *)src);
+ break;
+ case 4:
+ reg_value.SetUInt32(*(uint32_t *)src);
+ break;
+ case 8:
+ reg_value.SetUInt64(*(uint64_t *)src);
+ break;
+ default:
+ assert(false && "Unhandled data size.");
+ error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
+ break;
+ }
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ assert (reg_info && "reg_info is null");
+
+ const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg_index == LLDB_INVALID_REGNUM)
+ return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
+
+ if (IsGPR(reg_index))
+ return WriteRegisterRaw(reg_index, reg_value);
+
+ if (IsFPR(reg_index, GetFPRType()))
+ {
+ if (reg_info->encoding == lldb::eEncodingVector)
+ {
+ if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st)
+ ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_st].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+
+ if (reg_index >= m_reg_info.first_mm && reg_index <= m_reg_info.last_mm)
+ ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_mm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+
+ if (reg_index >= m_reg_info.first_xmm && reg_index <= m_reg_info.last_xmm)
+ ::memcpy (m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_xmm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+
+ if (reg_index >= m_reg_info.first_ymm && reg_index <= m_reg_info.last_ymm)
+ {
+ if (GetFPRType() != eFPRTypeXSAVE)
+ return Error ("target processor does not support AVX");
+
+ // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
+ ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+ if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
+ return Error ("CopyYMMtoXSTATE() failed");
+ }
+ }
+ else
+ {
+ // Get pointer to m_fpr.xstate.fxsave variable and set the data to it.
+
+ // Byte offsets of all registers are calculated wrt 'UserArea' structure.
+ // However, WriteFPR() takes m_fpr (of type FPR structure) and writes only fpu
+ // registers using ptrace(PTRACE_SETFPREGS,..) API. Hence fpu registers should
+ // be written in m_fpr at byte offsets calculated wrt FPR structure.
+
+ // Since, FPR structure is also one of the member of UserArea structure.
+ // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - byte_offset(fctrl wrt UserArea)
+ assert ( (reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr));
+ uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea;
+ switch (reg_info->byte_size)
+ {
+ case 1:
+ *(uint8_t *)dst = reg_value.GetAsUInt8();
+ break;
+ case 2:
+ *(uint16_t *)dst = reg_value.GetAsUInt16();
+ break;
+ case 4:
+ *(uint32_t *)dst = reg_value.GetAsUInt32();
+ break;
+ case 8:
+ *(uint64_t *)dst = reg_value.GetAsUInt64();
+ break;
+ default:
+ assert(false && "Unhandled data size.");
+ return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
+ }
+ }
+
+ Error error = WriteFPR();
+ if (error.Fail())
+ return error;
+
+ if (IsAVX(reg_index))
+ {
+ if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
+ return Error ("CopyYMMtoXSTATE() failed");
+ }
+ return Error ();
+ }
+ return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
+}
+
+Error
+NativeRegisterContextLinux_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ Error error;
+
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (!data_sp)
+ {
+ error.SetErrorStringWithFormat ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ error = ReadGPR();
+ if (error.Fail())
+ return error;
+
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+
+ uint8_t *dst = data_sp->GetBytes ();
+ if (dst == nullptr)
+ {
+ error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ ::memcpy (dst, &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ());
+ dst += GetRegisterInfoInterface ().GetGPRSize ();
+ if (GetFPRType () == eFPRTypeFXSAVE)
+ ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+ else if (GetFPRType () == eFPRTypeXSAVE)
+ {
+ lldb::ByteOrder byte_order = GetByteOrder ();
+
+ // Assemble the YMM register content from the register halves.
+ for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
+ {
+ if (!CopyXSTATEtoYMM (reg, byte_order))
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyXSTATEtoYMM() failed for reg num %" PRIu32, __FUNCTION__, reg);
+ return error;
+ }
+ }
+
+ // Copy the extended register state including the assembled ymm registers.
+ ::memcpy (dst, &m_fpr, sizeof (m_fpr));
+ }
+ else
+ {
+ assert (false && "how do we save the floating point registers?");
+ error.SetErrorString ("unsure how to save the floating point registers");
+ }
+ /** The following code is specific to Linux x86 based architectures,
+ * where the register orig_eax (32 bit)/orig_rax (64 bit) is set to
+ * -1 to solve the bug 23659, such a setting prevents the automatic
+ * decrement of the instruction pointer which was causing the SIGILL
+ * exception.
+ * **/
+
+ RegisterValue value((uint64_t) -1);
+ const RegisterInfo *reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax");
+ if (reg_info == nullptr)
+ reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax");
+
+ if (reg_info != nullptr)
+ return DoWriteRegisterValue(reg_info->byte_offset,reg_info->name,value);
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ Error error;
+
+ if (!data_sp)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
+ return error;
+ }
+
+
+ uint8_t *src = data_sp->GetBytes ();
+ if (src == nullptr)
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
+ return error;
+ }
+ ::memcpy (&m_gpr_x86_64, src, GetRegisterInfoInterface ().GetGPRSize ());
+
+ error = WriteGPR();
+ if (error.Fail())
+ return error;
+
+ src += GetRegisterInfoInterface ().GetGPRSize ();
+ if (GetFPRType () == eFPRTypeFXSAVE)
+ ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
+ else if (GetFPRType () == eFPRTypeXSAVE)
+ ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
+
+ error = WriteFPR();
+ if (error.Fail())
+ return error;
+
+ if (GetFPRType() == eFPRTypeXSAVE)
+ {
+ lldb::ByteOrder byte_order = GetByteOrder();
+
+ // Parse the YMM register content from the register halves.
+ for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
+ {
+ if (!CopyYMMtoXSTATE (reg, byte_order))
+ {
+ error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyYMMtoXSTATE() failed for reg num %" PRIu32, __FUNCTION__, reg);
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable (uint32_t set_index) const
+{
+ // Note: Extended register sets are assumed to be at the end of g_reg_sets.
+ uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets;
+
+ if (GetFPRType () == eFPRTypeXSAVE)
+ {
+ // AVX is the first extended register set.
+ ++num_sets;
+ }
+ return (set_index < num_sets);
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const
+{
+ // GPRs come first.
+ return reg_index <= m_reg_info.last_gpr;
+}
+
+NativeRegisterContextLinux_x86_64::FPRType
+NativeRegisterContextLinux_x86_64::GetFPRType () const
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (m_fpr_type == eFPRTypeNotValid)
+ {
+ // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx.
+
+ // Try and see if AVX register retrieval works.
+ m_fpr_type = eFPRTypeXSAVE;
+ if (const_cast<NativeRegisterContextLinux_x86_64*>(this)->ReadFPR().Fail())
+ {
+ // Fall back to general floating point with no AVX support.
+ m_fpr_type = eFPRTypeFXSAVE;
+
+ // Check if FXSAVE area can be read.
+ if (const_cast<NativeRegisterContextLinux_x86_64*>(this)->ReadFPR().Fail())
+ {
+ if (log)
+ log->Printf("NativeRegisterContextLinux_x86_64::%s ptrace APIs failed to read XSAVE/FXSAVE area", __FUNCTION__);
+ }
+ }
+ }
+ return m_fpr_type;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const
+{
+ return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr);
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index, FPRType fpr_type) const
+{
+ bool generic_fpr = IsFPR(reg_index);
+
+ if (fpr_type == eFPRTypeXSAVE)
+ return generic_fpr || IsAVX(reg_index);
+ return generic_fpr;
+}
+
+Error
+NativeRegisterContextLinux_x86_64::WriteFPR()
+{
+ const FPRType fpr_type = GetFPRType ();
+ const lldb_private::ArchSpec& target_arch = GetRegisterInfoInterface().GetTargetArchitecture();
+ switch (fpr_type)
+ {
+ case FPRType::eFPRTypeFXSAVE:
+ // For 32-bit inferiors on x86_32/x86_64 architectures,
+ // FXSAVE area can be written using PTRACE_SETREGSET ptrace api
+ // For 64-bit inferiors on x86_64 architectures,
+ // FXSAVE area can be written using PTRACE_SETFPREGS ptrace api
+ switch (target_arch.GetMachine ())
+ {
+ case llvm::Triple::x86:
+ return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_PRXFPREG);
+ case llvm::Triple::x86_64:
+ return NativeRegisterContextLinux::WriteFPR();
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+ case FPRType::eFPRTypeXSAVE:
+ return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
+ default:
+ return Error("Unrecognized FPR type");
+ }
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsAVX(uint32_t reg_index) const
+{
+ return (m_reg_info.first_ymm <= reg_index && reg_index <= m_reg_info.last_ymm);
+}
+
+bool
+NativeRegisterContextLinux_x86_64::CopyXSTATEtoYMM (uint32_t reg_index, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX (reg_index))
+ return false;
+
+ if (byte_order == lldb::eByteOrderLittle)
+ {
+ ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
+ m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
+ sizeof (XMMReg));
+ ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
+ m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
+ sizeof (YMMHReg));
+ return true;
+ }
+
+ if (byte_order == lldb::eByteOrderBig)
+ {
+ ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
+ m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
+ sizeof (XMMReg));
+ ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
+ m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
+ sizeof (YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+
+}
+
+bool
+NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == lldb::eByteOrderLittle)
+ {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
+ sizeof(XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
+ sizeof(YMMHReg));
+ return true;
+ }
+
+ if (byte_order == lldb::eByteOrderBig)
+ {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
+ sizeof(XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
+ sizeof(YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+}
+
+void*
+NativeRegisterContextLinux_x86_64::GetFPRBuffer()
+{
+ const FPRType fpr_type = GetFPRType ();
+ switch (fpr_type)
+ {
+ case FPRType::eFPRTypeFXSAVE:
+ return &m_fpr.xstate.fxsave;
+ case FPRType::eFPRTypeXSAVE:
+ return &m_iovec;
+ default:
+ return nullptr;
+ }
+}
+
+size_t
+NativeRegisterContextLinux_x86_64::GetFPRSize()
+{
+ const FPRType fpr_type = GetFPRType ();
+ switch (fpr_type)
+ {
+ case FPRType::eFPRTypeFXSAVE:
+ return sizeof(m_fpr.xstate.fxsave);
+ case FPRType::eFPRTypeXSAVE:
+ return sizeof(m_iovec);
+ default:
+ return 0;
+ }
+}
+
+Error
+NativeRegisterContextLinux_x86_64::ReadFPR ()
+{
+ const FPRType fpr_type = GetFPRType ();
+ const lldb_private::ArchSpec& target_arch = GetRegisterInfoInterface().GetTargetArchitecture();
+ switch (fpr_type)
+ {
+ case FPRType::eFPRTypeFXSAVE:
+ // For 32-bit inferiors on x86_32/x86_64 architectures,
+ // FXSAVE area can be read using PTRACE_GETREGSET ptrace api
+ // For 64-bit inferiors on x86_64 architectures,
+ // FXSAVE area can be read using PTRACE_GETFPREGS ptrace api
+ switch (target_arch.GetMachine ())
+ {
+ case llvm::Triple::x86:
+ return ReadRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_PRXFPREG);
+ case llvm::Triple::x86_64:
+ return NativeRegisterContextLinux::ReadFPR();
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+ case FPRType::eFPRTypeXSAVE:
+ return ReadRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
+ default:
+ return Error("Unrecognized FPR type");
+ }
+}
+
+Error
+NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint32_t wp_index, bool &is_hit)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Error("Watchpoint index out of range");
+
+ RegisterValue reg_value;
+ Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
+ if (error.Fail())
+ {
+ is_hit = false;
+ return error;
+ }
+
+ uint64_t status_bits = reg_value.GetAsUInt64();
+
+ is_hit = status_bits & (1 << wp_index);
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_x86_64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) {
+ uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+ for (wp_index = 0; wp_index < num_hw_wps; ++wp_index)
+ {
+ bool is_hit;
+ Error error = IsWatchpointHit(wp_index, is_hit);
+ if (error.Fail()) {
+ wp_index = LLDB_INVALID_INDEX32;
+ return error;
+ } else if (is_hit) {
+ return error;
+ }
+ }
+ wp_index = LLDB_INVALID_INDEX32;
+ return Error();
+}
+
+Error
+NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index, bool &is_vacant)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Error ("Watchpoint index out of range");
+
+ RegisterValue reg_value;
+ Error error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
+ if (error.Fail())
+ {
+ is_vacant = false;
+ return error;
+ }
+
+ uint64_t control_bits = reg_value.GetAsUInt64();
+
+ is_vacant = !(control_bits & (1 << (2 * wp_index)));
+
+ return error;
+}
+
+Error
+NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
+
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Error ("Watchpoint index out of range");
+
+ // Read only watchpoints aren't supported on x86_64. Fall back to read/write waitchpoints instead.
+ // TODO: Add logic to detect when a write happens and ignore that watchpoint hit.
+ if (watch_flags == 0x2)
+ watch_flags = 0x3;
+
+ if (watch_flags != 0x1 && watch_flags != 0x3)
+ return Error ("Invalid read/write bits for watchpoint");
+
+ if (size != 1 && size != 2 && size != 4 && size != 8)
+ return Error ("Invalid size for watchpoint");
+
+ bool is_vacant;
+ Error error = IsWatchpointVacant (wp_index, is_vacant);
+ if (error.Fail()) return error;
+ if (!is_vacant) return Error("Watchpoint index not vacant");
+
+ RegisterValue reg_value;
+ error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
+ if (error.Fail()) return error;
+
+ // for watchpoints 0, 1, 2, or 3, respectively,
+ // set bits 1, 3, 5, or 7
+ uint64_t enable_bit = 1 << (2 * wp_index);
+
+ // set bits 16-17, 20-21, 24-25, or 28-29
+ // with 0b01 for write, and 0b11 for read/write
+ uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
+
+ // set bits 18-19, 22-23, 26-27, or 30-31
+ // with 0b00, 0b01, 0b10, or 0b11
+ // for 1, 2, 8 (if supported), or 4 bytes, respectively
+ uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
+
+ uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
+
+ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+
+ control_bits |= enable_bit | rw_bits | size_bits;
+
+ error = WriteRegisterRaw(m_reg_info.first_dr + wp_index, RegisterValue(addr));
+ if (error.Fail()) return error;
+
+ error = WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
+ if (error.Fail()) return error;
+
+ error.Clear();
+ return error;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint(uint32_t wp_index)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return false;
+
+ RegisterValue reg_value;
+
+ // for watchpoints 0, 1, 2, or 3, respectively,
+ // clear bits 0, 1, 2, or 3 of the debug status register (DR6)
+ Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
+ if (error.Fail()) return false;
+ uint64_t bit_mask = 1 << wp_index;
+ uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
+ if (error.Fail()) return false;
+
+ // for watchpoints 0, 1, 2, or 3, respectively,
+ // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31}
+ // of the debug control register (DR7)
+ error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
+ if (error.Fail()) return false;
+ bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
+ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits)).Success();
+}
+
+Error
+NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints()
+{
+ RegisterValue reg_value;
+
+ // clear bits {0-4} of the debug status register (DR6)
+ Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
+ if (error.Fail()) return error;
+ uint64_t bit_mask = 0xF;
+ uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
+ if (error.Fail()) return error;
+
+ // clear bits {0-7,16-31} of the debug control register (DR7)
+ error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
+ if (error.Fail()) return error;
+ bit_mask = 0xFF | (0xFFFF << 16);
+ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
+}
+
+uint32_t
+NativeRegisterContextLinux_x86_64::SetHardwareWatchpoint(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index)
+ {
+ bool is_vacant;
+ Error error = IsWatchpointVacant(wp_index, is_vacant);
+ if (is_vacant)
+ {
+ error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
+ if (error.Success())
+ return wp_index;
+ }
+ if (error.Fail() && log)
+ {
+ log->Printf("NativeRegisterContextLinux_x86_64::%s Error: %s",
+ __FUNCTION__, error.AsCString());
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+lldb::addr_t
+NativeRegisterContextLinux_x86_64::GetWatchpointAddress(uint32_t wp_index)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return LLDB_INVALID_ADDRESS;
+ RegisterValue reg_value;
+ if (ReadRegisterRaw(m_reg_info.first_dr + wp_index, reg_value).Fail())
+ return LLDB_INVALID_ADDRESS;
+ return reg_value.GetAsUInt64();
+}
+
+uint32_t
+NativeRegisterContextLinux_x86_64::NumSupportedHardwareWatchpoints ()
+{
+ // Available debug address registers: dr0, dr1, dr2, dr3
+ return 4;
+}
+
+#endif // defined(__i386__) || defined(__x86_64__)
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
new file mode 100644
index 000000000000..b04be4bb7688
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
@@ -0,0 +1,171 @@
+//===-- NativeRegisterContextLinux_x86_64.h ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifndef lldb_NativeRegisterContextLinux_x86_64_h
+#define lldb_NativeRegisterContextLinux_x86_64_h
+
+#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
+#include "Plugins/Process/Utility/RegisterContext_x86.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+namespace lldb_private {
+namespace process_linux {
+
+ class NativeProcessLinux;
+
+ class NativeRegisterContextLinux_x86_64 : public NativeRegisterContextLinux
+ {
+ public:
+ NativeRegisterContextLinux_x86_64 (const ArchSpec& target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx);
+
+ uint32_t
+ GetRegisterSetCount () const override;
+
+ const RegisterSet *
+ GetRegisterSet (uint32_t set_index) const override;
+
+ uint32_t
+ GetUserRegisterCount() const override;
+
+ Error
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value) override;
+
+ Error
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
+
+ Error
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override;
+
+ Error
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
+
+ Error
+ IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
+
+ Error
+ GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override;
+
+ Error
+ IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
+
+ bool
+ ClearHardwareWatchpoint(uint32_t wp_index) override;
+
+ Error
+ ClearAllHardwareWatchpoints () override;
+
+ Error
+ SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, uint32_t wp_index);
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags) override;
+
+ lldb::addr_t
+ GetWatchpointAddress(uint32_t wp_index) override;
+
+ uint32_t
+ NumSupportedHardwareWatchpoints() override;
+
+ protected:
+ void*
+ GetGPRBuffer() override { return &m_gpr_x86_64; }
+
+ void*
+ GetFPRBuffer() override;
+
+ size_t
+ GetFPRSize() override;
+
+ Error
+ ReadFPR() override;
+
+ Error
+ WriteFPR() override;
+
+ private:
+
+ // Private member types.
+ enum FPRType
+ {
+ eFPRTypeNotValid = 0,
+ eFPRTypeFXSAVE,
+ eFPRTypeXSAVE
+ };
+
+ // Info about register ranges.
+ struct RegInfo
+ {
+ uint32_t num_registers;
+ uint32_t num_gpr_registers;
+ uint32_t num_fpr_registers;
+ uint32_t num_avx_registers;
+
+ uint32_t last_gpr;
+ uint32_t first_fpr;
+ uint32_t last_fpr;
+
+ uint32_t first_st;
+ uint32_t last_st;
+ uint32_t first_mm;
+ uint32_t last_mm;
+ uint32_t first_xmm;
+ uint32_t last_xmm;
+ uint32_t first_ymm;
+ uint32_t last_ymm;
+
+ uint32_t first_dr;
+ uint32_t gpr_flags;
+ };
+
+ // Private member variables.
+ mutable FPRType m_fpr_type;
+ FPR m_fpr;
+ IOVEC m_iovec;
+ YMM m_ymm_set;
+ RegInfo m_reg_info;
+ uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64];
+ uint32_t m_fctrl_offset_in_userarea;
+
+ // Private member methods.
+ bool IsRegisterSetAvailable (uint32_t set_index) const;
+
+ bool
+ IsGPR(uint32_t reg_index) const;
+
+ FPRType
+ GetFPRType () const;
+
+ bool
+ IsFPR(uint32_t reg_index) const;
+
+ bool
+ IsFPR(uint32_t reg_index, FPRType fpr_type) const;
+
+ bool
+ CopyXSTATEtoYMM (uint32_t reg_index, lldb::ByteOrder byte_order);
+
+ bool
+ CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
+
+ bool
+ IsAVX (uint32_t reg_index) const;
+ };
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextLinux_x86_64_h
+
+#endif // defined(__i386__) || defined(__x86_64__)
diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/source/Plugins/Process/Linux/NativeThreadLinux.cpp
new file mode 100644
index 000000000000..cbf82885e23a
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -0,0 +1,440 @@
+//===-- NativeThreadLinux.cpp --------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadLinux.h"
+
+#include <signal.h>
+#include <sstream>
+
+#include "NativeProcessLinux.h"
+#include "NativeRegisterContextLinux.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/HostNativeThread.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "llvm/ADT/SmallString.h"
+
+#include "Plugins/Process/POSIX/CrashReason.h"
+
+#include <sys/syscall.h>
+// Try to define a macro to encapsulate the tgkill syscall
+#define tgkill(pid, tid, sig) \
+ syscall(SYS_tgkill, static_cast< ::pid_t>(pid), static_cast< ::pid_t>(tid), sig)
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_linux;
+
+namespace
+{
+ void LogThreadStopInfo (Log &log, const ThreadStopInfo &stop_info, const char *const header)
+ {
+ switch (stop_info.reason)
+ {
+ case eStopReasonNone:
+ log.Printf ("%s: %s no stop reason", __FUNCTION__, header);
+ return;
+ case eStopReasonTrace:
+ log.Printf ("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo);
+ return;
+ case eStopReasonBreakpoint:
+ log.Printf ("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo);
+ return;
+ case eStopReasonWatchpoint:
+ log.Printf ("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo);
+ return;
+ case eStopReasonSignal:
+ log.Printf ("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo);
+ return;
+ case eStopReasonException:
+ log.Printf ("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header, stop_info.details.exception.type);
+ return;
+ case eStopReasonExec:
+ log.Printf ("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo);
+ return;
+ case eStopReasonPlanComplete:
+ log.Printf ("%s: %s plan complete", __FUNCTION__, header);
+ return;
+ case eStopReasonThreadExiting:
+ log.Printf ("%s: %s thread exiting", __FUNCTION__, header);
+ return;
+ case eStopReasonInstrumentation:
+ log.Printf ("%s: %s instrumentation", __FUNCTION__, header);
+ return;
+ default:
+ log.Printf ("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header, static_cast<uint32_t> (stop_info.reason));
+ }
+ }
+}
+
+NativeThreadLinux::NativeThreadLinux (NativeProcessLinux *process, lldb::tid_t tid) :
+ NativeThreadProtocol (process, tid),
+ m_state (StateType::eStateInvalid),
+ m_stop_info (),
+ m_reg_context_sp (),
+ m_stop_description ()
+{
+}
+
+std::string
+NativeThreadLinux::GetName()
+{
+ NativeProcessProtocolSP process_sp = m_process_wp.lock ();
+ if (!process_sp)
+ return "<unknown: no process>";
+
+ // const NativeProcessLinux *const process = reinterpret_cast<NativeProcessLinux*> (process_sp->get ());
+ llvm::SmallString<32> thread_name;
+ HostNativeThread::GetName(GetID(), thread_name);
+ return thread_name.c_str();
+}
+
+lldb::StateType
+NativeThreadLinux::GetState ()
+{
+ return m_state;
+}
+
+
+bool
+NativeThreadLinux::GetStopReason (ThreadStopInfo &stop_info, std::string& description)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ description.clear();
+
+ switch (m_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ case eStateUnloaded:
+ if (log)
+ LogThreadStopInfo (*log, m_stop_info, "m_stop_info in thread:");
+ stop_info = m_stop_info;
+ description = m_stop_description;
+ if (log)
+ LogThreadStopInfo (*log, stop_info, "returned stop_info:");
+
+ return true;
+
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ if (log)
+ {
+ log->Printf ("NativeThreadLinux::%s tid %" PRIu64 " in state %s cannot answer stop reason",
+ __FUNCTION__, GetID (), StateAsCString (m_state));
+ }
+ return false;
+ }
+ llvm_unreachable("unhandled StateType!");
+}
+
+NativeRegisterContextSP
+NativeThreadLinux::GetRegisterContext ()
+{
+ // Return the register context if we already created it.
+ if (m_reg_context_sp)
+ return m_reg_context_sp;
+
+ NativeProcessProtocolSP m_process_sp = m_process_wp.lock ();
+ if (!m_process_sp)
+ return NativeRegisterContextSP ();
+
+ ArchSpec target_arch;
+ if (!m_process_sp->GetArchitecture (target_arch))
+ return NativeRegisterContextSP ();
+
+ const uint32_t concrete_frame_idx = 0;
+ m_reg_context_sp.reset (NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(target_arch,
+ *this,
+ concrete_frame_idx));
+
+ return m_reg_context_sp;
+}
+
+Error
+NativeThreadLinux::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
+{
+ if (!hardware)
+ return Error ("not implemented");
+ if (m_state == eStateLaunching)
+ return Error ();
+ Error error = RemoveWatchpoint(addr);
+ if (error.Fail()) return error;
+ NativeRegisterContextSP reg_ctx = GetRegisterContext ();
+ uint32_t wp_index =
+ reg_ctx->SetHardwareWatchpoint (addr, size, watch_flags);
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return Error ("Setting hardware watchpoint failed.");
+ m_watchpoint_index_map.insert({addr, wp_index});
+ return Error ();
+}
+
+Error
+NativeThreadLinux::RemoveWatchpoint (lldb::addr_t addr)
+{
+ auto wp = m_watchpoint_index_map.find(addr);
+ if (wp == m_watchpoint_index_map.end())
+ return Error ();
+ uint32_t wp_index = wp->second;
+ m_watchpoint_index_map.erase(wp);
+ if (GetRegisterContext()->ClearHardwareWatchpoint(wp_index))
+ return Error ();
+ return Error ("Clearing hardware watchpoint failed.");
+}
+
+void
+NativeThreadLinux::SetRunning ()
+{
+ const StateType new_state = StateType::eStateRunning;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+ m_stop_description.clear();
+
+ // If watchpoints have been set, but none on this thread,
+ // then this is a new thread. So set all existing watchpoints.
+ if (m_watchpoint_index_map.empty())
+ {
+ const auto process_sp = GetProcess();
+ if (process_sp)
+ {
+ const auto &watchpoint_map = process_sp->GetWatchpointMap();
+ if (watchpoint_map.empty()) return;
+ GetRegisterContext()->ClearAllHardwareWatchpoints();
+ for (const auto &pair : watchpoint_map)
+ {
+ const auto& wp = pair.second;
+ SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware);
+ }
+ }
+ }
+}
+
+void
+NativeThreadLinux::SetStepping ()
+{
+ const StateType new_state = StateType::eStateStepping;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void
+NativeThreadLinux::SetStoppedBySignal(uint32_t signo, const siginfo_t *info)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("NativeThreadLinux::%s called with signal 0x%02" PRIx32, __FUNCTION__, signo);
+
+ const StateType new_state = StateType::eStateStopped;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.details.signal.signo = signo;
+
+ m_stop_description.clear();
+ if (info)
+ {
+ switch (signo)
+ {
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ //In case of MIPS64 target, SI_KERNEL is generated for invalid 64bit address.
+ const auto reason = (info->si_signo == SIGBUS && info->si_code == SI_KERNEL) ?
+ CrashReason::eInvalidAddress : GetCrashReason(*info);
+ m_stop_description = GetCrashReasonString(reason, reinterpret_cast<uintptr_t>(info->si_addr));
+ break;
+ }
+ }
+}
+
+bool
+NativeThreadLinux::IsStopped (int *signo)
+{
+ if (!StateIsStoppedState (m_state, false))
+ return false;
+
+ // If we are stopped by a signal, return the signo.
+ if (signo &&
+ m_state == StateType::eStateStopped &&
+ m_stop_info.reason == StopReason::eStopReasonSignal)
+ {
+ *signo = m_stop_info.details.signal.signo;
+ }
+
+ // Regardless, we are stopped.
+ return true;
+}
+
+
+void
+NativeThreadLinux::SetStoppedByExec ()
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("NativeThreadLinux::%s()", __FUNCTION__);
+
+ const StateType new_state = StateType::eStateStopped;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonExec;
+ m_stop_info.details.signal.signo = SIGSTOP;
+}
+
+void
+NativeThreadLinux::SetStoppedByBreakpoint ()
+{
+ const StateType new_state = StateType::eStateStopped;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonBreakpoint;
+ m_stop_info.details.signal.signo = SIGTRAP;
+ m_stop_description.clear();
+}
+
+void
+NativeThreadLinux::SetStoppedByWatchpoint (uint32_t wp_index)
+{
+ const StateType new_state = StateType::eStateStopped;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+ m_stop_description.clear ();
+
+ lldbassert(wp_index != LLDB_INVALID_INDEX32 &&
+ "wp_index cannot be invalid");
+
+ std::ostringstream ostr;
+ ostr << GetRegisterContext()->GetWatchpointAddress(wp_index) << " ";
+ ostr << wp_index;
+
+ /*
+ * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For example:
+ * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at 'm', then
+ * watch exception is generated even when 'n' is read/written. To handle this case,
+ * find the base address of the load/store instruction and append it in the stop-info
+ * packet.
+ */
+ ostr << " " << GetRegisterContext()->GetWatchpointHitAddress(wp_index);
+
+ m_stop_description = ostr.str();
+
+ m_stop_info.reason = StopReason::eStopReasonWatchpoint;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+bool
+NativeThreadLinux::IsStoppedAtBreakpoint ()
+{
+ return GetState () == StateType::eStateStopped &&
+ m_stop_info.reason == StopReason::eStopReasonBreakpoint;
+}
+
+bool
+NativeThreadLinux::IsStoppedAtWatchpoint ()
+{
+ return GetState () == StateType::eStateStopped &&
+ m_stop_info.reason == StopReason::eStopReasonWatchpoint;
+}
+
+void
+NativeThreadLinux::SetStoppedByTrace ()
+{
+ const StateType new_state = StateType::eStateStopped;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonTrace;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void
+NativeThreadLinux::SetStoppedWithNoReason ()
+{
+ const StateType new_state = StateType::eStateStopped;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+ m_stop_info.details.signal.signo = 0;
+}
+
+void
+NativeThreadLinux::SetExited ()
+{
+ const StateType new_state = StateType::eStateExited;
+ MaybeLogStateChange (new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonThreadExiting;
+}
+
+Error
+NativeThreadLinux::RequestStop ()
+{
+ Log* log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ const auto process_sp = GetProcess();
+ if (! process_sp)
+ return Error("Process is null.");
+
+ lldb::pid_t pid = process_sp->GetID();
+ lldb::tid_t tid = GetID();
+
+ if (log)
+ log->Printf ("NativeThreadLinux::%s requesting thread stop(pid: %" PRIu64 ", tid: %" PRIu64 ")", __FUNCTION__, pid, tid);
+
+ Error err;
+ errno = 0;
+ if (::tgkill (pid, tid, SIGSTOP) != 0)
+ {
+ err.SetErrorToErrno ();
+ if (log)
+ log->Printf ("NativeThreadLinux::%s tgkill(%" PRIu64 ", %" PRIu64 ", SIGSTOP) failed: %s", __FUNCTION__, pid, tid, err.AsCString ());
+ }
+
+ return err;
+}
+
+void
+NativeThreadLinux::MaybeLogStateChange (lldb::StateType new_state)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ // If we're not logging, we're done.
+ if (!log)
+ return;
+
+ // If this is a state change to the same state, we're done.
+ lldb::StateType old_state = m_state;
+ if (new_state == old_state)
+ return;
+
+ NativeProcessProtocolSP m_process_sp = m_process_wp.lock ();
+ lldb::pid_t pid = m_process_sp ? m_process_sp->GetID () : LLDB_INVALID_PROCESS_ID;
+
+ // Log it.
+ log->Printf ("NativeThreadLinux: thread (pid=%" PRIu64 ", tid=%" PRIu64 ") changing from state %s to %s", pid, GetID (), StateAsCString (old_state), StateAsCString (new_state));
+}
diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.h b/source/Plugins/Process/Linux/NativeThreadLinux.h
new file mode 100644
index 000000000000..bf6b00a78cfd
--- /dev/null
+++ b/source/Plugins/Process/Linux/NativeThreadLinux.h
@@ -0,0 +1,120 @@
+//===-- NativeThreadLinux.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_NativeThreadLinux_H_
+#define liblldb_NativeThreadLinux_H_
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+namespace lldb_private {
+namespace process_linux {
+
+ class NativeProcessLinux;
+
+ class NativeThreadLinux : public NativeThreadProtocol
+ {
+ friend class NativeProcessLinux;
+
+ public:
+ NativeThreadLinux (NativeProcessLinux *process, lldb::tid_t tid);
+
+ // ---------------------------------------------------------------------
+ // NativeThreadProtocol Interface
+ // ---------------------------------------------------------------------
+ std::string
+ GetName() override;
+
+ lldb::StateType
+ GetState () override;
+
+ bool
+ GetStopReason (ThreadStopInfo &stop_info, std::string& description) override;
+
+ NativeRegisterContextSP
+ GetRegisterContext () override;
+
+ Error
+ SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) override;
+
+ Error
+ RemoveWatchpoint (lldb::addr_t addr) override;
+
+ private:
+ // ---------------------------------------------------------------------
+ // Interface for friend classes
+ // ---------------------------------------------------------------------
+ void
+ SetRunning ();
+
+ void
+ SetStepping ();
+
+ void
+ SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
+
+ /// Return true if the thread is stopped.
+ /// If stopped by a signal, indicate the signo in the signo argument.
+ /// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER.
+ bool
+ IsStopped (int *signo);
+
+ void
+ SetStoppedByExec ();
+
+ void
+ SetStoppedByBreakpoint ();
+
+ void
+ SetStoppedByWatchpoint (uint32_t wp_index);
+
+ bool
+ IsStoppedAtBreakpoint ();
+
+ bool
+ IsStoppedAtWatchpoint ();
+
+ void
+ SetStoppedByTrace ();
+
+ void
+ SetStoppedWithNoReason ();
+
+ void
+ SetExited ();
+
+ Error
+ RequestStop ();
+
+ // ---------------------------------------------------------------------
+ // Private interface
+ // ---------------------------------------------------------------------
+ void
+ MaybeLogStateChange (lldb::StateType new_state);
+
+ // ---------------------------------------------------------------------
+ // Member Variables
+ // ---------------------------------------------------------------------
+ lldb::StateType m_state;
+ ThreadStopInfo m_stop_info;
+ NativeRegisterContextSP m_reg_context_sp;
+ std::string m_stop_description;
+ using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
+ WatchpointIndexMap m_watchpoint_index_map;
+ };
+
+ typedef std::shared_ptr<NativeThreadLinux> NativeThreadLinuxSP;
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeThreadLinux_H_
diff --git a/source/Plugins/Process/Linux/ProcFileReader.cpp b/source/Plugins/Process/Linux/ProcFileReader.cpp
new file mode 100644
index 000000000000..4d1f231f4f9b
--- /dev/null
+++ b/source/Plugins/Process/Linux/ProcFileReader.cpp
@@ -0,0 +1,108 @@
+//===-- ProcFileReader.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/Linux/ProcFileReader.h"
+
+// C Headers
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+// C++ Headers
+#include <fstream>
+
+// LLDB Headers
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_linux;
+
+lldb::DataBufferSP
+ProcFileReader::ReadIntoDataBuffer (lldb::pid_t pid, const char *name)
+{
+ int fd;
+ char path[PATH_MAX];
+
+ // Make sure we've got a nil terminated buffer for all the folks calling
+ // GetBytes() directly off our returned DataBufferSP if we hit an error.
+ lldb::DataBufferSP buf_sp (new DataBufferHeap(1, 0));
+
+ // Ideally, we would simply create a FileSpec and call ReadFileContents.
+ // However, files in procfs have zero size (since they are, in general,
+ // dynamically generated by the kernel) which is incompatible with the
+ // current ReadFileContents implementation. Therefore we simply stream the
+ // data into a DataBuffer ourselves.
+ if (snprintf (path, PATH_MAX, "/proc/%" PRIu64 "/%s", pid, name) > 0)
+ {
+ if ((fd = open (path, O_RDONLY, 0)) >= 0)
+ {
+ size_t bytes_read = 0;
+ std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
+
+ for (;;)
+ {
+ size_t avail = buf_ap->GetByteSize() - bytes_read;
+ ssize_t status = read (fd, buf_ap->GetBytes() + bytes_read, avail);
+
+ if (status < 0)
+ break;
+
+ if (status == 0)
+ {
+ buf_ap->SetByteSize (bytes_read);
+ buf_sp.reset (buf_ap.release());
+ break;
+ }
+
+ bytes_read += status;
+
+ if (avail - status == 0)
+ buf_ap->SetByteSize (2 * buf_ap->GetByteSize());
+ }
+
+ close (fd);
+ }
+ }
+
+ return buf_sp;
+}
+
+Error
+ProcFileReader::ProcessLineByLine (lldb::pid_t pid, const char *name, std::function<bool (const std::string &line)> line_parser)
+{
+ Error error;
+
+ // Try to open the /proc/{pid}/maps entry.
+ char filename [PATH_MAX];
+ snprintf (filename, sizeof(filename), "/proc/%" PRIu64 "/%s", pid, name);
+ filename[sizeof (filename) - 1] = '\0';
+
+ std::ifstream proc_file (filename);
+ if (proc_file.fail ())
+ {
+ error.SetErrorStringWithFormat ("failed to open file '%s'", filename);
+ return error;
+ }
+
+ // Read the file line by line, processing until either end of file or when the line_parser returns false.
+ std::string line;
+ bool should_continue = true;
+
+ while (should_continue && std::getline (proc_file, line))
+ {
+ // Pass the line over to the line_parser for processing. If the line_parser returns false, we
+ // stop processing.
+ should_continue = line_parser (line);
+ }
+
+ return error;
+}
diff --git a/source/Plugins/Process/Linux/ProcFileReader.h b/source/Plugins/Process/Linux/ProcFileReader.h
new file mode 100644
index 000000000000..7b3812433068
--- /dev/null
+++ b/source/Plugins/Process/Linux/ProcFileReader.h
@@ -0,0 +1,37 @@
+//===-- ProcFileReader.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_ProcFileReader_h_
+#define liblldb_ProcFileReader_h_
+
+#include <functional>
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+namespace process_linux {
+
+ class ProcFileReader
+ {
+ public:
+
+ static lldb::DataBufferSP
+ ReadIntoDataBuffer (lldb::pid_t pid, const char *name);
+
+ /// Parse the /proc/{@a pid}/{@a name} file line by line, passing each line to line_parser, until
+ /// either end of file or until line_parser returns false.
+ static Error
+ ProcessLineByLine (lldb::pid_t pid, const char *name, std::function<bool (const std::string &line)> line_parser);
+ };
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_ProcFileReader_h_
diff --git a/source/Plugins/Process/Linux/Procfs.h b/source/Plugins/Process/Linux/Procfs.h
new file mode 100644
index 000000000000..cad433fb095d
--- /dev/null
+++ b/source/Plugins/Process/Linux/Procfs.h
@@ -0,0 +1,31 @@
+//===-- Procfs.h ---------------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// source/Plugins/Process/Linux/Procfs.h defines the symbols we need from
+// sys/procfs.h on Android/Linux for all supported architectures.
+
+#include <sys/ptrace.h>
+
+#ifdef __ANDROID__
+#if defined (__arm64__) || defined (__aarch64__)
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[(sizeof (struct user_pt_regs) / sizeof(elf_greg_t))];
+typedef struct user_fpsimd_state elf_fpregset_t;
+#ifndef NT_FPREGSET
+ #define NT_FPREGSET NT_PRFPREG
+#endif // NT_FPREGSET
+#elif defined (__mips__)
+#ifndef NT_FPREGSET
+ #define NT_FPREGSET NT_PRFPREG
+#endif // NT_FPREGSET
+#endif
+#else // __ANDROID__
+#include <sys/procfs.h>
+#endif // __ANDROID__
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt b/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt
new file mode 100644
index 000000000000..681b7405e2b8
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_lldb_library(lldbPluginProcessMacOSXKernel
+ CommunicationKDP.cpp
+ ProcessKDP.cpp
+ ProcessKDPLog.cpp
+ RegisterContextKDP_arm.cpp
+ RegisterContextKDP_arm64.cpp
+ RegisterContextKDP_i386.cpp
+ RegisterContextKDP_x86_64.cpp
+ ThreadKDP.cpp
+ )
diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp
new file mode 100644
index 000000000000..5c1c3284a35c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp
@@ -0,0 +1,1445 @@
+//===-- CommunicationKDP.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "CommunicationKDP.h"
+
+// C Includes
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+
+// C++ Includes
+
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "ProcessKDPLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// CommunicationKDP constructor
+//----------------------------------------------------------------------
+CommunicationKDP::CommunicationKDP (const char *comm_name) :
+ Communication(comm_name),
+ m_addr_byte_size (4),
+ m_byte_order (eByteOrderLittle),
+ m_packet_timeout (5),
+ m_sequence_mutex (Mutex::eMutexTypeRecursive),
+ m_is_running (false),
+ m_session_key (0u),
+ m_request_sequence_id (0u),
+ m_exception_sequence_id (0u),
+ m_kdp_version_version (0u),
+ m_kdp_version_feature (0u),
+ m_kdp_hostinfo_cpu_mask (0u),
+ m_kdp_hostinfo_cpu_type (0u),
+ m_kdp_hostinfo_cpu_subtype (0u)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommunicationKDP::~CommunicationKDP()
+{
+ if (IsConnected())
+ {
+ Disconnect();
+ }
+}
+
+bool
+CommunicationKDP::SendRequestPacket (const PacketStreamType &request_packet)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return SendRequestPacketNoLock (request_packet);
+}
+
+#if 0
+typedef struct {
+ uint8_t request; // Either: CommandType | ePacketTypeRequest, or CommandType | ePacketTypeReply
+ uint8_t sequence;
+ uint16_t length; // Length of entire packet including this header
+ uint32_t key; // Session key
+} kdp_hdr_t;
+#endif
+
+void
+CommunicationKDP::MakeRequestPacketHeader (CommandType request_type,
+ PacketStreamType &request_packet,
+ uint16_t request_length)
+{
+ request_packet.Clear();
+ request_packet.PutHex8 (request_type | ePacketTypeRequest); // Set the request type
+ request_packet.PutHex8 (m_request_sequence_id++); // Sequence number
+ request_packet.PutHex16 (request_length); // Length of the packet including this header
+ request_packet.PutHex32 (m_session_key); // Session key
+}
+
+bool
+CommunicationKDP::SendRequestAndGetReply (const CommandType command,
+ const PacketStreamType &request_packet,
+ DataExtractor &reply_packet)
+{
+ if (IsRunning())
+ {
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
+ if (log)
+ {
+ PacketStreamType log_strm;
+ DumpPacket (log_strm, request_packet.GetData(), request_packet.GetSize());
+ log->Printf("error: kdp running, not sending packet: %.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData());
+ }
+ return false;
+ }
+
+ Mutex::Locker locker(m_sequence_mutex);
+#ifdef LLDB_CONFIGURATION_DEBUG
+ // NOTE: this only works for packets that are in native endian byte order
+ assert (request_packet.GetSize() == *((uint16_t *)(request_packet.GetData() + 2)));
+#endif
+ lldb::offset_t offset = 1;
+ const uint32_t num_retries = 3;
+ for (uint32_t i=0; i<num_retries; ++i)
+ {
+ if (SendRequestPacketNoLock(request_packet))
+ {
+ const uint8_t request_sequence_id = (uint8_t)request_packet.GetData()[1];
+ while (1)
+ {
+ if (WaitForPacketWithTimeoutMicroSecondsNoLock (reply_packet, GetPacketTimeoutInMicroSeconds ()))
+ {
+ offset = 0;
+ const uint8_t reply_command = reply_packet.GetU8 (&offset);
+ const uint8_t reply_sequence_id = reply_packet.GetU8 (&offset);
+ if (request_sequence_id == reply_sequence_id)
+ {
+ // The sequent ID was correct, now verify we got the response we were looking for
+ if ((reply_command & eCommandTypeMask) == command)
+ {
+ // Success
+ if (command == KDP_RESUMECPUS)
+ m_is_running.SetValue(true, eBroadcastAlways);
+ return true;
+ }
+ else
+ {
+ // Failed to get the correct response, bail
+ reply_packet.Clear();
+ return false;
+ }
+ }
+ else if (reply_sequence_id > request_sequence_id)
+ {
+ // Sequence ID was greater than the sequence ID of the packet we sent, something
+ // is really wrong...
+ reply_packet.Clear();
+ return false;
+ }
+ else
+ {
+ // The reply sequence ID was less than our current packet's sequence ID
+ // so we should keep trying to get a response because this was a response
+ // for a previous packet that we must have retried.
+ }
+ }
+ else
+ {
+ // Break and retry sending the packet as we didn't get a response due to timeout
+ break;
+ }
+ }
+ }
+ }
+ reply_packet.Clear();
+ return false;
+}
+
+bool
+CommunicationKDP::SendRequestPacketNoLock (const PacketStreamType &request_packet)
+{
+ if (IsConnected())
+ {
+ const char *packet_data = request_packet.GetData();
+ const size_t packet_size = request_packet.GetSize();
+
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
+ if (log)
+ {
+ PacketStreamType log_strm;
+ DumpPacket (log_strm, packet_data, packet_size);
+ log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData());
+ }
+ ConnectionStatus status = eConnectionStatusSuccess;
+
+ size_t bytes_written = Write (packet_data,
+ packet_size,
+ status,
+ NULL);
+
+ if (bytes_written == packet_size)
+ return true;
+
+ if (log)
+ log->Printf ("error: failed to send packet entire packet %" PRIu64 " of %" PRIu64 " bytes sent", (uint64_t)bytes_written, (uint64_t)packet_size);
+ }
+ return false;
+}
+
+bool
+CommunicationKDP::GetSequenceMutex (Mutex::Locker& locker)
+{
+ return locker.TryLock (m_sequence_mutex);
+}
+
+
+bool
+CommunicationKDP::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
+{
+ return m_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
+}
+
+size_t
+CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds (DataExtractor &packet, uint32_t timeout_usec)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec);
+}
+
+size_t
+CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (DataExtractor &packet, uint32_t timeout_usec)
+{
+ uint8_t buffer[8192];
+ Error error;
+
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS | KDP_LOG_VERBOSE));
+
+ // Check for a packet from our cache first without trying any reading...
+ if (CheckForPacket (NULL, 0, packet))
+ return packet.GetByteSize();
+
+ bool timed_out = false;
+ while (IsConnected() && !timed_out)
+ {
+ lldb::ConnectionStatus status = eConnectionStatusNoConnection;
+ size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error);
+
+ if (log)
+ log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %" PRIu64,
+ __PRETTY_FUNCTION__,
+ timeout_usec,
+ Communication::ConnectionStatusAsCString (status),
+ error.AsCString(),
+ (uint64_t)bytes_read);
+
+ if (bytes_read > 0)
+ {
+ if (CheckForPacket (buffer, bytes_read, packet))
+ return packet.GetByteSize();
+ }
+ else
+ {
+ switch (status)
+ {
+ case eConnectionStatusInterrupted:
+ case eConnectionStatusTimedOut:
+ timed_out = true;
+ break;
+ case eConnectionStatusSuccess:
+ //printf ("status = success but error = %s\n", error.AsCString("<invalid>"));
+ break;
+
+ case eConnectionStatusEndOfFile:
+ case eConnectionStatusNoConnection:
+ case eConnectionStatusLostConnection:
+ case eConnectionStatusError:
+ Disconnect();
+ break;
+ }
+ }
+ }
+ packet.Clear ();
+ return 0;
+}
+
+bool
+CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, DataExtractor &packet)
+{
+ // Put the packet data into the buffer in a thread safe fashion
+ Mutex::Locker locker(m_bytes_mutex);
+
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
+
+ if (src && src_len > 0)
+ {
+ if (log && log->GetVerbose())
+ {
+ PacketStreamType log_strm;
+ DataExtractor::DumpHexBytes (&log_strm, src, src_len, UINT32_MAX, LLDB_INVALID_ADDRESS);
+ log->Printf ("CommunicationKDP::%s adding %u bytes: %s",
+ __FUNCTION__,
+ (uint32_t)src_len,
+ log_strm.GetData());
+ }
+ m_bytes.append ((const char *)src, src_len);
+ }
+
+ // Make sure we at least have enough bytes for a packet header
+ const size_t bytes_available = m_bytes.size();
+ if (bytes_available >= 8)
+ {
+ packet.SetData (&m_bytes[0], bytes_available, m_byte_order);
+ lldb::offset_t offset = 0;
+ uint8_t reply_command = packet.GetU8(&offset);
+ switch (reply_command)
+ {
+ case ePacketTypeRequest | KDP_EXCEPTION:
+ case ePacketTypeRequest | KDP_TERMINATION:
+ // We got an exception request, so be sure to send an ACK
+ {
+ PacketStreamType request_ack_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ // Set the reply but and make the ACK packet
+ request_ack_packet.PutHex8 (reply_command | ePacketTypeReply);
+ request_ack_packet.PutHex8 (packet.GetU8(&offset));
+ request_ack_packet.PutHex16 (packet.GetU16(&offset));
+ request_ack_packet.PutHex32 (packet.GetU32(&offset));
+ m_is_running.SetValue(false, eBroadcastAlways);
+ // Ack to the exception or termination
+ SendRequestPacketNoLock (request_ack_packet);
+ }
+ // Fall through to case below to get packet contents
+ case ePacketTypeReply | KDP_CONNECT:
+ case ePacketTypeReply | KDP_DISCONNECT:
+ case ePacketTypeReply | KDP_HOSTINFO:
+ case ePacketTypeReply | KDP_VERSION:
+ case ePacketTypeReply | KDP_MAXBYTES:
+ case ePacketTypeReply | KDP_READMEM:
+ case ePacketTypeReply | KDP_WRITEMEM:
+ case ePacketTypeReply | KDP_READREGS:
+ case ePacketTypeReply | KDP_WRITEREGS:
+ case ePacketTypeReply | KDP_LOAD:
+ case ePacketTypeReply | KDP_IMAGEPATH:
+ case ePacketTypeReply | KDP_SUSPEND:
+ case ePacketTypeReply | KDP_RESUMECPUS:
+ case ePacketTypeReply | KDP_BREAKPOINT_SET:
+ case ePacketTypeReply | KDP_BREAKPOINT_REMOVE:
+ case ePacketTypeReply | KDP_REGIONS:
+ case ePacketTypeReply | KDP_REATTACH:
+ case ePacketTypeReply | KDP_HOSTREBOOT:
+ case ePacketTypeReply | KDP_READMEM64:
+ case ePacketTypeReply | KDP_WRITEMEM64:
+ case ePacketTypeReply | KDP_BREAKPOINT_SET64:
+ case ePacketTypeReply | KDP_BREAKPOINT_REMOVE64:
+ case ePacketTypeReply | KDP_KERNELVERSION:
+ case ePacketTypeReply | KDP_READPHYSMEM64:
+ case ePacketTypeReply | KDP_WRITEPHYSMEM64:
+ case ePacketTypeReply | KDP_READIOPORT:
+ case ePacketTypeReply | KDP_WRITEIOPORT:
+ case ePacketTypeReply | KDP_READMSR64:
+ case ePacketTypeReply | KDP_WRITEMSR64:
+ case ePacketTypeReply | KDP_DUMPINFO:
+ {
+ offset = 2;
+ const uint16_t length = packet.GetU16 (&offset);
+ if (length <= bytes_available)
+ {
+ // We have an entire packet ready, we need to copy the data
+ // bytes into a buffer that will be owned by the packet and
+ // erase the bytes from our communcation buffer "m_bytes"
+ packet.SetData (DataBufferSP (new DataBufferHeap (&m_bytes[0], length)));
+ m_bytes.erase (0, length);
+
+ if (log)
+ {
+ PacketStreamType log_strm;
+ DumpPacket (log_strm, packet);
+
+ log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData());
+ }
+ return true;
+ }
+ }
+ break;
+
+ default:
+ // Unrecognized reply command byte, erase this byte and try to get back on track
+ if (log)
+ log->Printf ("CommunicationKDP::%s: tossing junk byte: 0x%2.2x",
+ __FUNCTION__,
+ (uint8_t)m_bytes[0]);
+ m_bytes.erase(0, 1);
+ break;
+ }
+ }
+ packet.Clear();
+ return false;
+}
+
+
+bool
+CommunicationKDP::SendRequestConnect (uint16_t reply_port,
+ uint16_t exc_port,
+ const char *greeting)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ if (greeting == NULL)
+ greeting = "";
+
+ const CommandType command = KDP_CONNECT;
+ // Length is 82 uint16_t and the length of the greeting C string with the terminating NULL
+ const uint32_t command_length = 8 + 2 + 2 + ::strlen(greeting) + 1;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ // Always send connect ports as little endian
+ request_packet.SetByteOrder (eByteOrderLittle);
+ request_packet.PutHex16 (htons(reply_port));
+ request_packet.PutHex16 (htons(exc_port));
+ request_packet.SetByteOrder (m_byte_order);
+ request_packet.PutCString (greeting);
+ DataExtractor reply_packet;
+ return SendRequestAndGetReply (command, request_packet, reply_packet);
+}
+
+void
+CommunicationKDP::ClearKDPSettings ()
+{
+ m_request_sequence_id = 0;
+ m_kdp_version_version = 0;
+ m_kdp_version_feature = 0;
+ m_kdp_hostinfo_cpu_mask = 0;
+ m_kdp_hostinfo_cpu_type = 0;
+ m_kdp_hostinfo_cpu_subtype = 0;
+}
+
+bool
+CommunicationKDP::SendRequestReattach (uint16_t reply_port)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_REATTACH;
+ // Length is 8 bytes for the header plus 2 bytes for the reply UDP port
+ const uint32_t command_length = 8 + 2;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ // Always send connect ports as little endian
+ request_packet.SetByteOrder (eByteOrderLittle);
+ request_packet.PutHex16(htons(reply_port));
+ request_packet.SetByteOrder (m_byte_order);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ // Reset the sequence ID to zero for reattach
+ ClearKDPSettings ();
+ lldb::offset_t offset = 4;
+ m_session_key = reply_packet.GetU32 (&offset);
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+CommunicationKDP::GetVersion ()
+{
+ if (!VersionIsValid())
+ SendRequestVersion();
+ return m_kdp_version_version;
+}
+
+uint32_t
+CommunicationKDP::GetFeatureFlags ()
+{
+ if (!VersionIsValid())
+ SendRequestVersion();
+ return m_kdp_version_feature;
+}
+
+bool
+CommunicationKDP::SendRequestVersion ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_VERSION;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ m_kdp_version_version = reply_packet.GetU32 (&offset);
+ m_kdp_version_feature = reply_packet.GetU32 (&offset);
+ return true;
+ }
+ return false;
+}
+
+#if 0 // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection...
+const char *
+CommunicationKDP::GetImagePath ()
+{
+ if (m_image_path.empty())
+ SendRequestImagePath();
+ return m_image_path.c_str();
+}
+
+bool
+CommunicationKDP::SendRequestImagePath ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_IMAGEPATH;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ const char *path = reply_packet.PeekCStr(8);
+ if (path && path[0])
+ m_kernel_version.assign (path);
+ return true;
+ }
+ return false;
+}
+#endif
+
+uint32_t
+CommunicationKDP::GetCPUMask ()
+{
+ if (!HostInfoIsValid())
+ SendRequestHostInfo();
+ return m_kdp_hostinfo_cpu_mask;
+}
+
+uint32_t
+CommunicationKDP::GetCPUType ()
+{
+ if (!HostInfoIsValid())
+ SendRequestHostInfo();
+ return m_kdp_hostinfo_cpu_type;
+}
+
+uint32_t
+CommunicationKDP::GetCPUSubtype ()
+{
+ if (!HostInfoIsValid())
+ SendRequestHostInfo();
+ return m_kdp_hostinfo_cpu_subtype;
+}
+
+lldb_private::UUID
+CommunicationKDP::GetUUID ()
+{
+ UUID uuid;
+ if (GetKernelVersion() == NULL)
+ return uuid;
+
+ if (m_kernel_version.find("UUID=") == std::string::npos)
+ return uuid;
+
+ size_t p = m_kernel_version.find("UUID=") + strlen ("UUID=");
+ std::string uuid_str = m_kernel_version.substr(p, 36);
+ if (uuid_str.size() < 32)
+ return uuid;
+
+ if (uuid.SetFromCString (uuid_str.c_str()) == 0)
+ {
+ UUID invalid_uuid;
+ return invalid_uuid;
+ }
+
+ return uuid;
+}
+
+bool
+CommunicationKDP::RemoteIsEFI ()
+{
+ if (GetKernelVersion() == NULL)
+ return false;
+ if (strncmp (m_kernel_version.c_str(), "EFI", 3) == 0)
+ return true;
+ else
+ return false;
+}
+
+bool
+CommunicationKDP::RemoteIsDarwinKernel ()
+{
+ if (GetKernelVersion() == NULL)
+ return false;
+ if (m_kernel_version.find("Darwin Kernel") != std::string::npos)
+ return true;
+ else
+ return false;
+}
+
+lldb::addr_t
+CommunicationKDP::GetLoadAddress ()
+{
+ if (GetKernelVersion() == NULL)
+ return LLDB_INVALID_ADDRESS;
+
+ if (m_kernel_version.find("stext=") == std::string::npos)
+ return LLDB_INVALID_ADDRESS;
+ size_t p = m_kernel_version.find("stext=") + strlen ("stext=");
+ if (m_kernel_version[p] != '0' || m_kernel_version[p + 1] != 'x')
+ return LLDB_INVALID_ADDRESS;
+
+ addr_t kernel_load_address;
+ errno = 0;
+ kernel_load_address = ::strtoul (m_kernel_version.c_str() + p, NULL, 16);
+ if (errno != 0 || kernel_load_address == 0)
+ return LLDB_INVALID_ADDRESS;
+
+ return kernel_load_address;
+}
+
+bool
+CommunicationKDP::SendRequestHostInfo ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_HOSTINFO;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ m_kdp_hostinfo_cpu_mask = reply_packet.GetU32 (&offset);
+ m_kdp_hostinfo_cpu_type = reply_packet.GetU32 (&offset);
+ m_kdp_hostinfo_cpu_subtype = reply_packet.GetU32 (&offset);
+
+ ArchSpec kernel_arch;
+ kernel_arch.SetArchitecture (eArchTypeMachO,
+ m_kdp_hostinfo_cpu_type,
+ m_kdp_hostinfo_cpu_subtype);
+
+ m_addr_byte_size = kernel_arch.GetAddressByteSize();
+ m_byte_order = kernel_arch.GetByteOrder();
+ return true;
+ }
+ return false;
+}
+
+const char *
+CommunicationKDP::GetKernelVersion ()
+{
+ if (m_kernel_version.empty())
+ SendRequestKernelVersion ();
+ return m_kernel_version.c_str();
+}
+
+bool
+CommunicationKDP::SendRequestKernelVersion ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_KERNELVERSION;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ const char *kernel_version_cstr = reply_packet.PeekCStr(8);
+ if (kernel_version_cstr && kernel_version_cstr[0])
+ m_kernel_version.assign (kernel_version_cstr);
+ return true;
+ }
+ return false;
+}
+
+bool
+CommunicationKDP::SendRequestDisconnect ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_DISCONNECT;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ // Are we supposed to get a reply for disconnect?
+ }
+ ClearKDPSettings ();
+ return true;
+}
+
+uint32_t
+CommunicationKDP::SendRequestReadMemory (lldb::addr_t addr,
+ void *dst,
+ uint32_t dst_len,
+ Error &error)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ bool use_64 = (GetVersion() >= 11);
+ uint32_t command_addr_byte_size = use_64 ? 8 : 4;
+ const CommandType command = use_64 ? KDP_READMEM64 : KDP_READMEM;
+ // Size is header + address size + uint32_t length
+ const uint32_t command_length = 8 + command_addr_byte_size + 4;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutMaxHex64 (addr, command_addr_byte_size);
+ request_packet.PutHex32 (dst_len);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ uint32_t kdp_error = reply_packet.GetU32 (&offset);
+ uint32_t src_len = reply_packet.GetByteSize() - 12;
+
+ if (src_len > 0)
+ {
+ const void *src = reply_packet.GetData(&offset, src_len);
+ if (src)
+ {
+ ::memcpy (dst, src, src_len);
+ error.Clear();
+ return src_len;
+ }
+ }
+ if (kdp_error)
+ error.SetErrorStringWithFormat ("kdp read memory failed (error %u)", kdp_error);
+ else
+ error.SetErrorString ("kdp read memory failed");
+ }
+ else
+ {
+ error.SetErrorString ("failed to send packet");
+ }
+ return 0;
+}
+
+
+uint32_t
+CommunicationKDP::SendRequestWriteMemory (lldb::addr_t addr,
+ const void *src,
+ uint32_t src_len,
+ Error &error)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ bool use_64 = (GetVersion() >= 11);
+ uint32_t command_addr_byte_size = use_64 ? 8 : 4;
+ const CommandType command = use_64 ? KDP_WRITEMEM64 : KDP_WRITEMEM;
+ // Size is header + address size + uint32_t length
+ const uint32_t command_length = 8 + command_addr_byte_size + 4 + src_len;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutMaxHex64 (addr, command_addr_byte_size);
+ request_packet.PutHex32 (src_len);
+ request_packet.PutRawBytes(src, src_len);
+
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ uint32_t kdp_error = reply_packet.GetU32 (&offset);
+ if (kdp_error)
+ error.SetErrorStringWithFormat ("kdp write memory failed (error %u)", kdp_error);
+ else
+ {
+ error.Clear();
+ return src_len;
+ }
+ }
+ else
+ {
+ error.SetErrorString ("failed to send packet");
+ }
+ return 0;
+}
+
+bool
+CommunicationKDP::SendRawRequest (uint8_t command_byte,
+ const void *src, // Raw packet payload bytes
+ uint32_t src_len, // Raw packet payload length
+ DataExtractor &reply_packet,
+ Error &error)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ // Size is header + address size + uint32_t length
+ const uint32_t command_length = 8 + src_len;
+ const CommandType command = (CommandType)command_byte;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutRawBytes(src, src_len);
+
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ uint32_t kdp_error = reply_packet.GetU32 (&offset);
+ if (kdp_error && (command_byte != KDP_DUMPINFO))
+ error.SetErrorStringWithFormat ("request packet 0x%8.8x failed (error %u)", command_byte, kdp_error);
+ else
+ {
+ error.Clear();
+ return true;
+ }
+ }
+ else
+ {
+ error.SetErrorString ("failed to send packet");
+ }
+ return false;
+}
+
+
+const char *
+CommunicationKDP::GetCommandAsCString (uint8_t command)
+{
+ switch (command)
+ {
+ case KDP_CONNECT: return "KDP_CONNECT";
+ case KDP_DISCONNECT: return "KDP_DISCONNECT";
+ case KDP_HOSTINFO: return "KDP_HOSTINFO";
+ case KDP_VERSION: return "KDP_VERSION";
+ case KDP_MAXBYTES: return "KDP_MAXBYTES";
+ case KDP_READMEM: return "KDP_READMEM";
+ case KDP_WRITEMEM: return "KDP_WRITEMEM";
+ case KDP_READREGS: return "KDP_READREGS";
+ case KDP_WRITEREGS: return "KDP_WRITEREGS";
+ case KDP_LOAD: return "KDP_LOAD";
+ case KDP_IMAGEPATH: return "KDP_IMAGEPATH";
+ case KDP_SUSPEND: return "KDP_SUSPEND";
+ case KDP_RESUMECPUS: return "KDP_RESUMECPUS";
+ case KDP_EXCEPTION: return "KDP_EXCEPTION";
+ case KDP_TERMINATION: return "KDP_TERMINATION";
+ case KDP_BREAKPOINT_SET: return "KDP_BREAKPOINT_SET";
+ case KDP_BREAKPOINT_REMOVE: return "KDP_BREAKPOINT_REMOVE";
+ case KDP_REGIONS: return "KDP_REGIONS";
+ case KDP_REATTACH: return "KDP_REATTACH";
+ case KDP_HOSTREBOOT: return "KDP_HOSTREBOOT";
+ case KDP_READMEM64: return "KDP_READMEM64";
+ case KDP_WRITEMEM64: return "KDP_WRITEMEM64";
+ case KDP_BREAKPOINT_SET64: return "KDP_BREAKPOINT64_SET";
+ case KDP_BREAKPOINT_REMOVE64: return "KDP_BREAKPOINT64_REMOVE";
+ case KDP_KERNELVERSION: return "KDP_KERNELVERSION";
+ case KDP_READPHYSMEM64: return "KDP_READPHYSMEM64";
+ case KDP_WRITEPHYSMEM64: return "KDP_WRITEPHYSMEM64";
+ case KDP_READIOPORT: return "KDP_READIOPORT";
+ case KDP_WRITEIOPORT: return "KDP_WRITEIOPORT";
+ case KDP_READMSR64: return "KDP_READMSR64";
+ case KDP_WRITEMSR64: return "KDP_WRITEMSR64";
+ case KDP_DUMPINFO: return "KDP_DUMPINFO";
+ }
+ return NULL;
+}
+
+void
+CommunicationKDP::DumpPacket (Stream &s, const void *data, uint32_t data_len)
+{
+ DataExtractor extractor (data, data_len, m_byte_order, m_addr_byte_size);
+ DumpPacket (s, extractor);
+}
+
+void
+CommunicationKDP::DumpPacket (Stream &s, const DataExtractor& packet)
+{
+ const char *error_desc = NULL;
+ if (packet.GetByteSize() < 8)
+ {
+ error_desc = "error: invalid packet (too short): ";
+ }
+ else
+ {
+ lldb::offset_t offset = 0;
+ const uint8_t first_packet_byte = packet.GetU8 (&offset);
+ const uint8_t sequence_id = packet.GetU8 (&offset);
+ const uint16_t length = packet.GetU16 (&offset);
+ const uint32_t key = packet.GetU32 (&offset);
+ const CommandType command = ExtractCommand (first_packet_byte);
+ const char *command_name = GetCommandAsCString (command);
+ if (command_name)
+ {
+ const bool is_reply = ExtractIsReply(first_packet_byte);
+ s.Printf ("(running=%i) %s %24s: 0x%2.2x 0x%2.2x 0x%4.4x 0x%8.8x ",
+ IsRunning(),
+ is_reply ? "<--" : "-->",
+ command_name,
+ first_packet_byte,
+ sequence_id,
+ length,
+ key);
+
+ if (is_reply)
+ {
+ // Dump request reply packets
+ switch (command)
+ {
+ // Commands that return a single 32 bit error
+ case KDP_CONNECT:
+ case KDP_WRITEMEM:
+ case KDP_WRITEMEM64:
+ case KDP_BREAKPOINT_SET:
+ case KDP_BREAKPOINT_REMOVE:
+ case KDP_BREAKPOINT_SET64:
+ case KDP_BREAKPOINT_REMOVE64:
+ case KDP_WRITEREGS:
+ case KDP_LOAD:
+ case KDP_WRITEIOPORT:
+ case KDP_WRITEMSR64:
+ {
+ const uint32_t error = packet.GetU32 (&offset);
+ s.Printf(" (error=0x%8.8x)", error);
+ }
+ break;
+
+ case KDP_DISCONNECT:
+ case KDP_REATTACH:
+ case KDP_HOSTREBOOT:
+ case KDP_SUSPEND:
+ case KDP_RESUMECPUS:
+ case KDP_EXCEPTION:
+ case KDP_TERMINATION:
+ // No return value for the reply, just the header to ack
+ s.PutCString(" ()");
+ break;
+
+ case KDP_HOSTINFO:
+ {
+ const uint32_t cpu_mask = packet.GetU32 (&offset);
+ const uint32_t cpu_type = packet.GetU32 (&offset);
+ const uint32_t cpu_subtype = packet.GetU32 (&offset);
+ s.Printf(" (cpu_mask=0x%8.8x, cpu_type=0x%8.8x, cpu_subtype=0x%8.8x)", cpu_mask, cpu_type, cpu_subtype);
+ }
+ break;
+
+ case KDP_VERSION:
+ {
+ const uint32_t version = packet.GetU32 (&offset);
+ const uint32_t feature = packet.GetU32 (&offset);
+ s.Printf(" (version=0x%8.8x, feature=0x%8.8x)", version, feature);
+ }
+ break;
+
+ case KDP_REGIONS:
+ {
+ const uint32_t region_count = packet.GetU32 (&offset);
+ s.Printf(" (count = %u", region_count);
+ for (uint32_t i=0; i<region_count; ++i)
+ {
+ const addr_t region_addr = packet.GetPointer (&offset);
+ const uint32_t region_size = packet.GetU32 (&offset);
+ const uint32_t region_prot = packet.GetU32 (&offset);
+ s.Printf("\n\tregion[%" PRIu64 "] = { range = [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), size = 0x%8.8x, prot = %s }", region_addr, region_addr, region_addr + region_size, region_size, GetPermissionsAsCString (region_prot));
+ }
+ }
+ break;
+
+ case KDP_READMEM:
+ case KDP_READMEM64:
+ case KDP_READPHYSMEM64:
+ {
+ const uint32_t error = packet.GetU32 (&offset);
+ const uint32_t count = packet.GetByteSize() - offset;
+ s.Printf(" (error = 0x%8.8x:\n", error);
+ if (count > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatBytesWithASCII, // Format to use
+ 1, // Size of each item in bytes
+ count, // Number of items
+ 16, // Number per line
+ m_last_read_memory_addr, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+
+ case KDP_READREGS:
+ {
+ const uint32_t error = packet.GetU32 (&offset);
+ const uint32_t count = packet.GetByteSize() - offset;
+ s.Printf(" (error = 0x%8.8x regs:\n", error);
+ if (count > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ m_addr_byte_size, // Size of each item in bytes
+ count / m_addr_byte_size, // Number of items
+ 16 / m_addr_byte_size, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+
+ case KDP_KERNELVERSION:
+ {
+ const char *kernel_version = packet.PeekCStr(8);
+ s.Printf(" (version = \"%s\")", kernel_version);
+ }
+ break;
+
+ case KDP_MAXBYTES:
+ {
+ const uint32_t max_bytes = packet.GetU32 (&offset);
+ s.Printf(" (max_bytes = 0x%8.8x (%u))", max_bytes, max_bytes);
+ }
+ break;
+ case KDP_IMAGEPATH:
+ {
+ const char *path = packet.GetCStr(&offset);
+ s.Printf(" (path = \"%s\")", path);
+ }
+ break;
+
+ case KDP_READIOPORT:
+ case KDP_READMSR64:
+ {
+ const uint32_t error = packet.GetU32 (&offset);
+ const uint32_t count = packet.GetByteSize() - offset;
+ s.Printf(" (error = 0x%8.8x io:\n", error);
+ if (count > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ 1, // Size of each item in bytes
+ count, // Number of items
+ 16, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+ case KDP_DUMPINFO:
+ {
+ const uint32_t count = packet.GetByteSize() - offset;
+ s.Printf(" (count = %u, bytes = \n", count);
+ if (count > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ 1, // Size of each item in bytes
+ count, // Number of items
+ 16, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+
+ }
+ break;
+
+ default:
+ s.Printf(" (add support for dumping this packet reply!!!");
+ break;
+
+ }
+ }
+ else
+ {
+ // Dump request packets
+ switch (command)
+ {
+ case KDP_CONNECT:
+ {
+ const uint16_t reply_port = ntohs(packet.GetU16 (&offset));
+ const uint16_t exc_port = ntohs(packet.GetU16 (&offset));
+ s.Printf(" (reply_port = %u, exc_port = %u, greeting = \"%s\")", reply_port, exc_port, packet.GetCStr(&offset));
+ }
+ break;
+
+ case KDP_DISCONNECT:
+ case KDP_HOSTREBOOT:
+ case KDP_HOSTINFO:
+ case KDP_VERSION:
+ case KDP_REGIONS:
+ case KDP_KERNELVERSION:
+ case KDP_MAXBYTES:
+ case KDP_IMAGEPATH:
+ case KDP_SUSPEND:
+ // No args, just the header in the request...
+ s.PutCString(" ()");
+ break;
+
+ case KDP_RESUMECPUS:
+ {
+ const uint32_t cpu_mask = packet.GetU32 (&offset);
+ s.Printf(" (cpu_mask = 0x%8.8x)", cpu_mask);
+ }
+ break;
+
+ case KDP_READMEM:
+ {
+ const uint32_t addr = packet.GetU32 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ s.Printf(" (addr = 0x%8.8x, size = %u)", addr, size);
+ m_last_read_memory_addr = addr;
+ }
+ break;
+
+ case KDP_WRITEMEM:
+ {
+ const uint32_t addr = packet.GetU32 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ s.Printf(" (addr = 0x%8.8x, size = %u, bytes = \n", addr, size);
+ if (size > 0)
+ DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
+ }
+ break;
+
+ case KDP_READMEM64:
+ {
+ const uint64_t addr = packet.GetU64 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u)", addr, size);
+ m_last_read_memory_addr = addr;
+ }
+ break;
+
+ case KDP_READPHYSMEM64:
+ {
+ const uint64_t addr = packet.GetU64 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ const uint32_t lcpu = packet.GetU16 (&offset);
+ s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u)", addr, size, lcpu);
+ m_last_read_memory_addr = addr;
+ }
+ break;
+
+ case KDP_WRITEMEM64:
+ {
+ const uint64_t addr = packet.GetU64 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u, bytes = \n", addr, size);
+ if (size > 0)
+ DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
+ }
+ break;
+
+ case KDP_WRITEPHYSMEM64:
+ {
+ const uint64_t addr = packet.GetU64 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ const uint32_t lcpu = packet.GetU16 (&offset);
+ s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u, bytes = \n", addr, size, lcpu);
+ if (size > 0)
+ DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
+ }
+ break;
+
+ case KDP_READREGS:
+ {
+ const uint32_t cpu = packet.GetU32 (&offset);
+ const uint32_t flavor = packet.GetU32 (&offset);
+ s.Printf(" (cpu = %u, flavor = %u)", cpu, flavor);
+ }
+ break;
+
+ case KDP_WRITEREGS:
+ {
+ const uint32_t cpu = packet.GetU32 (&offset);
+ const uint32_t flavor = packet.GetU32 (&offset);
+ const uint32_t nbytes = packet.GetByteSize() - offset;
+ s.Printf(" (cpu = %u, flavor = %u, regs = \n", cpu, flavor);
+ if (nbytes > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ m_addr_byte_size, // Size of each item in bytes
+ nbytes / m_addr_byte_size, // Number of items
+ 16 / m_addr_byte_size, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+
+
+ case KDP_BREAKPOINT_SET:
+ case KDP_BREAKPOINT_REMOVE:
+ {
+ const uint32_t addr = packet.GetU32 (&offset);
+ s.Printf(" (addr = 0x%8.8x)", addr);
+ }
+ break;
+
+ case KDP_BREAKPOINT_SET64:
+ case KDP_BREAKPOINT_REMOVE64:
+ {
+ const uint64_t addr = packet.GetU64 (&offset);
+ s.Printf(" (addr = 0x%16.16" PRIx64 ")", addr);
+ }
+ break;
+
+
+ case KDP_LOAD:
+ {
+ const char *path = packet.GetCStr(&offset);
+ s.Printf(" (path = \"%s\")", path);
+ }
+ break;
+
+ case KDP_EXCEPTION:
+ {
+ const uint32_t count = packet.GetU32 (&offset);
+
+ for (uint32_t i=0; i<count; ++i)
+ {
+ const uint32_t cpu = packet.GetU32 (&offset);
+ const uint32_t exc = packet.GetU32 (&offset);
+ const uint32_t code = packet.GetU32 (&offset);
+ const uint32_t subcode = packet.GetU32 (&offset);
+ const char *exc_cstr = NULL;
+ switch (exc)
+ {
+ case 1: exc_cstr = "EXC_BAD_ACCESS"; break;
+ case 2: exc_cstr = "EXC_BAD_INSTRUCTION"; break;
+ case 3: exc_cstr = "EXC_ARITHMETIC"; break;
+ case 4: exc_cstr = "EXC_EMULATION"; break;
+ case 5: exc_cstr = "EXC_SOFTWARE"; break;
+ case 6: exc_cstr = "EXC_BREAKPOINT"; break;
+ case 7: exc_cstr = "EXC_SYSCALL"; break;
+ case 8: exc_cstr = "EXC_MACH_SYSCALL"; break;
+ case 9: exc_cstr = "EXC_RPC_ALERT"; break;
+ case 10: exc_cstr = "EXC_CRASH"; break;
+ default:
+ break;
+ }
+
+ s.Printf ("{ cpu = 0x%8.8x, exc = %s (%u), code = %u (0x%8.8x), subcode = %u (0x%8.8x)} ",
+ cpu, exc_cstr, exc, code, code, subcode, subcode);
+ }
+ }
+ break;
+
+ case KDP_TERMINATION:
+ {
+ const uint32_t term_code = packet.GetU32 (&offset);
+ const uint32_t exit_code = packet.GetU32 (&offset);
+ s.Printf(" (term_code = 0x%8.8x (%u), exit_code = 0x%8.8x (%u))", term_code, term_code, exit_code, exit_code);
+ }
+ break;
+
+ case KDP_REATTACH:
+ {
+ const uint16_t reply_port = ntohs(packet.GetU16 (&offset));
+ s.Printf(" (reply_port = %u)", reply_port);
+ }
+ break;
+
+ case KDP_READMSR64:
+ {
+ const uint32_t address = packet.GetU32 (&offset);
+ const uint16_t lcpu = packet.GetU16 (&offset);
+ s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x)", address, lcpu);
+ }
+ break;
+
+ case KDP_WRITEMSR64:
+ {
+ const uint32_t address = packet.GetU32 (&offset);
+ const uint16_t lcpu = packet.GetU16 (&offset);
+ const uint32_t nbytes = packet.GetByteSize() - offset;
+ s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x, nbytes=0x%8.8x)", lcpu, address, nbytes);
+ if (nbytes > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ 1, // Size of each item in bytes
+ nbytes, // Number of items
+ 16, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+
+ case KDP_READIOPORT:
+ {
+ const uint16_t lcpu = packet.GetU16 (&offset);
+ const uint16_t address = packet.GetU16 (&offset);
+ const uint16_t nbytes = packet.GetU16 (&offset);
+ s.Printf(" (lcpu=0x%4.4x, address=0x%4.4x, nbytes=%u)", lcpu, address, nbytes);
+ }
+ break;
+
+ case KDP_WRITEIOPORT:
+ {
+ const uint16_t lcpu = packet.GetU16 (&offset);
+ const uint16_t address = packet.GetU16 (&offset);
+ const uint16_t nbytes = packet.GetU16 (&offset);
+ s.Printf(" (lcpu = %u, addr = 0x%4.4x, nbytes = %u, bytes = \n", lcpu, address, nbytes);
+ if (nbytes > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ 1, // Size of each item in bytes
+ nbytes, // Number of items
+ 16, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+
+ case KDP_DUMPINFO:
+ {
+ const uint32_t count = packet.GetByteSize() - offset;
+ s.Printf(" (count = %u, bytes = \n", count);
+ if (count > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ 1, // Size of each item in bytes
+ count, // Number of items
+ 16, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+
+ }
+ break;
+
+ }
+ }
+ }
+ else
+ {
+ error_desc = "error: invalid packet command: ";
+ }
+ }
+
+ if (error_desc)
+ {
+ s.PutCString (error_desc);
+
+ packet.Dump (&s, // Stream to dump to
+ 0, // Offset into "packet"
+ eFormatBytes, // Dump as hex bytes
+ 1, // Size of each item is 1 for single bytes
+ packet.GetByteSize(), // Number of bytes
+ UINT32_MAX, // Num bytes per line
+ LLDB_INVALID_ADDRESS, // Base address
+ 0, 0); // Bitfield info set to not do anything bitfield related
+ }
+}
+
+uint32_t
+CommunicationKDP::SendRequestReadRegisters (uint32_t cpu,
+ uint32_t flavor,
+ void *dst,
+ uint32_t dst_len,
+ Error &error)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_READREGS;
+ // Size is header + 4 byte cpu and 4 byte flavor
+ const uint32_t command_length = 8 + 4 + 4;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutHex32 (cpu);
+ request_packet.PutHex32 (flavor);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ uint32_t kdp_error = reply_packet.GetU32 (&offset);
+ uint32_t src_len = reply_packet.GetByteSize() - 12;
+
+ if (src_len > 0)
+ {
+ const uint32_t bytes_to_copy = std::min<uint32_t>(src_len, dst_len);
+ const void *src = reply_packet.GetData(&offset, bytes_to_copy);
+ if (src)
+ {
+ ::memcpy (dst, src, bytes_to_copy);
+ error.Clear();
+ // Return the number of bytes we could have returned regardless if
+ // we copied them or not, just so we know when things don't match up
+ return src_len;
+ }
+ }
+ if (kdp_error)
+ error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u (error %u)", cpu, flavor, kdp_error);
+ else
+ error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u", cpu, flavor);
+ }
+ else
+ {
+ error.SetErrorString ("failed to send packet");
+ }
+ return 0;
+}
+
+uint32_t
+CommunicationKDP::SendRequestWriteRegisters (uint32_t cpu,
+ uint32_t flavor,
+ const void *src,
+ uint32_t src_len,
+ Error &error)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_WRITEREGS;
+ // Size is header + 4 byte cpu and 4 byte flavor
+ const uint32_t command_length = 8 + 4 + 4 + src_len;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutHex32 (cpu);
+ request_packet.PutHex32 (flavor);
+ request_packet.Write(src, src_len);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ uint32_t kdp_error = reply_packet.GetU32 (&offset);
+ if (kdp_error == 0)
+ return src_len;
+ error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u (error %u)", cpu, flavor, kdp_error);
+ }
+ else
+ {
+ error.SetErrorString ("failed to send packet");
+ }
+ return 0;
+}
+
+
+bool
+CommunicationKDP::SendRequestResume ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_RESUMECPUS;
+ const uint32_t command_length = 12;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutHex32(GetCPUMask());
+
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ return true;
+ return false;
+}
+
+bool
+CommunicationKDP::SendRequestBreakpoint (bool set, addr_t addr)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ bool use_64 = (GetVersion() >= 11);
+ uint32_t command_addr_byte_size = use_64 ? 8 : 4;
+ const CommandType command = set ? (use_64 ? KDP_BREAKPOINT_SET64 : KDP_BREAKPOINT_SET ):
+ (use_64 ? KDP_BREAKPOINT_REMOVE64 : KDP_BREAKPOINT_REMOVE);
+
+ const uint32_t command_length = 8 + command_addr_byte_size;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutMaxHex64 (addr, command_addr_byte_size);
+
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ uint32_t kdp_error = reply_packet.GetU32 (&offset);
+ if (kdp_error == 0)
+ return true;
+ }
+ return false;
+}
+
+bool
+CommunicationKDP::SendRequestSuspend ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_SUSPEND;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ return true;
+ return false;
+}
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h
new file mode 100644
index 000000000000..98a146d5a06d
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h
@@ -0,0 +1,347 @@
+//===-- CommunicationKDP.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_CommunicationKDP_h_
+#define liblldb_CommunicationKDP_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Core/StreamBuffer.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Host/TimeValue.h"
+
+class CommunicationKDP : public lldb_private::Communication
+{
+public:
+ enum
+ {
+ eBroadcastBitRunPacketSent = kLoUserBroadcastBit
+ };
+
+ const static uint32_t kMaxPacketSize = 1200;
+ const static uint32_t kMaxDataSize = 1024;
+ typedef lldb_private::StreamBuffer<1024> PacketStreamType;
+ typedef enum
+ {
+ KDP_CONNECT = 0u,
+ KDP_DISCONNECT,
+ KDP_HOSTINFO,
+ KDP_VERSION,
+ KDP_MAXBYTES,
+ KDP_READMEM,
+ KDP_WRITEMEM,
+ KDP_READREGS,
+ KDP_WRITEREGS,
+ KDP_LOAD,
+ KDP_IMAGEPATH,
+ KDP_SUSPEND,
+ KDP_RESUMECPUS,
+ KDP_EXCEPTION,
+ KDP_TERMINATION,
+ KDP_BREAKPOINT_SET,
+ KDP_BREAKPOINT_REMOVE,
+ KDP_REGIONS,
+ KDP_REATTACH,
+ KDP_HOSTREBOOT,
+ KDP_READMEM64,
+ KDP_WRITEMEM64,
+ KDP_BREAKPOINT_SET64,
+ KDP_BREAKPOINT_REMOVE64,
+ KDP_KERNELVERSION,
+ KDP_READPHYSMEM64,
+ KDP_WRITEPHYSMEM64,
+ KDP_READIOPORT,
+ KDP_WRITEIOPORT,
+ KDP_READMSR64,
+ KDP_WRITEMSR64,
+ KDP_DUMPINFO
+ } CommandType;
+
+ enum
+ {
+ KDP_FEATURE_BP = (1u << 0)
+ };
+
+ typedef enum
+ {
+ KDP_PROTERR_SUCCESS = 0,
+ KDP_PROTERR_ALREADY_CONNECTED,
+ KDP_PROTERR_BAD_NBYTES,
+ KDP_PROTERR_BADFLAVOR
+ } KDPError;
+
+ typedef enum
+ {
+ ePacketTypeRequest = 0x00u,
+ ePacketTypeReply = 0x80u,
+ ePacketTypeMask = 0x80u,
+ eCommandTypeMask = 0x7fu
+ } PacketType;
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommunicationKDP (const char *comm_name);
+
+ virtual
+ ~CommunicationKDP();
+
+ bool
+ SendRequestPacket (const PacketStreamType &request_packet);
+
+ // Wait for a packet within 'nsec' seconds
+ size_t
+ WaitForPacketWithTimeoutMicroSeconds (lldb_private::DataExtractor &response,
+ uint32_t usec);
+
+ bool
+ GetSequenceMutex(lldb_private::Mutex::Locker& locker);
+
+ bool
+ CheckForPacket (const uint8_t *src,
+ size_t src_len,
+ lldb_private::DataExtractor &packet);
+ bool
+ IsRunning() const
+ {
+ return m_is_running.GetValue();
+ }
+
+ //------------------------------------------------------------------
+ // Set the global packet timeout.
+ //
+ // For clients, this is the timeout that gets used when sending
+ // packets and waiting for responses. For servers, this might not
+ // get used, and if it doesn't this should be moved to the
+ // CommunicationKDPClient.
+ //------------------------------------------------------------------
+ uint32_t
+ SetPacketTimeout (uint32_t packet_timeout)
+ {
+ const uint32_t old_packet_timeout = m_packet_timeout;
+ m_packet_timeout = packet_timeout;
+ return old_packet_timeout;
+ }
+
+ uint32_t
+ GetPacketTimeoutInMicroSeconds () const
+ {
+ return m_packet_timeout * lldb_private::TimeValue::MicroSecPerSec;
+ }
+
+ //------------------------------------------------------------------
+ // Public Request Packets
+ //------------------------------------------------------------------
+ bool
+ SendRequestConnect (uint16_t reply_port,
+ uint16_t exc_port,
+ const char *greeting);
+
+ bool
+ SendRequestReattach (uint16_t reply_port);
+
+ bool
+ SendRequestDisconnect ();
+
+ uint32_t
+ SendRequestReadMemory (lldb::addr_t addr,
+ void *dst,
+ uint32_t dst_size,
+ lldb_private::Error &error);
+
+ uint32_t
+ SendRequestWriteMemory (lldb::addr_t addr,
+ const void *src,
+ uint32_t src_len,
+ lldb_private::Error &error);
+
+ bool
+ SendRawRequest (uint8_t command_byte,
+ const void *src,
+ uint32_t src_len,
+ lldb_private::DataExtractor &reply,
+ lldb_private::Error &error);
+
+ uint32_t
+ SendRequestReadRegisters (uint32_t cpu,
+ uint32_t flavor,
+ void *dst,
+ uint32_t dst_size,
+ lldb_private::Error &error);
+
+ uint32_t
+ SendRequestWriteRegisters (uint32_t cpu,
+ uint32_t flavor,
+ const void *src,
+ uint32_t src_size,
+ lldb_private::Error &error);
+
+ const char *
+ GetKernelVersion ();
+
+ // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection...
+ // const char *
+ // GetImagePath ();
+
+ uint32_t
+ GetVersion ();
+
+ uint32_t
+ GetFeatureFlags ();
+
+ bool
+ LocalBreakpointsAreSupported ()
+ {
+ return (GetFeatureFlags() & KDP_FEATURE_BP) != 0;
+ }
+
+ uint32_t
+ GetCPUMask ();
+
+ uint32_t
+ GetCPUType ();
+
+ uint32_t
+ GetCPUSubtype ();
+
+ lldb_private::UUID
+ GetUUID ();
+
+ bool
+ RemoteIsEFI ();
+
+ bool
+ RemoteIsDarwinKernel ();
+
+ lldb::addr_t
+ GetLoadAddress ();
+
+ bool
+ SendRequestResume ();
+
+ bool
+ SendRequestSuspend ();
+
+ bool
+ SendRequestBreakpoint (bool set, lldb::addr_t addr);
+
+protected:
+
+ bool
+ SendRequestPacketNoLock (const PacketStreamType &request_packet);
+
+ size_t
+ WaitForPacketWithTimeoutMicroSecondsNoLock (lldb_private::DataExtractor &response,
+ uint32_t timeout_usec);
+
+ bool
+ WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr);
+
+ void
+ MakeRequestPacketHeader (CommandType request_type,
+ PacketStreamType &request_packet,
+ uint16_t request_length);
+
+ //------------------------------------------------------------------
+ // Protected Request Packets (use public accessors which will cache
+ // results.
+ //------------------------------------------------------------------
+ bool
+ SendRequestVersion ();
+
+ bool
+ SendRequestHostInfo ();
+
+ bool
+ SendRequestKernelVersion ();
+
+ // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection...
+ //bool
+ //SendRequestImagePath ();
+
+ void
+ DumpPacket (lldb_private::Stream &s,
+ const void *data,
+ uint32_t data_len);
+
+ void
+ DumpPacket (lldb_private::Stream &s,
+ const lldb_private::DataExtractor& extractor);
+
+ bool
+ VersionIsValid() const
+ {
+ return m_kdp_version_version != 0;
+ }
+
+ bool
+ HostInfoIsValid() const
+ {
+ return m_kdp_hostinfo_cpu_type != 0;
+ }
+
+ bool
+ ExtractIsReply (uint8_t first_packet_byte) const
+ {
+ // TODO: handle big endian...
+ return (first_packet_byte & ePacketTypeMask) != 0;
+ }
+
+ CommandType
+ ExtractCommand (uint8_t first_packet_byte) const
+ {
+ // TODO: handle big endian...
+ return (CommandType)(first_packet_byte & eCommandTypeMask);
+ }
+
+ static const char *
+ GetCommandAsCString (uint8_t command);
+
+ void
+ ClearKDPSettings ();
+
+ bool
+ SendRequestAndGetReply (const CommandType command,
+ const PacketStreamType &request_packet,
+ lldb_private::DataExtractor &reply_packet);
+ //------------------------------------------------------------------
+ // Classes that inherit from CommunicationKDP can see and modify these
+ //------------------------------------------------------------------
+ uint32_t m_addr_byte_size;
+ lldb::ByteOrder m_byte_order;
+ uint32_t m_packet_timeout;
+ lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
+ lldb_private::Predicate<bool> m_is_running;
+ uint32_t m_session_key;
+ uint8_t m_request_sequence_id;
+ uint8_t m_exception_sequence_id;
+ uint32_t m_kdp_version_version;
+ uint32_t m_kdp_version_feature;
+ uint32_t m_kdp_hostinfo_cpu_mask;
+ uint32_t m_kdp_hostinfo_cpu_type;
+ uint32_t m_kdp_hostinfo_cpu_subtype;
+ std::string m_kernel_version;
+ //std::string m_image_path; // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection...
+ lldb::addr_t m_last_read_memory_addr; // Last memory read address for logging
+private:
+ //------------------------------------------------------------------
+ // For CommunicationKDP only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommunicationKDP);
+};
+
+#endif // liblldb_CommunicationKDP_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/Makefile b/source/Plugins/Process/MacOSX-Kernel/Makefile
new file mode 100644
index 000000000000..e42f390ffe0d
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Process/MacOSX-Darwin/Makefile -------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginProcessDarwin
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
new file mode 100644
index 000000000000..628f76d104fe
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
@@ -0,0 +1,1211 @@
+//===-- ProcessKDP.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+#include <stdlib.h>
+
+// C++ Includes
+#include <mutex>
+
+// Other libraries and framework includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionGroupString.h"
+#include "lldb/Interpreter/OptionGroupUInt64.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/StringExtractor.h"
+
+#define USEC_PER_SEC 1000000
+
+// Project includes
+#include "ProcessKDP.h"
+#include "ProcessKDPLog.h"
+#include "ThreadKDP.h"
+#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
+#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+ static PropertyDefinition
+ g_properties[] =
+ {
+ { "packet-timeout" , OptionValue::eTypeUInt64 , true , 5, NULL, NULL, "Specify the default packet timeout in seconds." },
+ { NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
+ };
+
+ enum
+ {
+ ePropertyPacketTimeout
+ };
+
+ class PluginProperties : public Properties
+ {
+ public:
+
+ static ConstString
+ GetSettingName ()
+ {
+ return ProcessKDP::GetPluginNameStatic();
+ }
+
+ PluginProperties() :
+ Properties ()
+ {
+ m_collection_sp.reset (new OptionValueProperties(GetSettingName()));
+ m_collection_sp->Initialize(g_properties);
+ }
+
+ virtual
+ ~PluginProperties()
+ {
+ }
+
+ uint64_t
+ GetPacketTimeout()
+ {
+ const uint32_t idx = ePropertyPacketTimeout;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value);
+ }
+ };
+
+ typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP;
+
+ static const ProcessKDPPropertiesSP &
+ GetGlobalPluginProperties()
+ {
+ static ProcessKDPPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ g_settings_sp.reset (new PluginProperties ());
+ return g_settings_sp;
+ }
+
+} // anonymous namespace end
+
+static const lldb::tid_t g_kernel_tid = 1;
+
+ConstString
+ProcessKDP::GetPluginNameStatic()
+{
+ static ConstString g_name("kdp-remote");
+ return g_name;
+}
+
+const char *
+ProcessKDP::GetPluginDescriptionStatic()
+{
+ return "KDP Remote protocol based debugging plug-in for darwin kernel debugging.";
+}
+
+void
+ProcessKDP::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessKDP::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessKDP::CreateInstance (TargetSP target_sp,
+ Listener &listener,
+ const FileSpec *crash_file_path)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == NULL)
+ process_sp.reset(new ProcessKDP (target_sp, listener));
+ return process_sp;
+}
+
+bool
+ProcessKDP::CanDebug(TargetSP target_sp, bool plugin_specified_by_name)
+{
+ if (plugin_specified_by_name)
+ return true;
+
+ // For now we are just making sure the file exists for a given module
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+ if (exe_module)
+ {
+ const llvm::Triple &triple_ref = target_sp->GetArchitecture().GetTriple();
+ switch (triple_ref.getOS())
+ {
+ case llvm::Triple::Darwin: // Should use "macosx" for desktop and "ios" for iOS, but accept darwin just in case
+ case llvm::Triple::MacOSX: // For desktop targets
+ case llvm::Triple::IOS: // For arm targets
+ case llvm::Triple::TvOS:
+ case llvm::Triple::WatchOS:
+ if (triple_ref.getVendor() == llvm::Triple::Apple)
+ {
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ if (exe_objfile->GetType() == ObjectFile::eTypeExecutable &&
+ exe_objfile->GetStrata() == ObjectFile::eStrataKernel)
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessKDP constructor
+//----------------------------------------------------------------------
+ProcessKDP::ProcessKDP(TargetSP target_sp, Listener &listener) :
+ Process (target_sp, listener),
+ m_comm("lldb.process.kdp-remote.communication"),
+ m_async_broadcaster (NULL, "lldb.process.kdp-remote.async-broadcaster"),
+ m_dyld_plugin_name (),
+ m_kernel_load_addr (LLDB_INVALID_ADDRESS),
+ m_command_sp(),
+ m_kernel_thread_wp()
+{
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit");
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue");
+ const uint64_t timeout_seconds = GetGlobalPluginProperties()->GetPacketTimeout();
+ if (timeout_seconds > 0)
+ m_comm.SetPacketTimeout(timeout_seconds);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessKDP::~ProcessKDP()
+{
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+lldb_private::ConstString
+ProcessKDP::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessKDP::GetPluginVersion()
+{
+ return 1;
+}
+
+Error
+ProcessKDP::WillLaunch (Module* module)
+{
+ Error error;
+ error.SetErrorString ("launching not supported in kdp-remote plug-in");
+ return error;
+}
+
+Error
+ProcessKDP::WillAttachToProcessWithID (lldb::pid_t pid)
+{
+ Error error;
+ error.SetErrorString ("attaching to a by process ID not supported in kdp-remote plug-in");
+ return error;
+}
+
+Error
+ProcessKDP::WillAttachToProcessWithName (const char *process_name, bool wait_for_launch)
+{
+ Error error;
+ error.SetErrorString ("attaching to a by process name not supported in kdp-remote plug-in");
+ return error;
+}
+
+bool
+ProcessKDP::GetHostArchitecture(ArchSpec &arch)
+{
+ uint32_t cpu = m_comm.GetCPUType();
+ if (cpu)
+ {
+ uint32_t sub = m_comm.GetCPUSubtype();
+ arch.SetArchitecture(eArchTypeMachO, cpu, sub);
+ // Leave architecture vendor as unspecified unknown
+ arch.GetTriple().setVendor(llvm::Triple::UnknownVendor);
+ arch.GetTriple().setVendorName(llvm::StringRef());
+ return true;
+ }
+ arch.Clear();
+ return false;
+}
+
+Error
+ProcessKDP::DoConnectRemote (Stream *strm, const char *remote_url)
+{
+ Error error;
+
+ // Don't let any JIT happen when doing KDP as we can't allocate
+ // memory and we don't want to be mucking with threads that might
+ // already be handling exceptions
+ SetCanJIT(false);
+
+ if (remote_url == NULL || remote_url[0] == '\0')
+ {
+ error.SetErrorStringWithFormat ("invalid connection URL '%s'", remote_url);
+ return error;
+ }
+
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
+ {
+ // Only try once for now.
+ // TODO: check if we should be retrying?
+ const uint32_t max_retry_count = 1;
+ for (uint32_t retry_count = 0; retry_count < max_retry_count; ++retry_count)
+ {
+ if (conn_ap->Connect(remote_url, &error) == eConnectionStatusSuccess)
+ break;
+ usleep (100000);
+ }
+ }
+
+ if (conn_ap->IsConnected())
+ {
+ const TCPSocket& socket = static_cast<const TCPSocket&>(*conn_ap->GetReadObject());
+ const uint16_t reply_port = socket.GetLocalPortNumber();
+
+ if (reply_port != 0)
+ {
+ m_comm.SetConnection(conn_ap.release());
+
+ if (m_comm.SendRequestReattach(reply_port))
+ {
+ if (m_comm.SendRequestConnect(reply_port, reply_port, "Greetings from LLDB..."))
+ {
+ m_comm.GetVersion();
+
+ Target &target = GetTarget();
+ ArchSpec kernel_arch;
+ // The host architecture
+ GetHostArchitecture(kernel_arch);
+ ArchSpec target_arch = target.GetArchitecture();
+ // Merge in any unspecified stuff into the target architecture in
+ // case the target arch isn't set at all or incompletely.
+ target_arch.MergeFrom(kernel_arch);
+ target.SetArchitecture(target_arch);
+
+ /* Get the kernel's UUID and load address via KDP_KERNELVERSION packet. */
+ /* An EFI kdp session has neither UUID nor load address. */
+
+ UUID kernel_uuid = m_comm.GetUUID ();
+ addr_t kernel_load_addr = m_comm.GetLoadAddress ();
+
+ if (m_comm.RemoteIsEFI ())
+ {
+ // Select an invalid plugin name for the dynamic loader so one doesn't get used
+ // since EFI does its own manual loading via python scripting
+ static ConstString g_none_dynamic_loader("none");
+ m_dyld_plugin_name = g_none_dynamic_loader;
+
+ if (kernel_uuid.IsValid()) {
+ // If EFI passed in a UUID= try to lookup UUID
+ // The slide will not be provided. But the UUID
+ // lookup will be used to launch EFI debug scripts
+ // from the dSYM, that can load all of the symbols.
+ ModuleSpec module_spec;
+ module_spec.GetUUID() = kernel_uuid;
+ module_spec.GetArchitecture() = target.GetArchitecture();
+
+ // Lookup UUID locally, before attempting dsymForUUID like action
+ module_spec.GetSymbolFileSpec() = Symbols::LocateExecutableSymbolFile(module_spec);
+ if (module_spec.GetSymbolFileSpec())
+ {
+ ModuleSpec executable_module_spec = Symbols::LocateExecutableObjectFile (module_spec);
+ if (executable_module_spec.GetFileSpec().Exists())
+ {
+ module_spec.GetFileSpec() = executable_module_spec.GetFileSpec();
+ }
+ }
+ if (!module_spec.GetSymbolFileSpec() || !module_spec.GetSymbolFileSpec())
+ Symbols::DownloadObjectAndSymbolFile (module_spec, true);
+
+ if (module_spec.GetFileSpec().Exists())
+ {
+ ModuleSP module_sp(new Module (module_spec));
+ if (module_sp.get() && module_sp->GetObjectFile())
+ {
+ // Get the current target executable
+ ModuleSP exe_module_sp (target.GetExecutableModule ());
+
+ // Make sure you don't already have the right module loaded and they will be uniqued
+ if (exe_module_sp.get() != module_sp.get())
+ target.SetExecutableModule (module_sp, false);
+ }
+ }
+ }
+ }
+ else if (m_comm.RemoteIsDarwinKernel ())
+ {
+ m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
+ if (kernel_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_kernel_load_addr = kernel_load_addr;
+ }
+ }
+
+ // Set the thread ID
+ UpdateThreadListIfNeeded ();
+ SetID (1);
+ GetThreadList ();
+ SetPrivateState (eStateStopped);
+ StreamSP async_strm_sp(target.GetDebugger().GetAsyncOutputStream());
+ if (async_strm_sp)
+ {
+ const char *cstr;
+ if ((cstr = m_comm.GetKernelVersion ()) != NULL)
+ {
+ async_strm_sp->Printf ("Version: %s\n", cstr);
+ async_strm_sp->Flush();
+ }
+// if ((cstr = m_comm.GetImagePath ()) != NULL)
+// {
+// async_strm_sp->Printf ("Image Path: %s\n", cstr);
+// async_strm_sp->Flush();
+// }
+ }
+ }
+ else
+ {
+ error.SetErrorString("KDP_REATTACH failed");
+ }
+ }
+ else
+ {
+ error.SetErrorString("KDP_REATTACH failed");
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid reply port from UDP connection");
+ }
+ }
+ else
+ {
+ if (error.Success())
+ error.SetErrorStringWithFormat ("failed to connect to '%s'", remote_url);
+ }
+ if (error.Fail())
+ m_comm.Disconnect();
+
+ return error;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessKDP::DoLaunch (Module *exe_module,
+ ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ error.SetErrorString ("launching not supported in kdp-remote plug-in");
+ return error;
+}
+
+Error
+ProcessKDP::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info)
+{
+ Error error;
+ error.SetErrorString ("attach to process by ID is not suppported in kdp remote debugging");
+ return error;
+}
+
+Error
+ProcessKDP::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info)
+{
+ Error error;
+ error.SetErrorString ("attach to process by name is not suppported in kdp remote debugging");
+ return error;
+}
+
+
+void
+ProcessKDP::DidAttach (ArchSpec &process_arch)
+{
+ Process::DidAttach(process_arch);
+
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessKDP::DidAttach()");
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ GetHostArchitecture(process_arch);
+ }
+}
+
+addr_t
+ProcessKDP::GetImageInfoAddress()
+{
+ return m_kernel_load_addr;
+}
+
+lldb_private::DynamicLoader *
+ProcessKDP::GetDynamicLoader ()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, m_dyld_plugin_name.IsEmpty() ? NULL : m_dyld_plugin_name.GetCString()));
+ return m_dyld_ap.get();
+}
+
+Error
+ProcessKDP::WillResume ()
+{
+ return Error();
+}
+
+Error
+ProcessKDP::DoResume ()
+{
+ Error error;
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS));
+ // Only start the async thread if we try to do any process control
+ if (!m_async_thread.IsJoinable())
+ StartAsyncThread();
+
+ bool resume = false;
+
+ // With KDP there is only one thread we can tell what to do
+ ThreadSP kernel_thread_sp (m_thread_list.FindThreadByProtocolID(g_kernel_tid));
+
+ if (kernel_thread_sp)
+ {
+ const StateType thread_resume_state = kernel_thread_sp->GetTemporaryResumeState();
+
+ if (log)
+ log->Printf ("ProcessKDP::DoResume() thread_resume_state = %s", StateAsCString(thread_resume_state));
+ switch (thread_resume_state)
+ {
+ case eStateSuspended:
+ // Nothing to do here when a thread will stay suspended
+ // we just leave the CPU mask bit set to zero for the thread
+ if (log)
+ log->Printf ("ProcessKDP::DoResume() = suspended???");
+ break;
+
+ case eStateStepping:
+ {
+ lldb::RegisterContextSP reg_ctx_sp (kernel_thread_sp->GetRegisterContext());
+
+ if (reg_ctx_sp)
+ {
+ if (log)
+ log->Printf ("ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (true);");
+ reg_ctx_sp->HardwareSingleStep (true);
+ resume = true;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("KDP thread 0x%llx has no register context", kernel_thread_sp->GetID());
+ }
+ }
+ break;
+
+ case eStateRunning:
+ {
+ lldb::RegisterContextSP reg_ctx_sp (kernel_thread_sp->GetRegisterContext());
+
+ if (reg_ctx_sp)
+ {
+ if (log)
+ log->Printf ("ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (false);");
+ reg_ctx_sp->HardwareSingleStep (false);
+ resume = true;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("KDP thread 0x%llx has no register context", kernel_thread_sp->GetID());
+ }
+ }
+ break;
+
+ default:
+ // The only valid thread resume states are listed above
+ assert (!"invalid thread resume state");
+ break;
+ }
+ }
+
+ if (resume)
+ {
+ if (log)
+ log->Printf ("ProcessKDP::DoResume () sending resume");
+
+ if (m_comm.SendRequestResume ())
+ {
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue);
+ SetPrivateState(eStateRunning);
+ }
+ else
+ error.SetErrorString ("KDP resume failed");
+ }
+ else
+ {
+ error.SetErrorString ("kernel thread is suspended");
+ }
+
+ return error;
+}
+
+lldb::ThreadSP
+ProcessKDP::GetKernelThread()
+{
+ // KDP only tells us about one thread/core. Any other threads will usually
+ // be the ones that are read from memory by the OS plug-ins.
+
+ ThreadSP thread_sp (m_kernel_thread_wp.lock());
+ if (!thread_sp)
+ {
+ thread_sp.reset(new ThreadKDP (*this, g_kernel_tid));
+ m_kernel_thread_wp = thread_sp;
+ }
+ return thread_sp;
+}
+
+
+
+
+bool
+ProcessKDP::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_THREAD));
+ if (log && log->GetMask().Test(KDP_LOG_VERBOSE))
+ log->Printf ("ProcessKDP::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID());
+
+ // Even though there is a CPU mask, it doesn't mean we can see each CPU
+ // individually, there is really only one. Lets call this thread 1.
+ ThreadSP thread_sp (old_thread_list.FindThreadByProtocolID(g_kernel_tid, false));
+ if (!thread_sp)
+ thread_sp = GetKernelThread ();
+ new_thread_list.AddThread(thread_sp);
+
+ return new_thread_list.GetSize(false) > 0;
+}
+
+void
+ProcessKDP::RefreshStateAfterStop ()
+{
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_thread_list.RefreshStateAfterStop();
+}
+
+Error
+ProcessKDP::DoHalt (bool &caused_stop)
+{
+ Error error;
+
+ if (m_comm.IsRunning())
+ {
+ if (m_destroy_in_process)
+ {
+ // If we are attemping to destroy, we need to not return an error to
+ // Halt or DoDestroy won't get called.
+ // We are also currently running, so send a process stopped event
+ SetPrivateState (eStateStopped);
+ }
+ else
+ {
+ error.SetErrorString ("KDP cannot interrupt a running kernel");
+ }
+ }
+ return error;
+}
+
+Error
+ProcessKDP::DoDetach(bool keep_stopped)
+{
+ Error error;
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessKDP::DoDetach(keep_stopped = %i)", keep_stopped);
+
+ if (m_comm.IsRunning())
+ {
+ // We are running and we can't interrupt a running kernel, so we need
+ // to just close the connection to the kernel and hope for the best
+ }
+ else
+ {
+ // If we are going to keep the target stopped, then don't send the disconnect message.
+ if (!keep_stopped && m_comm.IsConnected())
+ {
+ const bool success = m_comm.SendRequestDisconnect();
+ if (log)
+ {
+ if (success)
+ log->PutCString ("ProcessKDP::DoDetach() detach packet sent successfully");
+ else
+ log->PutCString ("ProcessKDP::DoDetach() connection channel shutdown failed");
+ }
+ m_comm.Disconnect ();
+ }
+ }
+ StopAsyncThread ();
+ m_comm.Clear();
+
+ SetPrivateState (eStateDetached);
+ ResumePrivateStateThread();
+
+ //KillDebugserverProcess ();
+ return error;
+}
+
+Error
+ProcessKDP::DoDestroy ()
+{
+ // For KDP there really is no difference between destroy and detach
+ bool keep_stopped = false;
+ return DoDetach(keep_stopped);
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessKDP::IsAlive ()
+{
+ return m_comm.IsConnected() && Process::IsAlive();
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessKDP::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error)
+{
+ uint8_t *data_buffer = (uint8_t *) buf;
+ if (m_comm.IsConnected())
+ {
+ const size_t max_read_size = 512;
+ size_t total_bytes_read = 0;
+
+ // Read the requested amount of memory in 512 byte chunks
+ while (total_bytes_read < size)
+ {
+ size_t bytes_to_read_this_request = size - total_bytes_read;
+ if (bytes_to_read_this_request > max_read_size)
+ {
+ bytes_to_read_this_request = max_read_size;
+ }
+ size_t bytes_read = m_comm.SendRequestReadMemory (addr + total_bytes_read,
+ data_buffer + total_bytes_read,
+ bytes_to_read_this_request, error);
+ total_bytes_read += bytes_read;
+ if (error.Fail() || bytes_read == 0)
+ {
+ return total_bytes_read;
+ }
+ }
+
+ return total_bytes_read;
+ }
+ error.SetErrorString ("not connected");
+ return 0;
+}
+
+size_t
+ProcessKDP::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
+{
+ if (m_comm.IsConnected())
+ return m_comm.SendRequestWriteMemory (addr, buf, size, error);
+ error.SetErrorString ("not connected");
+ return 0;
+}
+
+lldb::addr_t
+ProcessKDP::DoAllocateMemory (size_t size, uint32_t permissions, Error &error)
+{
+ error.SetErrorString ("memory allocation not suppported in kdp remote debugging");
+ return LLDB_INVALID_ADDRESS;
+}
+
+Error
+ProcessKDP::DoDeallocateMemory (lldb::addr_t addr)
+{
+ Error error;
+ error.SetErrorString ("memory deallocation not suppported in kdp remote debugging");
+ return error;
+}
+
+Error
+ProcessKDP::EnableBreakpointSite (BreakpointSite *bp_site)
+{
+ if (m_comm.LocalBreakpointsAreSupported ())
+ {
+ Error error;
+ if (!bp_site->IsEnabled())
+ {
+ if (m_comm.SendRequestBreakpoint(true, bp_site->GetLoadAddress()))
+ {
+ bp_site->SetEnabled(true);
+ bp_site->SetType (BreakpointSite::eExternal);
+ }
+ else
+ {
+ error.SetErrorString ("KDP set breakpoint failed");
+ }
+ }
+ return error;
+ }
+ return EnableSoftwareBreakpoint (bp_site);
+}
+
+Error
+ProcessKDP::DisableBreakpointSite (BreakpointSite *bp_site)
+{
+ if (m_comm.LocalBreakpointsAreSupported ())
+ {
+ Error error;
+ if (bp_site->IsEnabled())
+ {
+ BreakpointSite::Type bp_type = bp_site->GetType();
+ if (bp_type == BreakpointSite::eExternal)
+ {
+ if (m_destroy_in_process && m_comm.IsRunning())
+ {
+ // We are trying to destroy our connection and we are running
+ bp_site->SetEnabled(false);
+ }
+ else
+ {
+ if (m_comm.SendRequestBreakpoint(false, bp_site->GetLoadAddress()))
+ bp_site->SetEnabled(false);
+ else
+ error.SetErrorString ("KDP remove breakpoint failed");
+ }
+ }
+ else
+ {
+ error = DisableSoftwareBreakpoint (bp_site);
+ }
+ }
+ return error;
+ }
+ return DisableSoftwareBreakpoint (bp_site);
+}
+
+Error
+ProcessKDP::EnableWatchpoint (Watchpoint *wp, bool notify)
+{
+ Error error;
+ error.SetErrorString ("watchpoints are not suppported in kdp remote debugging");
+ return error;
+}
+
+Error
+ProcessKDP::DisableWatchpoint (Watchpoint *wp, bool notify)
+{
+ Error error;
+ error.SetErrorString ("watchpoints are not suppported in kdp remote debugging");
+ return error;
+}
+
+void
+ProcessKDP::Clear()
+{
+ m_thread_list.Clear();
+}
+
+Error
+ProcessKDP::DoSignal (int signo)
+{
+ Error error;
+ error.SetErrorString ("sending signals is not suppported in kdp remote debugging");
+ return error;
+}
+
+void
+ProcessKDP::Initialize()
+{
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, []()
+ {
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ DebuggerInitialize);
+
+ Log::Callbacks log_callbacks = {
+ ProcessKDPLog::DisableLog,
+ ProcessKDPLog::EnableLog,
+ ProcessKDPLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessKDP::GetPluginNameStatic(), log_callbacks);
+ });
+}
+
+void
+ProcessKDP::DebuggerInitialize (lldb_private::Debugger &debugger)
+{
+ if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName()))
+ {
+ const bool is_global_setting = true;
+ PluginManager::CreateSettingForProcessPlugin (debugger,
+ GetGlobalPluginProperties()->GetValueProperties(),
+ ConstString ("Properties for the kdp-remote process plug-in."),
+ is_global_setting);
+ }
+}
+
+bool
+ProcessKDP::StartAsyncThread ()
+{
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessKDP::StartAsyncThread ()");
+
+ if (m_async_thread.IsJoinable())
+ return true;
+
+ m_async_thread = ThreadLauncher::LaunchThread("<lldb.process.kdp-remote.async>", ProcessKDP::AsyncThread, this, NULL);
+ return m_async_thread.IsJoinable();
+}
+
+void
+ProcessKDP::StopAsyncThread ()
+{
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessKDP::StopAsyncThread ()");
+
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit);
+
+ // Stop the stdio thread
+ if (m_async_thread.IsJoinable())
+ m_async_thread.Join(nullptr);
+}
+
+
+void *
+ProcessKDP::AsyncThread (void *arg)
+{
+ ProcessKDP *process = (ProcessKDP*) arg;
+
+ const lldb::pid_t pid = process->GetID();
+
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 ") thread starting...", arg, pid);
+
+ Listener listener ("ProcessKDP::AsyncThread");
+ EventSP event_sp;
+ const uint32_t desired_event_mask = eBroadcastBitAsyncContinue |
+ eBroadcastBitAsyncThreadShouldExit;
+
+
+ if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask)
+ {
+ bool done = false;
+ while (!done)
+ {
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...",
+ pid);
+ if (listener.WaitForEvent (NULL, event_sp))
+ {
+ uint32_t event_type = event_sp->GetType();
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") Got an event of type: %d...",
+ pid,
+ event_type);
+
+ // When we are running, poll for 1 second to try and get an exception
+ // to indicate the process has stopped. If we don't get one, check to
+ // make sure no one asked us to exit
+ bool is_running = false;
+ DataExtractor exc_reply_packet;
+ do
+ {
+ switch (event_type)
+ {
+ case eBroadcastBitAsyncContinue:
+ {
+ is_running = true;
+ if (process->m_comm.WaitForPacketWithTimeoutMicroSeconds (exc_reply_packet, 1 * USEC_PER_SEC))
+ {
+ ThreadSP thread_sp (process->GetKernelThread());
+ if (thread_sp)
+ {
+ lldb::RegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext());
+ if (reg_ctx_sp)
+ reg_ctx_sp->InvalidateAllRegisters();
+ static_cast<ThreadKDP *>(thread_sp.get())->SetStopInfoFrom_KDP_EXCEPTION (exc_reply_packet);
+ }
+
+ // TODO: parse the stop reply packet
+ is_running = false;
+ process->SetPrivateState(eStateStopped);
+ }
+ else
+ {
+ // Check to see if we are supposed to exit. There is no way to
+ // interrupt a running kernel, so all we can do is wait for an
+ // exception or detach...
+ if (listener.GetNextEvent(event_sp))
+ {
+ // We got an event, go through the loop again
+ event_type = event_sp->GetType();
+ }
+ }
+ }
+ break;
+
+ case eBroadcastBitAsyncThreadShouldExit:
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...",
+ pid);
+ done = true;
+ is_running = false;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") got unknown event 0x%8.8x",
+ pid,
+ event_type);
+ done = true;
+ is_running = false;
+ break;
+ }
+ } while (is_running);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false",
+ pid);
+ done = true;
+ }
+ }
+ }
+
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 ") thread exiting...",
+ arg,
+ pid);
+
+ process->m_async_thread.Reset();
+ return NULL;
+}
+
+
+class CommandObjectProcessKDPPacketSend : public CommandObjectParsed
+{
+private:
+
+ OptionGroupOptions m_option_group;
+ OptionGroupUInt64 m_command_byte;
+ OptionGroupString m_packet_data;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+
+public:
+ CommandObjectProcessKDPPacketSend(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet send",
+ "Send a custom packet through the KDP protocol by specifying the command byte and the packet payload data. A packet will be sent with a correct header and payload, and the raw result bytes will be displayed as a string value. ",
+ NULL),
+ m_option_group (interpreter),
+ m_command_byte(LLDB_OPT_SET_1, true , "command", 'c', 0, eArgTypeNone, "Specify the command byte to use when sending the KDP request packet.", 0),
+ m_packet_data (LLDB_OPT_SET_1, false, "payload", 'p', 0, eArgTypeNone, "Specify packet payload bytes as a hex ASCII string with no spaces or hex prefixes.", NULL)
+ {
+ m_option_group.Append (&m_command_byte, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_packet_data , LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectProcessKDPPacketSend ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ if (!m_command_byte.GetOptionValue().OptionWasSet())
+ {
+ result.AppendError ("the --command option must be set to a valid command byte");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ const uint64_t command_byte = m_command_byte.GetOptionValue().GetUInt64Value(0);
+ if (command_byte > 0 && command_byte <= UINT8_MAX)
+ {
+ ProcessKDP *process = (ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ const StateType state = process->GetState();
+
+ if (StateIsStoppedState (state, true))
+ {
+ std::vector<uint8_t> payload_bytes;
+ const char *ascii_hex_bytes_cstr = m_packet_data.GetOptionValue().GetCurrentValue();
+ if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0])
+ {
+ StringExtractor extractor(ascii_hex_bytes_cstr);
+ const size_t ascii_hex_bytes_cstr_len = extractor.GetStringRef().size();
+ if (ascii_hex_bytes_cstr_len & 1)
+ {
+ result.AppendErrorWithFormat ("payload data must contain an even number of ASCII hex characters: '%s'", ascii_hex_bytes_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ payload_bytes.resize(ascii_hex_bytes_cstr_len/2);
+ if (extractor.GetHexBytes(&payload_bytes[0], payload_bytes.size(), '\xdd') != payload_bytes.size())
+ {
+ result.AppendErrorWithFormat ("payload data must only contain ASCII hex characters (no spaces or hex prefixes): '%s'", ascii_hex_bytes_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ Error error;
+ DataExtractor reply;
+ process->GetCommunication().SendRawRequest (command_byte,
+ payload_bytes.empty() ? NULL : payload_bytes.data(),
+ payload_bytes.size(),
+ reply,
+ error);
+
+ if (error.Success())
+ {
+ // Copy the binary bytes into a hex ASCII string for the result
+ StreamString packet;
+ packet.PutBytesAsRawHex8(reply.GetDataStart(),
+ reply.GetByteSize(),
+ endian::InlHostByteOrder(),
+ endian::InlHostByteOrder());
+ result.AppendMessage(packet.GetString().c_str());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ else
+ {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr && error_cstr[0])
+ result.AppendError (error_cstr);
+ else
+ result.AppendErrorWithFormat ("unknown error 0x%8.8x", error.GetError());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("process must be stopped in order to send KDP packets, state is %s", StateAsCString (state));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid process");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid command byte 0x%" PRIx64 ", valid values are 1 - 255", command_byte);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' takes no arguments, only options.", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return false;
+ }
+};
+
+class CommandObjectProcessKDPPacket : public CommandObjectMultiword
+{
+private:
+
+public:
+ CommandObjectProcessKDPPacket(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process plugin packet",
+ "Commands that deal with KDP remote packets.",
+ NULL)
+ {
+ LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessKDPPacketSend (interpreter)));
+ }
+
+ ~CommandObjectProcessKDPPacket ()
+ {
+ }
+};
+
+class CommandObjectMultiwordProcessKDP : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordProcessKDP (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process plugin",
+ "A set of commands for operating on a ProcessKDP process.",
+ "process plugin <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("packet", CommandObjectSP (new CommandObjectProcessKDPPacket (interpreter)));
+ }
+
+ ~CommandObjectMultiwordProcessKDP ()
+ {
+ }
+};
+
+CommandObject *
+ProcessKDP::GetPluginCommandObject()
+{
+ if (!m_command_sp)
+ m_command_sp.reset (new CommandObjectMultiwordProcessKDP (GetTarget().GetDebugger().GetCommandInterpreter()));
+ return m_command_sp.get();
+}
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
new file mode 100644
index 000000000000..fe9a4e2844bf
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
@@ -0,0 +1,274 @@
+//===-- ProcessKDP.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_ProcessKDP_h_
+#define liblldb_ProcessKDP_h_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "CommunicationKDP.h"
+
+class ThreadKDP;
+
+class ProcessKDP : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance (lldb::TargetSP target_sp,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ DebuggerInitialize (lldb_private::Debugger &debugger);
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessKDP(lldb::TargetSP target_sp, lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessKDP();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug (lldb::TargetSP target_sp,
+ bool plugin_specified_by_name);
+
+ virtual lldb_private::CommandObject *
+ GetPluginCommandObject();
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillLaunch (lldb_private::Module* module);
+
+ virtual lldb_private::Error
+ DoLaunch (lldb_private::Module *exe_module,
+ lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual lldb_private::Error
+ WillAttachToProcessWithID (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ WillAttachToProcessWithName (const char *process_name, bool wait_for_launch);
+
+ virtual lldb_private::Error
+ DoConnectRemote (lldb_private::Stream *strm, const char *remote_url);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithName (const char *process_name, const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual void
+ DidAttach (lldb_private::ArchSpec &process_arch);
+
+ lldb::addr_t
+ GetImageInfoAddress();
+
+ lldb_private::DynamicLoader *
+ GetDynamicLoader ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillResume ();
+
+ virtual lldb_private::Error
+ DoResume ();
+
+ virtual lldb_private::Error
+ DoHalt (bool &caused_stop);
+
+ virtual lldb_private::Error
+ DoDetach (bool keep_stopped);
+
+ virtual lldb_private::Error
+ DoSignal (int signal);
+
+ virtual lldb_private::Error
+ DoDestroy ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ virtual bool
+ IsAlive ();
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ virtual size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+
+ virtual size_t
+ DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error);
+
+ virtual lldb_private::Error
+ DoDeallocateMemory (lldb::addr_t ptr);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableBreakpointSite (lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpointSite (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ DisableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true);
+
+ CommunicationKDP &
+ GetCommunication()
+ {
+ return m_comm;
+ }
+
+protected:
+ friend class ThreadKDP;
+ friend class CommunicationKDP;
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ bool
+ IsRunning ( lldb::StateType state )
+ {
+ return state == lldb::eStateRunning || IsStepping(state);
+ }
+
+ bool
+ IsStepping ( lldb::StateType state)
+ {
+ return state == lldb::eStateStepping;
+ }
+
+ bool
+ CanResume ( lldb::StateType state)
+ {
+ return state == lldb::eStateStopped;
+ }
+
+ bool
+ HasExited (lldb::StateType state)
+ {
+ return state == lldb::eStateExited;
+ }
+
+ bool
+ GetHostArchitecture (lldb_private::ArchSpec &arch);
+
+ bool
+ ProcessIDIsValid ( ) const;
+
+ void
+ Clear ( );
+
+ virtual bool
+ UpdateThreadList (lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list);
+
+ enum
+ {
+ eBroadcastBitAsyncContinue = (1 << 0),
+ eBroadcastBitAsyncThreadShouldExit = (1 << 1)
+ };
+
+ lldb::ThreadSP
+ GetKernelThread ();
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ CommunicationKDP m_comm;
+ lldb_private::Broadcaster m_async_broadcaster;
+ lldb_private::HostThread m_async_thread;
+ lldb_private::ConstString m_dyld_plugin_name;
+ lldb::addr_t m_kernel_load_addr;
+ lldb::CommandObjectSP m_command_sp;
+ lldb::ThreadWP m_kernel_thread_wp;
+
+
+ bool
+ StartAsyncThread ();
+
+ void
+ StopAsyncThread ();
+
+ static void *
+ AsyncThread (void *arg);
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessKDP only
+ //------------------------------------------------------------------
+
+ DISALLOW_COPY_AND_ASSIGN (ProcessKDP);
+
+};
+
+#endif // liblldb_ProcessKDP_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp
new file mode 100644
index 000000000000..79cb62aa0066
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp
@@ -0,0 +1,186 @@
+//===-- ProcessKDPLog.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessKDPLog.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessKDP.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_log_sp the first time this function is
+// called.
+static bool g_log_enabled = false;
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+Log *
+ProcessKDPLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+ProcessKDPLog::DisableLog (const char **categories, Stream *feedback_strm)
+{
+ Log *log (GetLog ());
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+
+ if (categories[0] != NULL)
+ {
+ flag_bits = log->GetMask().Get();
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits &= ~KDP_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) flag_bits &= ~KDP_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits &= ~KDP_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits &= ~KDP_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits &= ~KDP_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits &= ~KDP_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits &= ~KDP_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~KDP_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits &= ~KDP_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits &= ~KDP_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits &= ~KDP_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits &= ~KDP_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits &= ~KDP_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits &= ~KDP_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ }
+
+ }
+ }
+
+ log->GetMask().Reset (flag_bits);
+ if (flag_bits == 0)
+ g_log_enabled = false;
+ }
+
+ return;
+}
+
+Log *
+ProcessKDPLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits = 0;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ bool got_unknown_category = false;
+ for (size_t i=0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits |= KDP_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) flag_bits |= KDP_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits |= KDP_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits |= KDP_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= KDP_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits |= KDP_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= KDP_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= KDP_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= KDP_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= KDP_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= KDP_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= KDP_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= KDP_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits |= KDP_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = KDP_LOG_DEFAULT;
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ }
+ g_log_enabled = true;
+ return g_log;
+}
+
+void
+ProcessKDPLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " async - log asynchronous activity\n"
+ " break - log breakpoints\n"
+ " communication - log communication activity\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " packets - log gdb remote packets\n"
+ " memory - log memory reads and writes\n"
+ " data-short - log memory bytes for memory reads and writes for short transactions only\n"
+ " data-long - log memory bytes for memory reads and writes for all transactions\n"
+ " process - log process events and activities\n"
+ " thread - log thread events and activities\n"
+ " step - log step related activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n",
+ ProcessKDP::GetPluginNameStatic().GetCString());
+}
+
+
+void
+ProcessKDPLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h
new file mode 100644
index 000000000000..0cb32d9b2dcf
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h
@@ -0,0 +1,54 @@
+//===-- ProcessKDPLog.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_ProcessKDPLog_h_
+#define liblldb_ProcessKDPLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define KDP_LOG_VERBOSE (1u << 0)
+#define KDP_LOG_PROCESS (1u << 1)
+#define KDP_LOG_THREAD (1u << 2)
+#define KDP_LOG_PACKETS (1u << 3)
+#define KDP_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define KDP_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define KDP_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define KDP_LOG_BREAKPOINTS (1u << 7)
+#define KDP_LOG_WATCHPOINTS (1u << 8)
+#define KDP_LOG_STEP (1u << 9)
+#define KDP_LOG_COMM (1u << 10)
+#define KDP_LOG_ASYNC (1u << 11)
+#define KDP_LOG_ALL (UINT32_MAX)
+#define KDP_LOG_DEFAULT KDP_LOG_PACKETS
+
+class ProcessKDPLog
+{
+public:
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static void
+ DisableLog (const char **categories, lldb_private::Stream *feedback_strm);
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_ProcessKDPLog_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp
new file mode 100644
index 000000000000..449ac646ab3c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp
@@ -0,0 +1,161 @@
+//===-- RegisterContextKDP_arm.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextKDP_arm.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "ProcessKDP.h"
+#include "ThreadKDP.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextKDP_arm::RegisterContextKDP_arm (ThreadKDP &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_arm (thread, concrete_frame_idx),
+ m_kdp_thread (thread)
+{
+}
+
+RegisterContextKDP_arm::~RegisterContextKDP_arm()
+{
+}
+
+int
+RegisterContextKDP_arm::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h
new file mode 100644
index 000000000000..1e547289d9ce
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h
@@ -0,0 +1,61 @@
+//===-- RegisterContextKDP_arm.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_RegisterContextKDP_arm_h_
+#define liblldb_RegisterContextKDP_arm_h_
+
+// C Includes
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h"
+
+class ThreadKDP;
+
+class RegisterContextKDP_arm : public RegisterContextDarwin_arm
+{
+public:
+
+ RegisterContextKDP_arm (ThreadKDP &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextKDP_arm();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+
+ int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg);
+
+ ThreadKDP &m_kdp_thread;
+};
+
+#endif // liblldb_RegisterContextKDP_arm_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp
new file mode 100644
index 000000000000..ed62f1982d3c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp
@@ -0,0 +1,161 @@
+//===-- RegisterContextKDP_arm64.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextKDP_arm64.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "ProcessKDP.h"
+#include "ThreadKDP.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextKDP_arm64::RegisterContextKDP_arm64 (ThreadKDP &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_arm64 (thread, concrete_frame_idx),
+ m_kdp_thread (thread)
+{
+}
+
+RegisterContextKDP_arm64::~RegisterContextKDP_arm64()
+{
+}
+
+int
+RegisterContextKDP_arm64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h
new file mode 100644
index 000000000000..8780b7be4a9a
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h
@@ -0,0 +1,61 @@
+//===-- RegisterContextKDP_arm64.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_RegisterContextKDP_arm64_h_
+#define liblldb_RegisterContextKDP_arm64_h_
+
+// C Includes
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h"
+
+class ThreadKDP;
+
+class RegisterContextKDP_arm64 : public RegisterContextDarwin_arm64
+{
+public:
+
+ RegisterContextKDP_arm64 (ThreadKDP &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextKDP_arm64();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+
+ int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg);
+
+ ThreadKDP &m_kdp_thread;
+};
+
+#endif // liblldb_RegisterContextKDP_arm64_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp
new file mode 100644
index 000000000000..882b0c2e931d
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp
@@ -0,0 +1,129 @@
+//===-- RegisterContextKDP_i386.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextKDP_i386.h"
+#include "ProcessKDP.h"
+#include "ThreadKDP.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextKDP_i386::RegisterContextKDP_i386 (ThreadKDP &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_i386 (thread, concrete_frame_idx),
+ m_kdp_thread (thread)
+{
+}
+
+RegisterContextKDP_i386::~RegisterContextKDP_i386()
+{
+}
+
+int
+RegisterContextKDP_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h
new file mode 100644
index 000000000000..4b6bc5b262f7
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h
@@ -0,0 +1,53 @@
+//===-- RegisterContextKDP_i386.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_RegisterContextKDP_i386_h_
+#define liblldb_RegisterContextKDP_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
+
+class ThreadKDP;
+
+class RegisterContextKDP_i386 : public RegisterContextDarwin_i386
+{
+public:
+ RegisterContextKDP_i386 (ThreadKDP &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextKDP_i386();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+
+ ThreadKDP &m_kdp_thread;
+};
+
+#endif // liblldb_RegisterContextKDP_i386_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp
new file mode 100644
index 000000000000..f4247a5da272
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp
@@ -0,0 +1,127 @@
+//===-- RegisterContextKDP_x86_64.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextKDP_x86_64.h"
+#include "ProcessKDP.h"
+#include "ThreadKDP.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextKDP_x86_64::RegisterContextKDP_x86_64 (ThreadKDP &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_x86_64 (thread, concrete_frame_idx),
+ m_kdp_thread (thread)
+{
+}
+
+RegisterContextKDP_x86_64::~RegisterContextKDP_x86_64()
+{
+}
+
+int
+RegisterContextKDP_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h
new file mode 100644
index 000000000000..a426349198ff
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h
@@ -0,0 +1,54 @@
+//===-- RegisterContextKDP_x86_64.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_RegisterContextKDP_x86_64_h_
+#define liblldb_RegisterContextKDP_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
+
+class ThreadKDP;
+
+class RegisterContextKDP_x86_64 : public RegisterContextDarwin_x86_64
+{
+public:
+
+ RegisterContextKDP_x86_64 (ThreadKDP &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextKDP_x86_64();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+
+ ThreadKDP &m_kdp_thread;
+};
+
+#endif // liblldb_RegisterContextKDP_x86_64_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp
new file mode 100644
index 000000000000..3b8bed101a8a
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp
@@ -0,0 +1,211 @@
+//===-- ThreadKDP.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ThreadKDP.h"
+
+#include "lldb/Utility/SafeMachO.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+
+#include "ProcessKDP.h"
+#include "ProcessKDPLog.h"
+#include "RegisterContextKDP_arm.h"
+#include "RegisterContextKDP_arm64.h"
+#include "RegisterContextKDP_i386.h"
+#include "RegisterContextKDP_x86_64.h"
+#include "Plugins/Process/Utility/StopInfoMachException.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadKDP::ThreadKDP (Process &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_thread_name (),
+ m_dispatch_queue_name (),
+ m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS)
+{
+ ProcessKDPLog::LogIf(KDP_LOG_THREAD, "%p: ThreadKDP::ThreadKDP (tid = 0x%4.4x)", this, GetID());
+}
+
+ThreadKDP::~ThreadKDP ()
+{
+ ProcessKDPLog::LogIf(KDP_LOG_THREAD, "%p: ThreadKDP::~ThreadKDP (tid = 0x%4.4x)", this, GetID());
+ DestroyThread();
+}
+
+const char *
+ThreadKDP::GetName ()
+{
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+const char *
+ThreadKDP::GetQueueName ()
+{
+ return NULL;
+}
+
+void
+ThreadKDP::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context. We don't set "force" to
+ // true because the stop reply packet might have had some register values
+ // that were expedited and these will already be copied into the register
+ // context by the time this function gets called. The KDPRegisterContext
+ // class has been made smart enough to detect when it needs to invalidate
+ // which registers are valid by putting hooks in the register read and
+ // register supply functions where they check the process stop ID and do
+ // the right thing.
+ const bool force = false;
+ lldb::RegisterContextSP reg_ctx_sp (GetRegisterContext());
+ if (reg_ctx_sp)
+ reg_ctx_sp->InvalidateIfNeeded (force);
+}
+
+bool
+ThreadKDP::ThreadIDIsValid (lldb::tid_t thread)
+{
+ return thread != 0;
+}
+
+void
+ThreadKDP::Dump(Log *log, uint32_t index)
+{
+}
+
+
+bool
+ThreadKDP::ShouldStop (bool &step_more)
+{
+ return true;
+}
+lldb::RegisterContextSP
+ThreadKDP::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadKDP::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+ if (concrete_frame_idx == 0)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ switch (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().GetCPUType())
+ {
+ case llvm::MachO::CPU_TYPE_ARM:
+ reg_ctx_sp.reset (new RegisterContextKDP_arm (*this, concrete_frame_idx));
+ break;
+ case llvm::MachO::CPU_TYPE_ARM64:
+ reg_ctx_sp.reset (new RegisterContextKDP_arm64 (*this, concrete_frame_idx));
+ break;
+ case llvm::MachO::CPU_TYPE_I386:
+ reg_ctx_sp.reset (new RegisterContextKDP_i386 (*this, concrete_frame_idx));
+ break;
+ case llvm::MachO::CPU_TYPE_X86_64:
+ reg_ctx_sp.reset (new RegisterContextKDP_x86_64 (*this, concrete_frame_idx));
+ break;
+ default:
+ assert (!"Add CPU type support in KDP");
+ break;
+ }
+ }
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadKDP::CalculateStopInfo ()
+{
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ if (m_cached_stop_info_sp)
+ {
+ SetStopInfo (m_cached_stop_info_sp);
+ }
+ else
+ {
+ SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, SIGSTOP));
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+ThreadKDP::SetStopInfoFrom_KDP_EXCEPTION (const DataExtractor &exc_reply_packet)
+{
+ lldb::offset_t offset = 0;
+ uint8_t reply_command = exc_reply_packet.GetU8(&offset);
+ if (reply_command == CommunicationKDP::KDP_EXCEPTION)
+ {
+ offset = 8;
+ const uint32_t count = exc_reply_packet.GetU32 (&offset);
+ if (count >= 1)
+ {
+ //const uint32_t cpu = exc_reply_packet.GetU32 (&offset);
+ offset += 4; // Skip the useless CPU field
+ const uint32_t exc_type = exc_reply_packet.GetU32 (&offset);
+ const uint32_t exc_code = exc_reply_packet.GetU32 (&offset);
+ const uint32_t exc_subcode = exc_reply_packet.GetU32 (&offset);
+ // We have to make a copy of the stop info because the thread list
+ // will iterate through the threads and clear all stop infos..
+
+ // Let the StopInfoMachException::CreateStopReasonWithMachException()
+ // function update the PC if needed as we might hit a software breakpoint
+ // and need to decrement the PC (i386 and x86_64 need this) and KDP
+ // doesn't do this for us.
+ const bool pc_already_adjusted = false;
+ const bool adjust_pc_if_needed = true;
+
+ m_cached_stop_info_sp = StopInfoMachException::CreateStopReasonWithMachException (*this,
+ exc_type,
+ 2,
+ exc_code,
+ exc_subcode,
+ 0,
+ pc_already_adjusted,
+ adjust_pc_if_needed);
+ }
+ }
+}
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h
new file mode 100644
index 000000000000..7dc373f03550
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h
@@ -0,0 +1,98 @@
+//===-- ThreadKDP.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_ThreadKDP_h_
+#define liblldb_ThreadKDP_h_
+
+#include <string>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+class ProcessKDP;
+
+class ThreadKDP : public lldb_private::Thread
+{
+public:
+ ThreadKDP (lldb_private::Process &process,
+ lldb::tid_t tid);
+
+ virtual
+ ~ThreadKDP ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual const char *
+ GetName ();
+
+ virtual const char *
+ GetQueueName ();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ void
+ Dump (lldb_private::Log *log, uint32_t index);
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread);
+
+ bool
+ ShouldStop (bool &step_more);
+
+ const char *
+ GetBasicInfoAsString ();
+
+ void
+ SetName (const char *name)
+ {
+ if (name && name[0])
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+ }
+
+ lldb::addr_t
+ GetThreadDispatchQAddr ()
+ {
+ return m_thread_dispatch_qaddr;
+ }
+
+ void
+ SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr)
+ {
+ m_thread_dispatch_qaddr = thread_dispatch_qaddr;
+ }
+
+ void
+ SetStopInfoFrom_KDP_EXCEPTION (const lldb_private::DataExtractor &exc_reply_packet);
+
+protected:
+
+ friend class ProcessKDP;
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::string m_thread_name;
+ std::string m_dispatch_queue_name;
+ lldb::addr_t m_thread_dispatch_qaddr;
+ lldb::StopInfoSP m_cached_stop_info_sp;
+ //------------------------------------------------------------------
+ // Protected member functions.
+ //------------------------------------------------------------------
+ virtual bool
+ CalculateStopInfo ();
+};
+
+#endif // liblldb_ThreadKDP_h_
diff --git a/source/Plugins/Process/POSIX/CMakeLists.txt b/source/Plugins/Process/POSIX/CMakeLists.txt
new file mode 100644
index 000000000000..2ed7326dbb71
--- /dev/null
+++ b/source/Plugins/Process/POSIX/CMakeLists.txt
@@ -0,0 +1,8 @@
+include_directories(.)
+include_directories(../Utility)
+
+add_lldb_library(lldbPluginProcessPOSIX
+ CrashReason.cpp
+ ProcessMessage.cpp
+ ProcessPOSIXLog.cpp
+ )
diff --git a/source/Plugins/Process/POSIX/Makefile b/source/Plugins/Process/POSIX/Makefile
new file mode 100644
index 000000000000..e8ac3a8ae0ed
--- /dev/null
+++ b/source/Plugins/Process/POSIX/Makefile
@@ -0,0 +1,32 @@
+##===- source/Plugins/Process/POSIX/Makefile ---------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginProcessPOSIX
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/../../Makefile.config
+
+# Extend the include path so we may locate UnwindLLDB.h
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/source/Plugins/Utility
+
+ifeq ($(HOST_OS),Linux)
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/source/Plugins/Process/Linux
+
+# Disable warning for now as offsetof is used with an index into a structure member array
+# in defining register info tables.
+CPP.Flags += -Wno-extended-offsetof
+endif
+
+ifneq (,$(filter $(HOST_OS), FreeBSD GNU/kFreeBSD))
+# Extend the include path so we may locate ProcessMonitor
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/source/Plugins/Process/FreeBSD
+endif
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Process/Utility/CMakeLists.txt b/source/Plugins/Process/Utility/CMakeLists.txt
new file mode 100644
index 000000000000..4a847b4f966a
--- /dev/null
+++ b/source/Plugins/Process/Utility/CMakeLists.txt
@@ -0,0 +1,47 @@
+include_directories(../../../Utility/)
+
+add_lldb_library(lldbPluginProcessUtility
+ DynamicRegisterInfo.cpp
+ FreeBSDSignals.cpp
+ GDBRemoteSignals.cpp
+ HistoryThread.cpp
+ HistoryUnwind.cpp
+ InferiorCallPOSIX.cpp
+ LinuxSignals.cpp
+ MipsLinuxSignals.cpp
+ NetBSDSignals.cpp
+ RegisterContextDarwin_arm.cpp
+ RegisterContextDarwin_arm64.cpp
+ RegisterContextDarwin_i386.cpp
+ RegisterContextDarwin_x86_64.cpp
+ RegisterContextDummy.cpp
+ RegisterContextFreeBSD_arm.cpp
+ RegisterContextFreeBSD_arm64.cpp
+ RegisterContextFreeBSD_i386.cpp
+ RegisterContextFreeBSD_mips64.cpp
+ RegisterContextFreeBSD_powerpc.cpp
+ RegisterContextFreeBSD_x86_64.cpp
+ RegisterContextHistory.cpp
+ RegisterContextLinux_arm.cpp
+ RegisterContextLinux_arm64.cpp
+ RegisterContextLinux_i386.cpp
+ RegisterContextLinux_x86_64.cpp
+ RegisterContextLinux_mips64.cpp
+ RegisterContextLinux_mips.cpp
+ RegisterContextLLDB.cpp
+ RegisterContextMacOSXFrameBackchain.cpp
+ RegisterContextMach_arm.cpp
+ RegisterContextMach_i386.cpp
+ RegisterContextMach_x86_64.cpp
+ RegisterContextMemory.cpp
+ RegisterContextPOSIX_arm.cpp
+ RegisterContextPOSIX_arm64.cpp
+ RegisterContextPOSIX_mips64.cpp
+ RegisterContextPOSIX_powerpc.cpp
+ RegisterContextPOSIX_x86.cpp
+ RegisterContextThreadMemory.cpp
+ StopInfoMachException.cpp
+ ThreadMemory.cpp
+ UnwindLLDB.cpp
+ UnwindMacOSXFrameBackchain.cpp
+ )
diff --git a/source/Plugins/Process/Utility/Makefile b/source/Plugins/Process/Utility/Makefile
new file mode 100644
index 000000000000..eb0caf3f92fe
--- /dev/null
+++ b/source/Plugins/Process/Utility/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Utility/Makefile ---------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginProcessUtility
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Process/Windows/Common/CMakeLists.txt b/source/Plugins/Process/Windows/Common/CMakeLists.txt
new file mode 100644
index 000000000000..5a53c3c3300c
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/CMakeLists.txt
@@ -0,0 +1,23 @@
+include_directories(.)
+include_directories(../../Utility)
+
+set(PROC_WINDOWS_COMMON_SOURCES
+ RegisterContextWindows.cpp
+ ProcessWindows.cpp
+ ProcessWindowsLog.cpp
+ TargetThreadWindows.cpp
+ )
+
+if (CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(PROC_WINDOWS_COMMON_SOURCES ${PROC_WINDOWS_COMMON_SOURCES}
+ x86/RegisterContextWindows_x86.cpp
+ )
+elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(PROC_WINDOWS_COMMON_SOURCES ${PROC_WINDOWS_COMMON_SOURCES}
+ x64/RegisterContextWindows_x64.cpp
+ )
+endif()
+
+add_lldb_library(lldbPluginProcessWindowsCommon
+ ${PROC_WINDOWS_COMMON_SOURCES}
+ )
diff --git a/source/Plugins/Process/Windows/Common/ExceptionRecord.h b/source/Plugins/Process/Windows/Common/ExceptionRecord.h
new file mode 100644
index 000000000000..79dae3fca4e8
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/ExceptionRecord.h
@@ -0,0 +1,99 @@
+//===-- ExceptionRecord.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_Plugins_Process_Windows_ExceptionRecord_H_
+#define liblldb_Plugins_Process_Windows_ExceptionRecord_H_
+
+#include "lldb/lldb-forward.h"
+#include "lldb/Host/windows/windows.h"
+#include <DbgHelp.h>
+
+#include <memory>
+#include <vector>
+
+namespace lldb_private
+{
+
+//----------------------------------------------------------------------
+// ExceptionRecord
+//
+// ExceptionRecord defines an interface which allows implementors to receive
+// notification of events that happen in a debugged process.
+//----------------------------------------------------------------------
+class ExceptionRecord
+{
+ public:
+ ExceptionRecord(const EXCEPTION_RECORD &record, lldb::tid_t thread_id)
+ {
+ m_code = record.ExceptionCode;
+ m_continuable = (record.ExceptionFlags == 0);
+ if (record.ExceptionRecord)
+ m_next_exception.reset(new ExceptionRecord(*record.ExceptionRecord, thread_id));
+ m_exception_addr = reinterpret_cast<lldb::addr_t>(record.ExceptionAddress);
+ m_thread_id = thread_id;
+ m_arguments.assign(record.ExceptionInformation, record.ExceptionInformation + record.NumberParameters);
+ }
+
+ // MINIDUMP_EXCEPTIONs are almost identical to EXCEPTION_RECORDs.
+ ExceptionRecord(const MINIDUMP_EXCEPTION &record, lldb::tid_t thread_id) :
+ m_code(record.ExceptionCode),
+ m_continuable(record.ExceptionFlags == 0),
+ m_next_exception(nullptr),
+ m_exception_addr(static_cast<lldb::addr_t>(record.ExceptionAddress)),
+ m_thread_id(thread_id),
+ m_arguments(record.ExceptionInformation, record.ExceptionInformation + record.NumberParameters)
+ {
+ // Set up link to nested exception.
+ if (record.ExceptionRecord)
+ {
+ m_next_exception.reset(new ExceptionRecord(*reinterpret_cast<const MINIDUMP_EXCEPTION *>(record.ExceptionRecord),
+ thread_id));
+ }
+ }
+
+ virtual ~ExceptionRecord() {}
+
+ DWORD
+ GetExceptionCode() const
+ {
+ return m_code;
+ }
+ bool
+ IsContinuable() const
+ {
+ return m_continuable;
+ }
+ const ExceptionRecord *
+ GetNextException() const
+ {
+ return m_next_exception.get();
+ }
+ lldb::addr_t
+ GetExceptionAddress() const
+ {
+ return m_exception_addr;
+ }
+
+ lldb::tid_t
+ GetThreadID() const
+ {
+ return m_thread_id;
+ }
+
+ private:
+ DWORD m_code;
+ bool m_continuable;
+ std::shared_ptr<ExceptionRecord> m_next_exception;
+ lldb::addr_t m_exception_addr;
+ lldb::tid_t m_thread_id;
+ std::vector<ULONG_PTR> m_arguments;
+};
+}
+
+#endif
diff --git a/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
new file mode 100644
index 000000000000..0e6900d8fb7f
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -0,0 +1,100 @@
+//===-- ProcessWindows.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessWindows.h"
+
+// Other libraries and framework includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/windows/windows.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace lldb_private
+{
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessWindows::ProcessWindows(lldb::TargetSP target_sp, Listener &listener)
+ : lldb_private::Process(target_sp, listener)
+{
+}
+
+ProcessWindows::~ProcessWindows()
+{
+}
+
+size_t
+ProcessWindows::GetSTDOUT(char *buf, size_t buf_size, Error &error)
+{
+ error.SetErrorString("GetSTDOUT unsupported on Windows");
+ return 0;
+}
+
+size_t
+ProcessWindows::GetSTDERR(char *buf, size_t buf_size, Error &error)
+{
+ error.SetErrorString("GetSTDERR unsupported on Windows");
+ return 0;
+}
+
+size_t
+ProcessWindows::PutSTDIN(const char *buf, size_t buf_size, Error &error)
+{
+ error.SetErrorString("PutSTDIN unsupported on Windows");
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// ProcessInterface protocol.
+
+
+lldb::addr_t
+ProcessWindows::GetImageInfoAddress()
+{
+ Target &target = GetTarget();
+ ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress(&target);
+ if (addr.IsValid())
+ return addr.GetLoadAddress(&target);
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+// The Windows page protection bits are NOT independent masks that can be bitwise-ORed
+// together. For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE | PAGE_READ).
+// To test for an access type, it's necessary to test for any of the bits that provide
+// that access type.
+bool
+ProcessWindows::IsPageReadable(uint32_t protect)
+{
+ return (protect & PAGE_NOACCESS) == 0;
+}
+
+bool
+ProcessWindows::IsPageWritable(uint32_t protect)
+{
+ return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_READWRITE | PAGE_WRITECOPY)) != 0;
+}
+
+bool
+ProcessWindows::IsPageExecutable(uint32_t protect)
+{
+ return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
+}
+
+}
diff --git a/source/Plugins/Process/Windows/Common/ProcessWindows.h b/source/Plugins/Process/Windows/Common/ProcessWindows.h
new file mode 100644
index 000000000000..2a437c0ca909
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/ProcessWindows.h
@@ -0,0 +1,52 @@
+//===-- ProcessWindows.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_Plugins_Process_Windows_Common_ProcessWindows_H_
+#define liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_
+
+// Other libraries and framework includes
+#include "lldb/lldb-forward.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/Process.h"
+
+namespace lldb_private
+{
+
+class ProcessWindows : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessWindows(lldb::TargetSP target_sp,
+ lldb_private::Listener &listener);
+
+ ~ProcessWindows();
+
+ size_t GetSTDOUT(char *buf, size_t buf_size, lldb_private::Error &error) override;
+ size_t GetSTDERR(char *buf, size_t buf_size, lldb_private::Error &error) override;
+ size_t PutSTDIN(const char *buf, size_t buf_size, lldb_private::Error &error) override;
+
+ lldb::addr_t GetImageInfoAddress() override;
+
+protected:
+ // These decode the page protection bits.
+ static bool
+ IsPageReadable(uint32_t protect);
+
+ static bool
+ IsPageWritable(uint32_t protect);
+
+ static bool
+ IsPageExecutable(uint32_t protect);
+};
+
+}
+
+#endif // liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_
diff --git a/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp b/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp
new file mode 100644
index 000000000000..47722c5146b2
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp
@@ -0,0 +1,194 @@
+//===-- ProcessWindowsLog.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessWindowsLog.h"
+
+#include <mutex>
+
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Interpreter/Args.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_log_sp the first time this function is
+// called.
+static bool g_log_enabled = false;
+static Log * g_log = nullptr;
+
+static llvm::ManagedStatic<std::once_flag> g_once_flag;
+
+void
+ProcessWindowsLog::Initialize()
+{
+ static ConstString g_name("windows");
+
+ std::call_once(*g_once_flag, [](){
+ Log::Callbacks log_callbacks = {
+ DisableLog,
+ EnableLog,
+ ListLogCategories
+ };
+
+ Log::RegisterLogChannel(g_name, log_callbacks);
+ RegisterPluginName(g_name);
+ });
+}
+
+void
+ProcessWindowsLog::Terminate()
+{
+}
+
+Log *
+ProcessWindowsLog::GetLog()
+{
+ return (g_log_enabled) ? g_log : nullptr;
+}
+
+bool
+ProcessWindowsLog::TestLogFlags(uint32_t mask, LogMaskReq req)
+{
+ Log *log = GetLog();
+ if (!log)
+ return false;
+
+ uint32_t log_mask = log->GetMask().Get();
+ if (req == LogMaskReq::All)
+ return ((log_mask & mask) == mask);
+ else
+ return (log_mask & mask);
+}
+
+static uint32_t
+GetFlagBits(const char *arg)
+{
+ if (::strcasecmp(arg, "all") == 0 ) return WINDOWS_LOG_ALL;
+ else if (::strcasecmp(arg, "break") == 0 ) return WINDOWS_LOG_BREAKPOINTS;
+ else if (::strcasecmp(arg, "event") == 0 ) return WINDOWS_LOG_EVENT;
+ else if (::strcasecmp(arg, "exception") == 0 ) return WINDOWS_LOG_EXCEPTION;
+ else if (::strcasecmp(arg, "memory") == 0 ) return WINDOWS_LOG_MEMORY;
+ else if (::strcasecmp(arg, "process") == 0 ) return WINDOWS_LOG_PROCESS;
+ else if (::strcasecmp(arg, "registers") == 0 ) return WINDOWS_LOG_REGISTERS;
+ else if (::strcasecmp(arg, "step") == 0 ) return WINDOWS_LOG_STEP;
+ else if (::strcasecmp(arg, "thread") == 0 ) return WINDOWS_LOG_THREAD;
+ else if (::strcasecmp(arg, "verbose") == 0 ) return WINDOWS_LOG_VERBOSE;
+ return 0;
+}
+
+void
+ProcessWindowsLog::DisableLog(const char **args, Stream *feedback_strm)
+{
+ Log *log (GetLog());
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+
+ if (args[0] != nullptr)
+ {
+ flag_bits = log->GetMask().Get();
+ for (; args[0]; args++)
+ {
+ const char *arg = args[0];
+ uint32_t bits = GetFlagBits(arg);
+
+ if (bits)
+ {
+ flag_bits &= ~bits;
+ }
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories(feedback_strm);
+ }
+ }
+ }
+
+ log->GetMask().Reset(flag_bits);
+ if (flag_bits == 0)
+ {
+ g_log_enabled = false;
+ log->SetStream(lldb::StreamSP());
+ }
+ }
+
+ return;
+}
+
+Log *
+ProcessWindowsLog::EnableLog(StreamSP &log_stream_sp, uint32_t log_options, const char **args, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits = 0;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ bool got_unknown_category = false;
+ for (; args[0]; args++)
+ {
+ const char *arg = args[0];
+ uint32_t bits = GetFlagBits(arg);
+
+ if (bits)
+ {
+ flag_bits |= bits;
+ }
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = WINDOWS_LOG_ALL;
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ g_log_enabled = true;
+ }
+ return g_log;
+}
+
+void
+ProcessWindowsLog::ListLogCategories(Stream *strm)
+{
+ strm->Printf("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " break - log breakpoints\n"
+ " event - log low level debugger events\n"
+ " exception - log exception information\n"
+ " memory - log memory reads and writes\n"
+ " process - log process events and activities\n"
+ " registers - log register read/writes\n"
+ " thread - log thread events and activities\n"
+ " step - log step related activities\n"
+ " verbose - enable verbose logging\n",
+ ProcessWindowsLog::m_pluginname);
+}
+
+const char *ProcessWindowsLog::m_pluginname = "";
diff --git a/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h b/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h
new file mode 100644
index 000000000000..d798d131faeb
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h
@@ -0,0 +1,96 @@
+//===-- ProcessWindowsLog.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_ProcessWindowsLog_h_
+#define liblldb_ProcessWindowsLog_h_
+
+#include "lldb/Core/Log.h"
+
+#define WINDOWS_LOG_VERBOSE (1u << 0)
+#define WINDOWS_LOG_PROCESS (1u << 1) // Log process operations
+#define WINDOWS_LOG_EXCEPTION (1u << 1) // Log exceptions
+#define WINDOWS_LOG_THREAD (1u << 2) // Log thread operations
+#define WINDOWS_LOG_MEMORY (1u << 3) // Log memory reads/writes calls
+#define WINDOWS_LOG_BREAKPOINTS (1u << 4) // Log breakpoint operations
+#define WINDOWS_LOG_STEP (1u << 5) // Log step operations
+#define WINDOWS_LOG_REGISTERS (1u << 6) // Log register operations
+#define WINDOWS_LOG_EVENT (1u << 7) // Low level debug events
+#define WINDOWS_LOG_ALL (UINT32_MAX)
+
+enum class LogMaskReq
+{
+ All,
+ Any
+};
+
+class ProcessWindowsLog
+{
+ static const char *m_pluginname;
+
+public:
+ // ---------------------------------------------------------------------
+ // Public Static Methods
+ // ---------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static void
+ RegisterPluginName(const char *pluginName)
+ {
+ m_pluginname = pluginName;
+ }
+
+ static void
+ RegisterPluginName(lldb_private::ConstString pluginName)
+ {
+ m_pluginname = pluginName.GetCString();
+ }
+
+ static bool
+ TestLogFlags(uint32_t mask, LogMaskReq req);
+
+ static lldb_private::Log *
+ GetLog();
+
+ static void
+ DisableLog(const char **args, lldb_private::Stream *feedback_strm);
+
+ static lldb_private::Log *
+ EnableLog(lldb::StreamSP &log_stream_sp, uint32_t log_options,
+ const char **args, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories(lldb_private::Stream *strm);
+};
+
+#define WINLOGF_IF(Flags, Req, Method, ...) \
+ { \
+ if (ProcessWindowsLog::TestLogFlags(Flags, Req)) \
+ { \
+ Log *log = ProcessWindowsLog::GetLog(); \
+ if (log) \
+ log->Method(__VA_ARGS__); \
+ } \
+ }
+
+#define WINLOG_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Printf, __VA_ARGS__)
+#define WINLOG_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Printf, __VA_ARGS__)
+#define WINLOGV_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Verbose, __VA_ARGS__)
+#define WINLOGV_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Verbose, __VA_ARGS__)
+#define WINLOGD_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Debug, __VA_ARGS__)
+#define WINLOGD_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Debug, __VA_ARGS__)
+#define WINERR_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Error, __VA_ARGS__)
+#define WINERR_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Error, __VA_ARGS__)
+#define WINWARN_IFANY(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::Any, Warning, __VA_ARGS__)
+#define WINWARN_IFALL(Flags, ...) WINLOGF_IF(Flags, LogMaskReq::All, Warning, __VA_ARGS__)
+
+#endif // liblldb_ProcessWindowsLog_h_
diff --git a/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp b/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp
new file mode 100644
index 000000000000..d61675f09b1b
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp
@@ -0,0 +1,155 @@
+//===-- RegisterContextWindows.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/lldb-private-types.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+#include "lldb/Host/windows/windows.h"
+
+#include "ProcessWindowsLog.h"
+#include "RegisterContextWindows.h"
+#include "TargetThreadWindows.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const DWORD kWinContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
+
+//------------------------------------------------------------------
+// Constructors and Destructors
+//------------------------------------------------------------------
+RegisterContextWindows::RegisterContextWindows(Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContext(thread, concrete_frame_idx)
+ , m_context()
+ , m_context_stale(true)
+{
+}
+
+RegisterContextWindows::~RegisterContextWindows()
+{
+}
+
+void
+RegisterContextWindows::InvalidateAllRegisters()
+{
+ m_context_stale = true;
+}
+
+bool
+RegisterContextWindows::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ if (!CacheAllRegisterValues())
+ return false;
+ if (data_sp->GetByteSize() < sizeof(m_context))
+ {
+ data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0));
+ }
+ memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context));
+ return true;
+}
+
+bool
+RegisterContextWindows::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ assert(data_sp->GetByteSize() >= sizeof(m_context));
+ memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context));
+
+ TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
+ if (!::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context))
+ return false;
+
+ return true;
+}
+
+uint32_t
+RegisterContextWindows::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num)
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert(kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+//------------------------------------------------------------------
+// Subclasses can these functions if desired
+//------------------------------------------------------------------
+uint32_t
+RegisterContextWindows::NumSupportedHardwareBreakpoints()
+{
+ // Support for hardware breakpoints not yet implemented.
+ return 0;
+}
+
+uint32_t
+RegisterContextWindows::SetHardwareBreakpoint(lldb::addr_t addr, size_t size)
+{
+ return 0;
+}
+
+bool
+RegisterContextWindows::ClearHardwareBreakpoint(uint32_t hw_idx)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextWindows::NumSupportedHardwareWatchpoints()
+{
+ // Support for hardware watchpoints not yet implemented.
+ return 0;
+}
+
+uint32_t
+RegisterContextWindows::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ return 0;
+}
+
+bool
+RegisterContextWindows::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextWindows::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
+bool
+RegisterContextWindows::CacheAllRegisterValues()
+{
+ if (!m_context_stale)
+ return true;
+
+ TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
+ memset(&m_context, 0, sizeof(m_context));
+ m_context.ContextFlags = kWinContextFlags;
+ if (!::GetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context))
+ {
+ WINERR_IFALL(WINDOWS_LOG_REGISTERS, "GetThreadContext failed with error %u while caching register values.",
+ ::GetLastError());
+ return false;
+ }
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "GetThreadContext successfully updated the register values.", ::GetLastError());
+ m_context_stale = false;
+ return true;
+}
diff --git a/source/Plugins/Process/Windows/Common/RegisterContextWindows.h b/source/Plugins/Process/Windows/Common/RegisterContextWindows.h
new file mode 100644
index 000000000000..66b7a9004ead
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/RegisterContextWindows.h
@@ -0,0 +1,67 @@
+//===-- RegisterContextWindows.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_RegisterContextWindows_H_
+#define liblldb_RegisterContextWindows_H_
+
+#include "lldb/lldb-forward.h"
+#include "lldb/Target/RegisterContext.h"
+
+namespace lldb_private
+{
+
+class Thread;
+
+class RegisterContextWindows : public lldb_private::RegisterContext
+{
+ public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextWindows(Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual ~RegisterContextWindows();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ void InvalidateAllRegisters() override;
+
+ bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) override;
+
+ //------------------------------------------------------------------
+ // Subclasses can override these functions if desired
+ //------------------------------------------------------------------
+ uint32_t NumSupportedHardwareBreakpoints() override;
+
+ uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+ bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
+
+ uint32_t NumSupportedHardwareWatchpoints() override;
+
+ uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write) override;
+
+ bool ClearHardwareWatchpoint(uint32_t hw_index) override;
+
+ bool HardwareSingleStep(bool enable) override;
+
+ protected:
+ virtual bool CacheAllRegisterValues();
+
+ CONTEXT m_context;
+ bool m_context_stale;
+};
+}
+
+#endif // #ifndef liblldb_RegisterContextWindows_H_
diff --git a/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
new file mode 100644
index 000000000000..dcb6f0c72435
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
@@ -0,0 +1,98 @@
+//===-- TargetThreadWindows.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/Core/Log.h"
+#include "lldb/Core/Logging.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/HostNativeThreadBase.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+#include "lldb/Host/windows/windows.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "TargetThreadWindows.h"
+#include "ProcessWindows.h"
+#include "ProcessWindowsLog.h"
+#include "UnwindLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TargetThreadWindows::TargetThreadWindows(ProcessWindows &process, const HostThread &thread)
+ : Thread(process, thread.GetNativeThread().GetThreadId())
+ , m_host_thread(thread)
+{
+}
+
+TargetThreadWindows::~TargetThreadWindows()
+{
+ DestroyThread();
+}
+
+void
+TargetThreadWindows::RefreshStateAfterStop()
+{
+ ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
+ SetState(eStateStopped);
+ GetRegisterContext()->InvalidateIfNeeded(false);
+}
+
+void
+TargetThreadWindows::WillResume(lldb::StateType resume_state)
+{
+}
+
+void
+TargetThreadWindows::DidStop()
+{
+}
+
+bool
+TargetThreadWindows::CalculateStopInfo()
+{
+ SetStopInfo(m_stop_info_sp);
+ return true;
+}
+
+Unwind *
+TargetThreadWindows::GetUnwinder()
+{
+ // FIXME: Implement an unwinder based on the Windows unwinder exposed through DIA SDK.
+ if (m_unwinder_ap.get() == NULL)
+ m_unwinder_ap.reset(new UnwindLLDB(*this));
+ return m_unwinder_ap.get();
+}
+
+bool
+TargetThreadWindows::DoResume()
+{
+ StateType resume_state = GetTemporaryResumeState();
+ StateType current_state = GetState();
+ if (resume_state == current_state)
+ return true;
+
+ if (resume_state == eStateStepping)
+ {
+ uint32_t flags_index = GetRegisterContext()->ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+ uint64_t flags_value = GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0);
+ flags_value |= 0x100; // Set the trap flag on the CPU
+ GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
+ }
+
+ if (resume_state == eStateStepping || resume_state == eStateRunning)
+ {
+ DWORD previous_suspend_count = 0;
+ HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
+ do
+ {
+ previous_suspend_count = ::ResumeThread(thread_handle);
+ } while (previous_suspend_count > 0);
+ }
+ return true;
+}
diff --git a/source/Plugins/Process/Windows/Common/TargetThreadWindows.h b/source/Plugins/Process/Windows/Common/TargetThreadWindows.h
new file mode 100644
index 000000000000..701b56b6d26a
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/TargetThreadWindows.h
@@ -0,0 +1,50 @@
+//===-- TargetThreadWindows.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_Plugins_Process_Windows_TargetThreadWindows_H_
+#define liblldb_Plugins_Process_Windows_TargetThreadWindows_H_
+
+//#include "ForwardDecl.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Target/Thread.h"
+
+namespace lldb_private
+{
+class ProcessWindows;
+class HostThread;
+class StackFrame;
+
+class TargetThreadWindows : public lldb_private::Thread
+{
+ public:
+ TargetThreadWindows(ProcessWindows &process, const HostThread &thread);
+ virtual ~TargetThreadWindows();
+
+ // lldb_private::Thread overrides
+ void RefreshStateAfterStop() override;
+ void WillResume(lldb::StateType resume_state) override;
+ void DidStop() override;
+ bool CalculateStopInfo() override;
+ Unwind *GetUnwinder() override;
+
+ bool DoResume();
+
+ HostThread
+ GetHostThread() const
+ {
+ return m_host_thread;
+ }
+
+ private:
+ HostThread m_host_thread;
+};
+}
+
+#endif
diff --git a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp
new file mode 100644
index 000000000000..103cff4a2a56
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp
@@ -0,0 +1,323 @@
+//===-- RegisterContextWindows_x64.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/lldb-private-types.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+#include "lldb/Host/windows/windows.h"
+
+#include "lldb-x86-register-enums.h"
+#include "RegisterContext_x86.h"
+#include "RegisterContextWindows_x64.h"
+#include "TargetThreadWindows.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define DEFINE_GPR(reg, alt) #reg, alt, 8, 0, eEncodingUint, eFormatHexUppercase
+#define DEFINE_GPR_BIN(reg, alt) #reg, alt, 8, 0, eEncodingUint, eFormatBinary
+
+namespace
+{
+
+// This enum defines the layout of the global RegisterInfo array. This is necessary because
+// lldb register sets are defined in terms of indices into the register array. As such, the
+// order of RegisterInfos defined in global registers array must match the order defined here.
+// When defining the register set layouts, these values can appear in an arbitrary order, and that
+// determines the order that register values are displayed in a dump.
+enum RegisterIndex
+{
+ eRegisterIndexRax,
+ eRegisterIndexRbx,
+ eRegisterIndexRcx,
+ eRegisterIndexRdx,
+ eRegisterIndexRdi,
+ eRegisterIndexRsi,
+ eRegisterIndexR8,
+ eRegisterIndexR9,
+ eRegisterIndexR10,
+ eRegisterIndexR11,
+ eRegisterIndexR12,
+ eRegisterIndexR13,
+ eRegisterIndexR14,
+ eRegisterIndexR15,
+ eRegisterIndexRbp,
+ eRegisterIndexRsp,
+ eRegisterIndexRip,
+ eRegisterIndexRflags
+};
+
+// Array of all register information supported by Windows x86
+RegisterInfo g_register_infos[] = {
+ // Macro auto defines most stuff eh_frame DWARF GENERIC
+ // GDB LLDB VALUE REGS INVALIDATE REGS
+ // ================================ ========================= ====================== =========================
+ // =================== ================= ========== ===============
+ {DEFINE_GPR(rax, nullptr),
+ {dwarf_rax_x86_64, dwarf_rax_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rax_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(rbx, nullptr),
+ {dwarf_rbx_x86_64, dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rbx_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(rcx, nullptr),
+ {dwarf_rcx_x86_64, dwarf_rcx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rcx_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(rdx, nullptr),
+ {dwarf_rdx_x86_64, dwarf_rdx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rdx_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(rdi, nullptr),
+ {dwarf_rdi_x86_64, dwarf_rdi_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rdi_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(rsi, nullptr),
+ {dwarf_rsi_x86_64, dwarf_rsi_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_rsi_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(r8, nullptr),
+ {dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r8_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(r9, nullptr),
+ {dwarf_r9_x86_64, dwarf_r9_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r9_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(r10, nullptr),
+ {dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r10_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(r11, nullptr),
+ {dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r11_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(r12, nullptr),
+ {dwarf_r12_x86_64, dwarf_r12_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r12_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(r13, nullptr),
+ {dwarf_r13_x86_64, dwarf_r13_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r13_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(r14, nullptr),
+ {dwarf_r14_x86_64, dwarf_r14_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r14_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(r15, nullptr),
+ {dwarf_r15_x86_64, dwarf_r15_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_r15_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(rbp, "fp"),
+ {dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, lldb_rbp_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(rsp, "sp"),
+ {dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, lldb_rsp_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(rip, "pc"),
+ {dwarf_rip_x86_64, dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, lldb_rip_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR_BIN(eflags, "flags"),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, lldb_rflags_x86_64},
+ nullptr,
+ nullptr},
+};
+
+// Array of lldb register numbers used to define the set of all General Purpose Registers
+uint32_t g_gpr_reg_indices[] = {eRegisterIndexRax, eRegisterIndexRbx, eRegisterIndexRcx, eRegisterIndexRdx,
+ eRegisterIndexRdi, eRegisterIndexRsi, eRegisterIndexR8, eRegisterIndexR9,
+ eRegisterIndexR10, eRegisterIndexR11, eRegisterIndexR12, eRegisterIndexR13,
+ eRegisterIndexR14, eRegisterIndexR15, eRegisterIndexRbp, eRegisterIndexRsp,
+ eRegisterIndexRip, eRegisterIndexRflags};
+
+RegisterSet g_register_sets[] = {
+ {"General Purpose Registers", "gpr", llvm::array_lengthof(g_gpr_reg_indices), g_gpr_reg_indices},
+};
+}
+
+//------------------------------------------------------------------
+// Constructors and Destructors
+//------------------------------------------------------------------
+RegisterContextWindows_x64::RegisterContextWindows_x64(Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContextWindows(thread, concrete_frame_idx)
+{
+}
+
+RegisterContextWindows_x64::~RegisterContextWindows_x64()
+{
+}
+
+size_t
+RegisterContextWindows_x64::GetRegisterCount()
+{
+ return llvm::array_lengthof(g_register_infos);
+}
+
+const RegisterInfo *
+RegisterContextWindows_x64::GetRegisterInfoAtIndex(size_t reg)
+{
+ return &g_register_infos[reg];
+}
+
+size_t
+RegisterContextWindows_x64::GetRegisterSetCount()
+{
+ return llvm::array_lengthof(g_register_sets);
+}
+
+const RegisterSet *
+RegisterContextWindows_x64::GetRegisterSet(size_t reg_set)
+{
+ return &g_register_sets[reg_set];
+}
+
+bool
+RegisterContextWindows_x64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ if (!CacheAllRegisterValues())
+ return false;
+
+ switch (reg_info->kinds[eRegisterKindLLDB])
+ {
+ case lldb_rax_x86_64:
+ reg_value.SetUInt64(m_context.Rax);
+ break;
+ case lldb_rbx_x86_64:
+ reg_value.SetUInt64(m_context.Rbx);
+ break;
+ case lldb_rcx_x86_64:
+ reg_value.SetUInt64(m_context.Rcx);
+ break;
+ case lldb_rdx_x86_64:
+ reg_value.SetUInt64(m_context.Rdx);
+ break;
+ case lldb_rdi_x86_64:
+ reg_value.SetUInt64(m_context.Rdi);
+ break;
+ case lldb_rsi_x86_64:
+ reg_value.SetUInt64(m_context.Rsi);
+ break;
+ case lldb_r8_x86_64:
+ reg_value.SetUInt64(m_context.R8);
+ break;
+ case lldb_r9_x86_64:
+ reg_value.SetUInt64(m_context.R9);
+ break;
+ case lldb_r10_x86_64:
+ reg_value.SetUInt64(m_context.R10);
+ break;
+ case lldb_r11_x86_64:
+ reg_value.SetUInt64(m_context.R11);
+ break;
+ case lldb_r12_x86_64:
+ reg_value.SetUInt64(m_context.R12);
+ break;
+ case lldb_r13_x86_64:
+ reg_value.SetUInt64(m_context.R13);
+ break;
+ case lldb_r14_x86_64:
+ reg_value.SetUInt64(m_context.R14);
+ break;
+ case lldb_r15_x86_64:
+ reg_value.SetUInt64(m_context.R15);
+ break;
+ case lldb_rbp_x86_64:
+ reg_value.SetUInt64(m_context.Rbp);
+ break;
+ case lldb_rsp_x86_64:
+ reg_value.SetUInt64(m_context.Rsp);
+ break;
+ case lldb_rip_x86_64:
+ reg_value.SetUInt64(m_context.Rip);
+ break;
+ case lldb_rflags_x86_64:
+ reg_value.SetUInt64(m_context.EFlags);
+ break;
+ }
+ return true;
+}
+
+bool
+RegisterContextWindows_x64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ // Since we cannot only write a single register value to the inferior, we need to make sure
+ // our cached copy of the register values are fresh. Otherwise when writing EAX, for example,
+ // we may also overwrite some other register with a stale value.
+ if (!CacheAllRegisterValues())
+ return false;
+
+ switch (reg_info->kinds[eRegisterKindLLDB])
+ {
+ case lldb_rax_x86_64:
+ m_context.Rax = reg_value.GetAsUInt64();
+ break;
+ case lldb_rbx_x86_64:
+ m_context.Rbx = reg_value.GetAsUInt64();
+ break;
+ case lldb_rcx_x86_64:
+ m_context.Rcx = reg_value.GetAsUInt64();
+ break;
+ case lldb_rdx_x86_64:
+ m_context.Rdx = reg_value.GetAsUInt64();
+ break;
+ case lldb_rdi_x86_64:
+ m_context.Rdi = reg_value.GetAsUInt64();
+ break;
+ case lldb_rsi_x86_64:
+ m_context.Rsi = reg_value.GetAsUInt64();
+ break;
+ case lldb_r8_x86_64:
+ m_context.R8 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r9_x86_64:
+ m_context.R9 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r10_x86_64:
+ m_context.R10 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r11_x86_64:
+ m_context.R11 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r12_x86_64:
+ m_context.R12 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r13_x86_64:
+ m_context.R13 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r14_x86_64:
+ m_context.R14 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r15_x86_64:
+ m_context.R15 = reg_value.GetAsUInt64();
+ break;
+ case lldb_rbp_x86_64:
+ m_context.Rbp = reg_value.GetAsUInt64();
+ break;
+ case lldb_rsp_x86_64:
+ m_context.Rsp = reg_value.GetAsUInt64();
+ break;
+ case lldb_rip_x86_64:
+ m_context.Rip = reg_value.GetAsUInt64();
+ break;
+ case lldb_rflags_x86_64:
+ m_context.EFlags = reg_value.GetAsUInt64();
+ break;
+ }
+
+ // Physically update the registers in the target process.
+ TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
+ return ::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context);
+}
diff --git a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h
new file mode 100644
index 000000000000..e69179d99c6c
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h
@@ -0,0 +1,48 @@
+//===-- RegisterContextWindows_x64.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_RegisterContextWindows_x64_H_
+#define liblldb_RegisterContextWindows_x64_H_
+
+#include "lldb/lldb-forward.h"
+#include "RegisterContextWindows.h"
+
+namespace lldb_private
+{
+
+class Thread;
+
+class RegisterContextWindows_x64 : public RegisterContextWindows
+{
+ public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextWindows_x64(Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual ~RegisterContextWindows_x64();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ size_t GetRegisterCount() override;
+
+ const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const RegisterSet *GetRegisterSet(size_t reg_set) override;
+
+ bool ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value) override;
+
+ bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
+};
+}
+
+#endif // #ifndef liblldb_RegisterContextWindows_x64_H_
diff --git a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp
new file mode 100644
index 000000000000..e57e1effec9c
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp
@@ -0,0 +1,178 @@
+//===-- RegisterContextWindows_x86.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/lldb-private-types.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+#include "lldb/Host/windows/windows.h"
+
+#include "lldb-x86-register-enums.h"
+#include "ProcessWindowsLog.h"
+#include "RegisterContext_x86.h"
+#include "RegisterContextWindows_x86.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define DEFINE_GPR(reg, alt) #reg, alt, 4, 0, eEncodingUint, eFormatHexUppercase
+#define DEFINE_GPR_BIN(reg, alt) #reg, alt, 4, 0, eEncodingUint, eFormatBinary
+
+namespace
+{
+
+// This enum defines the layout of the global RegisterInfo array. This is necessary because
+// lldb register sets are defined in terms of indices into the register array. As such, the
+// order of RegisterInfos defined in global registers array must match the order defined here.
+// When defining the register set layouts, these values can appear in an arbitrary order, and that
+// determines the order that register values are displayed in a dump.
+enum RegisterIndex
+{
+ eRegisterIndexEax,
+ eRegisterIndexEbx,
+ eRegisterIndexEcx,
+ eRegisterIndexEdx,
+ eRegisterIndexEdi,
+ eRegisterIndexEsi,
+ eRegisterIndexEbp,
+ eRegisterIndexEsp,
+ eRegisterIndexEip,
+ eRegisterIndexEflags
+};
+
+// Array of all register information supported by Windows x86
+RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff eh_frame DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// ============================== ======================= =================== ========================= =================== ================= ========== ===============
+ { DEFINE_GPR(eax, nullptr), { ehframe_eax_i386, dwarf_eax_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_eax_i386 }, nullptr, nullptr},
+ { DEFINE_GPR(ebx, nullptr), { ehframe_ebx_i386, dwarf_ebx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_ebx_i386 }, nullptr, nullptr},
+ { DEFINE_GPR(ecx, nullptr), { ehframe_ecx_i386, dwarf_ecx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_ecx_i386 }, nullptr, nullptr},
+ { DEFINE_GPR(edx, nullptr), { ehframe_edx_i386, dwarf_edx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_edx_i386 }, nullptr, nullptr},
+ { DEFINE_GPR(edi, nullptr), { ehframe_edi_i386, dwarf_edi_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_edi_i386 }, nullptr, nullptr},
+ { DEFINE_GPR(esi, nullptr), { ehframe_esi_i386, dwarf_esi_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_esi_i386 }, nullptr, nullptr},
+ { DEFINE_GPR(ebp, "fp"), { ehframe_ebp_i386, dwarf_ebp_i386, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, lldb_ebp_i386 }, nullptr, nullptr},
+ { DEFINE_GPR(esp, "sp"), { ehframe_esp_i386, dwarf_esp_i386, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, lldb_esp_i386 }, nullptr, nullptr},
+ { DEFINE_GPR(eip, "pc"), { ehframe_eip_i386, dwarf_eip_i386, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, lldb_eip_i386 }, nullptr, nullptr},
+ { DEFINE_GPR_BIN(eflags, "flags"), { ehframe_eflags_i386, dwarf_eflags_i386, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, lldb_eflags_i386}, nullptr, nullptr},
+};
+
+// Array of lldb register numbers used to define the set of all General Purpose Registers
+uint32_t g_gpr_reg_indices[] =
+{
+ eRegisterIndexEax,
+ eRegisterIndexEbx,
+ eRegisterIndexEcx,
+ eRegisterIndexEdx,
+ eRegisterIndexEdi,
+ eRegisterIndexEsi,
+ eRegisterIndexEbp,
+ eRegisterIndexEsp,
+ eRegisterIndexEip,
+ eRegisterIndexEflags
+};
+
+RegisterSet g_register_sets[] = {
+ {"General Purpose Registers", "gpr", llvm::array_lengthof(g_gpr_reg_indices), g_gpr_reg_indices},
+};
+}
+
+//------------------------------------------------------------------
+// Constructors and Destructors
+//------------------------------------------------------------------
+RegisterContextWindows_x86::RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContextWindows(thread, concrete_frame_idx)
+{
+}
+
+RegisterContextWindows_x86::~RegisterContextWindows_x86()
+{
+}
+
+size_t
+RegisterContextWindows_x86::GetRegisterCount()
+{
+ return llvm::array_lengthof(g_register_infos);
+}
+
+const RegisterInfo *
+RegisterContextWindows_x86::GetRegisterInfoAtIndex(size_t reg)
+{
+ return &g_register_infos[reg];
+}
+
+size_t
+RegisterContextWindows_x86::GetRegisterSetCount()
+{
+ return llvm::array_lengthof(g_register_sets);
+}
+
+const RegisterSet *
+RegisterContextWindows_x86::GetRegisterSet(size_t reg_set)
+{
+ return &g_register_sets[reg_set];
+}
+
+bool
+RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ if (!CacheAllRegisterValues())
+ return false;
+
+ uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ switch (reg)
+ {
+ case lldb_eax_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EAX", m_context.Eax);
+ reg_value.SetUInt32(m_context.Eax);
+ break;
+ case lldb_ebx_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EBX", m_context.Ebx);
+ reg_value.SetUInt32(m_context.Ebx);
+ break;
+ case lldb_ecx_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from ECX", m_context.Ecx);
+ reg_value.SetUInt32(m_context.Ecx);
+ break;
+ case lldb_edx_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EDX", m_context.Edx);
+ reg_value.SetUInt32(m_context.Edx);
+ break;
+ case lldb_edi_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EDI", m_context.Edi);
+ reg_value.SetUInt32(m_context.Edi);
+ break;
+ case lldb_esi_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from ESI", m_context.Esi);
+ reg_value.SetUInt32(m_context.Esi);
+ break;
+ case lldb_ebp_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EBP", m_context.Ebp);
+ reg_value.SetUInt32(m_context.Ebp);
+ break;
+ case lldb_esp_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from ESP", m_context.Esp);
+ reg_value.SetUInt32(m_context.Esp);
+ break;
+ case lldb_eip_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EIP", m_context.Eip);
+ reg_value.SetUInt32(m_context.Eip);
+ break;
+ case lldb_eflags_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Read value 0x%x from EFLAGS", m_context.EFlags);
+ reg_value.SetUInt32(m_context.EFlags);
+ break;
+ default:
+ WINWARN_IFALL(WINDOWS_LOG_REGISTERS, "Requested unknown register %u", reg);
+ break;
+ }
+ return true;
+}
diff --git a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h
new file mode 100644
index 000000000000..7d854ef64a5c
--- /dev/null
+++ b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h
@@ -0,0 +1,48 @@
+//===-- RegisterContextWindows_x86.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_RegisterContextWindows_x86_H_
+#define liblldb_RegisterContextWindows_x86_H_
+
+#include "lldb/lldb-forward.h"
+#include "RegisterContextWindows.h"
+
+namespace lldb_private
+{
+
+class Thread;
+
+class RegisterContextWindows_x86 : public RegisterContextWindows
+{
+ public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual ~RegisterContextWindows_x86();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ size_t GetRegisterCount() override;
+
+ const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const RegisterSet *GetRegisterSet(size_t reg_set) override;
+
+ bool ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value) override;
+
+};
+
+}
+
+#endif // #ifndef liblldb_RegisterContextWindows_x86_H_
diff --git a/source/Plugins/Process/Windows/Live/CMakeLists.txt b/source/Plugins/Process/Windows/Live/CMakeLists.txt
new file mode 100644
index 000000000000..bdb680ad0bee
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/CMakeLists.txt
@@ -0,0 +1,24 @@
+include_directories(.)
+include_directories(../../Utility)
+include_directories(../Common)
+
+set(PROC_WINDOWS_SOURCES
+ DebuggerThread.cpp
+ LocalDebugDelegate.cpp
+ ProcessWindowsLive.cpp
+ TargetThreadWindowsLive.cpp
+ )
+
+if (CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(PROC_WINDOWS_SOURCES ${PROC_WINDOWS_SOURCES}
+ x86/RegisterContextWindowsLive_x86.cpp
+ )
+elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(PROC_WINDOWS_SOURCES ${PROC_WINDOWS_SOURCES}
+ x64/RegisterContextWindowsLive_x64.cpp
+ )
+endif()
+
+add_lldb_library(lldbPluginProcessWindows
+ ${PROC_WINDOWS_SOURCES}
+ )
diff --git a/source/Plugins/Process/Windows/Live/DebuggerThread.cpp b/source/Plugins/Process/Windows/Live/DebuggerThread.cpp
new file mode 100644
index 000000000000..d058a412c896
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/DebuggerThread.cpp
@@ -0,0 +1,546 @@
+//===-- DebuggerThread.DebuggerThread --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DebuggerThread.h"
+#include "ExceptionRecord.h"
+#include "IDebugDelegate.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Host/ThisThread.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/windows/HostProcessWindows.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+#include "lldb/Host/windows/ProcessLauncherWindows.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+#include "lldb/Target/Process.h"
+
+#include "Plugins/Process/Windows/Common/ProcessWindowsLog.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+struct DebugLaunchContext
+{
+ DebugLaunchContext(DebuggerThread *thread, const ProcessLaunchInfo &launch_info)
+ : m_thread(thread)
+ , m_launch_info(launch_info)
+ {
+ }
+ DebuggerThread *m_thread;
+ ProcessLaunchInfo m_launch_info;
+};
+
+struct DebugAttachContext
+{
+ DebugAttachContext(DebuggerThread *thread, lldb::pid_t pid, const ProcessAttachInfo &attach_info)
+ : m_thread(thread)
+ , m_pid(pid)
+ , m_attach_info(attach_info)
+ {
+ }
+ DebuggerThread *m_thread;
+ lldb::pid_t m_pid;
+ ProcessAttachInfo m_attach_info;
+};
+}
+
+DebuggerThread::DebuggerThread(DebugDelegateSP debug_delegate)
+ : m_debug_delegate(debug_delegate)
+ , m_image_file(nullptr)
+ , m_debugging_ended_event(nullptr)
+ , m_is_shutting_down(false)
+ , m_pid_to_detach(0)
+ , m_detached(false)
+{
+ m_debugging_ended_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
+}
+
+DebuggerThread::~DebuggerThread()
+{
+ ::CloseHandle(m_debugging_ended_event);
+}
+
+Error
+DebuggerThread::DebugLaunch(const ProcessLaunchInfo &launch_info)
+{
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS,
+ "DebuggerThread::DebugLaunch launching '%s'", launch_info.GetExecutableFile().GetPath().c_str());
+
+ Error error;
+ DebugLaunchContext *context = new DebugLaunchContext(this, launch_info);
+ HostThread slave_thread(ThreadLauncher::LaunchThread("lldb.plugin.process-windows.slave[?]",
+ DebuggerThreadLaunchRoutine, context, &error));
+
+ if (!error.Success())
+ {
+ WINERR_IFALL(WINDOWS_LOG_PROCESS,
+ "DebugLaunch couldn't launch debugger thread. %s", error.AsCString());
+ }
+
+ return error;
+}
+
+Error
+DebuggerThread::DebugAttach(lldb::pid_t pid, const ProcessAttachInfo &attach_info)
+{
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DebuggerThread::DebugAttach attaching to '%u'", (DWORD)pid);
+
+ Error error;
+ DebugAttachContext *context = new DebugAttachContext(this, pid, attach_info);
+ HostThread slave_thread(ThreadLauncher::LaunchThread("lldb.plugin.process-windows.slave[?]",
+ DebuggerThreadAttachRoutine, context, &error));
+
+ if (!error.Success())
+ {
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, "DebugAttach couldn't attach to process '%u'. %s", (DWORD)pid,
+ error.AsCString());
+ }
+
+ return error;
+}
+
+lldb::thread_result_t
+DebuggerThread::DebuggerThreadLaunchRoutine(void *data)
+{
+ DebugLaunchContext *context = static_cast<DebugLaunchContext *>(data);
+ lldb::thread_result_t result = context->m_thread->DebuggerThreadLaunchRoutine(context->m_launch_info);
+ delete context;
+ return result;
+}
+
+lldb::thread_result_t
+DebuggerThread::DebuggerThreadAttachRoutine(void *data)
+{
+ DebugAttachContext *context = static_cast<DebugAttachContext *>(data);
+ lldb::thread_result_t result =
+ context->m_thread->DebuggerThreadAttachRoutine(context->m_pid, context->m_attach_info);
+ delete context;
+ return result;
+}
+
+lldb::thread_result_t
+DebuggerThread::DebuggerThreadLaunchRoutine(const ProcessLaunchInfo &launch_info)
+{
+ // Grab a shared_ptr reference to this so that we know it won't get deleted until after the
+ // thread routine has exited.
+ std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
+
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DebuggerThread preparing to launch '%s' on background thread.",
+ launch_info.GetExecutableFile().GetPath().c_str());
+
+ Error error;
+ ProcessLauncherWindows launcher;
+ HostProcess process(launcher.LaunchProcess(launch_info, error));
+ // If we couldn't create the process, notify waiters immediately. Otherwise enter the debug
+ // loop and wait until we get the create process debug notification. Note that if the process
+ // was created successfully, we can throw away the process handle we got from CreateProcess
+ // because Windows will give us another (potentially more useful?) handle when it sends us the
+ // CREATE_PROCESS_DEBUG_EVENT.
+ if (error.Success())
+ DebugLoop();
+ else
+ m_debug_delegate->OnDebuggerError(error, 0);
+
+ return 0;
+}
+
+lldb::thread_result_t
+DebuggerThread::DebuggerThreadAttachRoutine(lldb::pid_t pid, const ProcessAttachInfo &attach_info)
+{
+ // Grab a shared_ptr reference to this so that we know it won't get deleted until after the
+ // thread routine has exited.
+ std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
+
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DebuggerThread preparing to attach to process '%u' on background thread.",
+ (DWORD)pid);
+
+ if (!DebugActiveProcess((DWORD)pid))
+ {
+ Error error(::GetLastError(), eErrorTypeWin32);
+ m_debug_delegate->OnDebuggerError(error, 0);
+ return 0;
+ }
+
+ // The attach was successful, enter the debug loop. From here on out, this is no different than
+ // a create process operation, so all the same comments in DebugLaunch should apply from this
+ // point out.
+ DebugLoop();
+
+ return 0;
+}
+
+Error
+DebuggerThread::StopDebugging(bool terminate)
+{
+ Error error;
+
+ lldb::pid_t pid = m_process.GetProcessId();
+
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS,
+ "StopDebugging('%s') called (inferior=%I64u).",
+ (terminate ? "true" : "false"), pid);
+
+ // Set m_is_shutting_down to true if it was false. Return if it was already true.
+ bool expected = false;
+ if (!m_is_shutting_down.compare_exchange_strong(expected, true))
+ return error;
+
+ // Make a copy of the process, since the termination sequence will reset
+ // DebuggerThread's internal copy and it needs to remain open for the Wait operation.
+ HostProcess process_copy = m_process;
+ lldb::process_t handle = m_process.GetNativeProcess().GetSystemHandle();
+
+ if (terminate)
+ {
+ // Initiate the termination before continuing the exception, so that the next debug
+ // event we get is the exit process event, and not some other event.
+ BOOL terminate_suceeded = TerminateProcess(handle, 0);
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS,
+ "StopDebugging called TerminateProcess(0x%p, 0) (inferior=%I64u), success='%s'",
+ handle, pid, (terminate_suceeded ? "true" : "false"));
+ }
+
+ // If we're stuck waiting for an exception to continue (e.g. the user is at a breakpoint
+ // messing around in the debugger), continue it now. But only AFTER calling TerminateProcess
+ // to make sure that the very next call to WaitForDebugEvent is an exit process event.
+ if (m_active_exception.get())
+ {
+ WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_EXCEPTION,
+ "StopDebugging masking active exception");
+
+ ContinueAsyncException(ExceptionResult::MaskException);
+ }
+
+ if (!terminate)
+ {
+ // Indicate that we want to detach.
+ m_pid_to_detach = GetProcess().GetProcessId();
+
+ // Force a fresh break so that the detach can happen from the debugger thread.
+ if (!::DebugBreakProcess(GetProcess().GetNativeProcess().GetSystemHandle()))
+ {
+ error.SetError(::GetLastError(), eErrorTypeWin32);
+ }
+ }
+
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "StopDebugging waiting for detach from process %u to complete.", pid);
+
+ DWORD wait_result = WaitForSingleObject(m_debugging_ended_event, 5000);
+ if (wait_result != WAIT_OBJECT_0)
+ {
+ error.SetError(GetLastError(), eErrorTypeWin32);
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, "StopDebugging WaitForSingleObject(0x%p, 5000) returned %u",
+ m_debugging_ended_event, wait_result);
+ }
+ else
+ {
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "StopDebugging detach from process %u completed successfully.", pid);
+ }
+
+ if (!error.Success())
+ {
+ WINERR_IFALL(WINDOWS_LOG_PROCESS,
+ "StopDebugging encountered an error while trying to stop process %u. %s",
+ pid, error.AsCString());
+ }
+ return error;
+}
+
+void
+DebuggerThread::ContinueAsyncException(ExceptionResult result)
+{
+ if (!m_active_exception.get())
+ return;
+
+ WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_EXCEPTION,
+ "ContinueAsyncException called for inferior process %I64u, broadcasting.",
+ m_process.GetProcessId());
+
+ m_active_exception.reset();
+ m_exception_pred.SetValue(result, eBroadcastAlways);
+}
+
+void
+DebuggerThread::FreeProcessHandles()
+{
+ m_process = HostProcess();
+ m_main_thread = HostThread();
+ if (m_image_file)
+ {
+ ::CloseHandle(m_image_file);
+ m_image_file = nullptr;
+ }
+}
+
+void
+DebuggerThread::DebugLoop()
+{
+ DEBUG_EVENT dbe = {0};
+ bool should_debug = true;
+ WINLOG_IFALL(WINDOWS_LOG_EVENT, "Entering WaitForDebugEvent loop");
+ while (should_debug)
+ {
+ WINLOGD_IFALL(WINDOWS_LOG_EVENT, "Calling WaitForDebugEvent");
+ BOOL wait_result = WaitForDebugEvent(&dbe, INFINITE);
+ if (wait_result)
+ {
+ DWORD continue_status = DBG_CONTINUE;
+ switch (dbe.dwDebugEventCode)
+ {
+ case EXCEPTION_DEBUG_EVENT:
+ {
+ ExceptionResult status = HandleExceptionEvent(dbe.u.Exception, dbe.dwThreadId);
+
+ if (status == ExceptionResult::MaskException)
+ continue_status = DBG_CONTINUE;
+ else if (status == ExceptionResult::SendToApplication)
+ continue_status = DBG_EXCEPTION_NOT_HANDLED;
+
+ break;
+ }
+ case CREATE_THREAD_DEBUG_EVENT:
+ continue_status = HandleCreateThreadEvent(dbe.u.CreateThread, dbe.dwThreadId);
+ break;
+ case CREATE_PROCESS_DEBUG_EVENT:
+ continue_status = HandleCreateProcessEvent(dbe.u.CreateProcessInfo, dbe.dwThreadId);
+ break;
+ case EXIT_THREAD_DEBUG_EVENT:
+ continue_status = HandleExitThreadEvent(dbe.u.ExitThread, dbe.dwThreadId);
+ break;
+ case EXIT_PROCESS_DEBUG_EVENT:
+ continue_status = HandleExitProcessEvent(dbe.u.ExitProcess, dbe.dwThreadId);
+ should_debug = false;
+ break;
+ case LOAD_DLL_DEBUG_EVENT:
+ continue_status = HandleLoadDllEvent(dbe.u.LoadDll, dbe.dwThreadId);
+ break;
+ case UNLOAD_DLL_DEBUG_EVENT:
+ continue_status = HandleUnloadDllEvent(dbe.u.UnloadDll, dbe.dwThreadId);
+ break;
+ case OUTPUT_DEBUG_STRING_EVENT:
+ continue_status = HandleODSEvent(dbe.u.DebugString, dbe.dwThreadId);
+ break;
+ case RIP_EVENT:
+ continue_status = HandleRipEvent(dbe.u.RipInfo, dbe.dwThreadId);
+ if (dbe.u.RipInfo.dwType == SLE_ERROR)
+ should_debug = false;
+ break;
+ }
+
+ WINLOGD_IFALL(WINDOWS_LOG_EVENT, "DebugLoop calling ContinueDebugEvent(%u, %u, %u) on thread %u.",
+ dbe.dwProcessId, dbe.dwThreadId, continue_status, ::GetCurrentThreadId());
+
+ ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status);
+
+ if (m_detached)
+ {
+ should_debug = false;
+ }
+ }
+ else
+ {
+ WINERR_IFALL(WINDOWS_LOG_EVENT,
+ "DebugLoop returned FALSE from WaitForDebugEvent. Error = %u",
+ ::GetCurrentThreadId(), ::GetLastError());
+
+ should_debug = false;
+ }
+ }
+ FreeProcessHandles();
+
+ WINLOG_IFALL(WINDOWS_LOG_EVENT, "WaitForDebugEvent loop completed, exiting.");
+ SetEvent(m_debugging_ended_event);
+}
+
+ExceptionResult
+DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id)
+{
+ if (m_is_shutting_down)
+ {
+ // A breakpoint that occurs while `m_pid_to_detach` is non-zero is a magic exception that
+ // we use simply to wake up the DebuggerThread so that we can close out the debug loop.
+ if (m_pid_to_detach != 0 && info.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
+ {
+ WINLOG_IFANY(WINDOWS_LOG_EVENT | WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_PROCESS,
+ "Breakpoint exception is cue to detach from process 0x%x",
+ m_pid_to_detach);
+ ::DebugActiveProcessStop(m_pid_to_detach);
+ m_detached = true;
+ }
+
+ // Don't perform any blocking operations while we're shutting down. That will
+ // cause TerminateProcess -> WaitForSingleObject to time out.
+ return ExceptionResult::SendToApplication;
+ }
+
+ bool first_chance = (info.dwFirstChance != 0);
+
+ m_active_exception.reset(new ExceptionRecord(info.ExceptionRecord, thread_id));
+ WINLOG_IFANY(WINDOWS_LOG_EVENT | WINDOWS_LOG_EXCEPTION,
+ "HandleExceptionEvent encountered %s chance exception 0x%x on thread 0x%x",
+ first_chance ? "first" : "second", info.ExceptionRecord.ExceptionCode, thread_id);
+
+ ExceptionResult result = m_debug_delegate->OnDebugException(first_chance,
+ *m_active_exception);
+ m_exception_pred.SetValue(result, eBroadcastNever);
+
+ WINLOG_IFANY(WINDOWS_LOG_EVENT|WINDOWS_LOG_EXCEPTION,
+ "DebuggerThread::HandleExceptionEvent waiting for ExceptionPred != BreakInDebugger");
+
+ m_exception_pred.WaitForValueNotEqualTo(ExceptionResult::BreakInDebugger, result);
+
+ WINLOG_IFANY(WINDOWS_LOG_EVENT|WINDOWS_LOG_EXCEPTION,
+ "DebuggerThread::HandleExceptionEvent got ExceptionPred = %u",
+ m_exception_pred.GetValue());
+
+ return result;
+}
+
+DWORD
+DebuggerThread::HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id)
+{
+ WINLOG_IFANY(WINDOWS_LOG_EVENT|WINDOWS_LOG_THREAD,
+ "HandleCreateThreadEvent Thread 0x%x spawned in process %I64u",
+ thread_id, m_process.GetProcessId());
+ HostThread thread(info.hThread);
+ thread.GetNativeThread().SetOwnsHandle(false);
+ m_debug_delegate->OnCreateThread(thread);
+ return DBG_CONTINUE;
+}
+
+DWORD
+DebuggerThread::HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, DWORD thread_id)
+{
+ uint32_t process_id = ::GetProcessId(info.hProcess);
+
+ WINLOG_IFANY(WINDOWS_LOG_EVENT | WINDOWS_LOG_PROCESS, "HandleCreateProcessEvent process %u spawned", process_id);
+
+ std::string thread_name;
+ llvm::raw_string_ostream name_stream(thread_name);
+ name_stream << "lldb.plugin.process-windows.slave[" << process_id << "]";
+ name_stream.flush();
+ ThisThread::SetName(thread_name.c_str());
+
+ // info.hProcess and info.hThread are closed automatically by Windows when
+ // EXIT_PROCESS_DEBUG_EVENT is received.
+ m_process = HostProcess(info.hProcess);
+ ((HostProcessWindows &)m_process.GetNativeProcess()).SetOwnsHandle(false);
+ m_main_thread = HostThread(info.hThread);
+ m_main_thread.GetNativeThread().SetOwnsHandle(false);
+ m_image_file = info.hFile;
+
+ lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfImage);
+ m_debug_delegate->OnDebuggerConnected(load_addr);
+
+ return DBG_CONTINUE;
+}
+
+DWORD
+DebuggerThread::HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD thread_id)
+{
+ WINLOG_IFANY(WINDOWS_LOG_EVENT|WINDOWS_LOG_THREAD,
+ "HandleExitThreadEvent Thread %u exited with code %u in process %I64u",
+ thread_id, info.dwExitCode, m_process.GetProcessId());
+ m_debug_delegate->OnExitThread(thread_id, info.dwExitCode);
+ return DBG_CONTINUE;
+}
+
+DWORD
+DebuggerThread::HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, DWORD thread_id)
+{
+ WINLOG_IFANY(WINDOWS_LOG_EVENT|WINDOWS_LOG_THREAD,
+ "HandleExitProcessEvent process %I64u exited with code %u",
+ m_process.GetProcessId(), info.dwExitCode);
+
+ m_debug_delegate->OnExitProcess(info.dwExitCode);
+
+ FreeProcessHandles();
+ return DBG_CONTINUE;
+}
+
+DWORD
+DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id)
+{
+ if (info.hFile == nullptr)
+ {
+ // Not sure what this is, so just ignore it.
+ WINWARN_IFALL(WINDOWS_LOG_EVENT, "Inferior %I64u - HandleLoadDllEvent has a NULL file handle, returning...",
+ m_process.GetProcessId());
+ return DBG_CONTINUE;
+ }
+
+ std::vector<char> buffer(1);
+ DWORD required_size = GetFinalPathNameByHandle(info.hFile, &buffer[0], 0, VOLUME_NAME_DOS);
+ if (required_size > 0)
+ {
+ buffer.resize(required_size + 1);
+ required_size = GetFinalPathNameByHandle(info.hFile, &buffer[0], required_size + 1, VOLUME_NAME_DOS);
+ llvm::StringRef path_str(&buffer[0]);
+ const char *path = path_str.data();
+ if (path_str.startswith("\\\\?\\"))
+ path += 4;
+
+ FileSpec file_spec(path, false);
+ ModuleSpec module_spec(file_spec);
+ lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll);
+
+ WINLOG_IFALL(WINDOWS_LOG_EVENT, "Inferior %I64u - HandleLoadDllEvent DLL '%s' loaded at address 0x%p...",
+ m_process.GetProcessId(), path, info.lpBaseOfDll);
+
+ m_debug_delegate->OnLoadDll(module_spec, load_addr);
+ }
+ else
+ {
+ WINERR_IFALL(WINDOWS_LOG_EVENT,
+ "Inferior %I64u - HandleLoadDllEvent Error %u occurred calling GetFinalPathNameByHandle",
+ m_process.GetProcessId(), ::GetLastError());
+ }
+ // Windows does not automatically close info.hFile, so we need to do it.
+ ::CloseHandle(info.hFile);
+ return DBG_CONTINUE;
+}
+
+DWORD
+DebuggerThread::HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, DWORD thread_id)
+{
+ WINLOG_IFALL(WINDOWS_LOG_EVENT,
+ "HandleUnloadDllEvent process %I64u unloading DLL at addr 0x%p.",
+ m_process.GetProcessId(), info.lpBaseOfDll);
+
+ m_debug_delegate->OnUnloadDll(reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll));
+ return DBG_CONTINUE;
+}
+
+DWORD
+DebuggerThread::HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, DWORD thread_id)
+{
+ return DBG_CONTINUE;
+}
+
+DWORD
+DebuggerThread::HandleRipEvent(const RIP_INFO &info, DWORD thread_id)
+{
+ WINERR_IFALL(WINDOWS_LOG_EVENT,
+ "HandleRipEvent encountered error %u (type=%u) in process %I64u thread %u",
+ info.dwError, info.dwType, m_process.GetProcessId(), thread_id);
+
+ Error error(info.dwError, eErrorTypeWin32);
+ m_debug_delegate->OnDebuggerError(error, info.dwType);
+
+ return DBG_CONTINUE;
+}
diff --git a/source/Plugins/Process/Windows/Live/DebuggerThread.h b/source/Plugins/Process/Windows/Live/DebuggerThread.h
new file mode 100644
index 000000000000..6a2619413950
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/DebuggerThread.h
@@ -0,0 +1,100 @@
+//===-- DebuggerThread.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_Plugins_Process_Windows_DebuggerThread_H_
+#define liblldb_Plugins_Process_Windows_DebuggerThread_H_
+
+#include <atomic>
+#include <memory>
+
+#include "ForwardDecl.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Host/windows/windows.h"
+
+namespace lldb_private
+{
+
+//----------------------------------------------------------------------
+// DebuggerThread
+//
+// Debugs a single process, notifying listeners as appropriate when interesting
+// things occur.
+//----------------------------------------------------------------------
+class DebuggerThread : public std::enable_shared_from_this<DebuggerThread>
+{
+ public:
+ DebuggerThread(DebugDelegateSP debug_delegate);
+ virtual ~DebuggerThread();
+
+ Error DebugLaunch(const ProcessLaunchInfo &launch_info);
+ Error DebugAttach(lldb::pid_t pid, const ProcessAttachInfo &attach_info);
+
+ HostProcess
+ GetProcess() const
+ {
+ return m_process;
+ }
+ HostThread
+ GetMainThread() const
+ {
+ return m_main_thread;
+ }
+ std::weak_ptr<ExceptionRecord>
+ GetActiveException()
+ {
+ return m_active_exception;
+ }
+
+ Error StopDebugging(bool terminate);
+
+ void ContinueAsyncException(ExceptionResult result);
+
+ private:
+ void FreeProcessHandles();
+ void DebugLoop();
+ ExceptionResult HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id);
+ DWORD HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id);
+ DWORD HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, DWORD thread_id);
+ DWORD HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD thread_id);
+ DWORD HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, DWORD thread_id);
+ DWORD HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id);
+ DWORD HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, DWORD thread_id);
+ DWORD HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, DWORD thread_id);
+ DWORD HandleRipEvent(const RIP_INFO &info, DWORD thread_id);
+
+ DebugDelegateSP m_debug_delegate;
+
+ HostProcess m_process; // The process being debugged.
+ HostThread m_main_thread; // The main thread of the inferior.
+ HANDLE m_image_file; // The image file of the process being debugged.
+
+ ExceptionRecordSP m_active_exception; // The current exception waiting to be handled
+
+ Predicate<ExceptionResult> m_exception_pred; // A predicate which gets signalled when an exception
+ // is finished processing and the debug loop can be
+ // continued.
+
+ HANDLE m_debugging_ended_event; // An event which gets signalled by the debugger thread when it
+ // exits the debugger loop and is detached from the inferior.
+
+ std::atomic<DWORD> m_pid_to_detach; // Signals the loop to detach from the process (specified by pid).
+ std::atomic<bool> m_is_shutting_down; // Signals the debug loop to stop processing certain types of
+ // events that block shutdown.
+ bool m_detached; // Indicates we've detached from the inferior process and the debug loop can exit.
+
+ static lldb::thread_result_t DebuggerThreadLaunchRoutine(void *data);
+ lldb::thread_result_t DebuggerThreadLaunchRoutine(const ProcessLaunchInfo &launch_info);
+ static lldb::thread_result_t DebuggerThreadAttachRoutine(void *data);
+ lldb::thread_result_t DebuggerThreadAttachRoutine(lldb::pid_t pid, const ProcessAttachInfo &launch_info);
+};
+}
+
+#endif
diff --git a/source/Plugins/Process/Windows/Live/ForwardDecl.h b/source/Plugins/Process/Windows/Live/ForwardDecl.h
new file mode 100644
index 000000000000..a782597555e1
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/ForwardDecl.h
@@ -0,0 +1,41 @@
+//===-- ForwardDecl.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_Plugins_Process_Windows_ForwardDecl_H_
+#define liblldb_Plugins_Process_Windows_ForwardDecl_H_
+
+#include <memory>
+
+// ExceptionResult is returned by the debug delegate to specify how it processed
+// the exception.
+enum class ExceptionResult
+{
+ BreakInDebugger, // Break in the debugger and give the user a chance to interact with
+ // the program before continuing.
+ MaskException, // Eat the exception and don't let the application know it occurred.
+ SendToApplication // Send the exception to the application to be handled as if there were
+ // no debugger attached.
+};
+
+namespace lldb_private
+{
+
+class ProcessWindows;
+
+class IDebugDelegate;
+class DebuggerThread;
+class ExceptionRecord;
+
+typedef std::shared_ptr<IDebugDelegate> DebugDelegateSP;
+typedef std::shared_ptr<DebuggerThread> DebuggerThreadSP;
+typedef std::shared_ptr<ExceptionRecord> ExceptionRecordSP;
+typedef std::unique_ptr<ExceptionRecord> ExceptionRecordUP;
+}
+
+#endif \ No newline at end of file
diff --git a/source/Plugins/Process/Windows/Live/IDebugDelegate.h b/source/Plugins/Process/Windows/Live/IDebugDelegate.h
new file mode 100644
index 000000000000..0e7849bb8ffe
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/IDebugDelegate.h
@@ -0,0 +1,46 @@
+//===-- IDebugDelegate.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_Plugins_Process_Windows_IDebugDelegate_H_
+#define liblldb_Plugins_Process_Windows_IDebugDelegate_H_
+
+#include "ForwardDecl.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+#include <string>
+
+namespace lldb_private
+{
+class Error;
+class HostThread;
+
+//----------------------------------------------------------------------
+// IDebugDelegate
+//
+// IDebugDelegate defines an interface which allows implementors to receive
+// notification of events that happen in a debugged process.
+//----------------------------------------------------------------------
+class IDebugDelegate
+{
+ public:
+ virtual ~IDebugDelegate() {}
+
+ virtual void OnExitProcess(uint32_t exit_code) = 0;
+ virtual void OnDebuggerConnected(lldb::addr_t image_base) = 0;
+ virtual ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record) = 0;
+ virtual void OnCreateThread(const HostThread &thread) = 0;
+ virtual void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) = 0;
+ virtual void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) = 0;
+ virtual void OnUnloadDll(lldb::addr_t module_addr) = 0;
+ virtual void OnDebugString(const std::string &string) = 0;
+ virtual void OnDebuggerError(const Error &error, uint32_t type) = 0;
+};
+}
+
+#endif
diff --git a/source/Plugins/Process/Windows/Live/LocalDebugDelegate.cpp b/source/Plugins/Process/Windows/Live/LocalDebugDelegate.cpp
new file mode 100644
index 000000000000..a0ac9725c756
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/LocalDebugDelegate.cpp
@@ -0,0 +1,91 @@
+//===-- LocalDebugDelegate.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LocalDebugDelegate.h"
+#include "ProcessWindowsLive.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LocalDebugDelegate::LocalDebugDelegate(ProcessWP process)
+ : m_process(process)
+{
+}
+
+void
+LocalDebugDelegate::OnExitProcess(uint32_t exit_code)
+{
+ if (ProcessWindowsLiveSP process = GetProcessPointer())
+ process->OnExitProcess(exit_code);
+}
+
+void
+LocalDebugDelegate::OnDebuggerConnected(lldb::addr_t image_base)
+{
+ if (ProcessWindowsLiveSP process = GetProcessPointer())
+ process->OnDebuggerConnected(image_base);
+}
+
+ExceptionResult
+LocalDebugDelegate::OnDebugException(bool first_chance, const ExceptionRecord &record)
+{
+ if (ProcessWindowsLiveSP process = GetProcessPointer())
+ return process->OnDebugException(first_chance, record);
+ else
+ return ExceptionResult::MaskException;
+}
+
+void
+LocalDebugDelegate::OnCreateThread(const HostThread &thread)
+{
+ if (ProcessWindowsLiveSP process = GetProcessPointer())
+ process->OnCreateThread(thread);
+}
+
+void
+LocalDebugDelegate::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code)
+{
+ if (ProcessWindowsLiveSP process = GetProcessPointer())
+ process->OnExitThread(thread_id, exit_code);
+}
+
+void
+LocalDebugDelegate::OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr)
+{
+ if (ProcessWindowsLiveSP process = GetProcessPointer())
+ process->OnLoadDll(module_spec, module_addr);
+}
+
+void
+LocalDebugDelegate::OnUnloadDll(lldb::addr_t module_addr)
+{
+ if (ProcessWindowsLiveSP process = GetProcessPointer())
+ process->OnUnloadDll(module_addr);
+}
+
+void
+LocalDebugDelegate::OnDebugString(const std::string &string)
+{
+ if (ProcessWindowsLiveSP process = GetProcessPointer())
+ process->OnDebugString(string);
+}
+
+void
+LocalDebugDelegate::OnDebuggerError(const Error &error, uint32_t type)
+{
+ if (ProcessWindowsLiveSP process = GetProcessPointer())
+ process->OnDebuggerError(error, type);
+}
+
+ProcessWindowsLiveSP
+LocalDebugDelegate::GetProcessPointer()
+{
+ ProcessSP process = m_process.lock();
+ return std::static_pointer_cast<ProcessWindowsLive>(process);
+}
diff --git a/source/Plugins/Process/Windows/Live/LocalDebugDelegate.h b/source/Plugins/Process/Windows/Live/LocalDebugDelegate.h
new file mode 100644
index 000000000000..ec2f9418142f
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/LocalDebugDelegate.h
@@ -0,0 +1,68 @@
+//===-- LocalDebugDelegate.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_Plugins_Process_Windows_LocalDebugDelegate_H_
+#define liblldb_Plugins_Process_Windows_LocalDebugDelegate_H_
+
+#include <memory>
+
+#include "IDebugDelegate.h"
+
+#include "lldb/lldb-forward.h"
+
+namespace lldb_private
+{
+
+class ProcessWindowsLive;
+typedef std::shared_ptr<ProcessWindowsLive> ProcessWindowsLiveSP;
+
+//----------------------------------------------------------------------
+// LocalDebugDelegate
+//
+// LocalDebugDelegate creates a connection between a ProcessWindowsLive and the
+// debug driver. This serves to decouple ProcessWindowsLive from the debug driver.
+// It would be possible to get a similar decoupling by just having
+// ProcessWindowsLive implement this interface directly. There are two reasons why
+// we don't do this:
+//
+// 1) In the future when we add support for local debugging through LLGS, and we
+// go through the Native*Protocol interface, it is likely we will need the
+// additional flexibility provided by this sort of adapter pattern.
+// 2) LLDB holds a shared_ptr to the ProcessWindows, and our driver thread
+// needs access to it as well. To avoid a race condition, we want to make
+// sure that we're also holding onto a shared_ptr.
+// lldb_private::Process supports enable_shared_from_this, but that gives us
+// a ProcessSP (which is exactly what we are trying to decouple from the
+// driver), so this adapter serves as a way to transparently hold the
+// ProcessSP while still keeping it decoupled from the driver.
+//----------------------------------------------------------------------
+class LocalDebugDelegate : public IDebugDelegate
+{
+ public:
+ explicit LocalDebugDelegate(lldb::ProcessWP process);
+
+ void OnExitProcess(uint32_t exit_code) override;
+ void OnDebuggerConnected(lldb::addr_t image_base) override;
+ ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record) override;
+ void OnCreateThread(const HostThread &thread) override;
+ void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override;
+ void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override;
+ void OnUnloadDll(lldb::addr_t module_addr) override;
+ void OnDebugString(const std::string &message) override;
+ void OnDebuggerError(const Error &error, uint32_t type) override;
+
+ private:
+ ProcessWindowsLiveSP
+ GetProcessPointer();
+
+ lldb::ProcessWP m_process;
+};
+}
+
+#endif
diff --git a/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp b/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp
new file mode 100644
index 000000000000..55102cc12ebb
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp
@@ -0,0 +1,989 @@
+//===-- ProcessWindowsLive.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Windows includes
+#include "lldb/Host/windows/windows.h"
+#include <psapi.h>
+
+// C++ Includes
+#include <list>
+#include <mutex>
+#include <set>
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/HostNativeProcessBase.h"
+#include "lldb/Host/HostNativeThreadBase.h"
+#include "lldb/Host/MonitoringProcessLauncher.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+#include "lldb/Host/windows/ProcessLauncherWindows.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+
+#include "Plugins/Process/Windows/Common/ProcessWindowsLog.h"
+
+#include "DebuggerThread.h"
+#include "ExceptionRecord.h"
+#include "LocalDebugDelegate.h"
+#include "ProcessWindowsLive.h"
+#include "TargetThreadWindowsLive.h"
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define BOOL_STR(b) ((b) ? "true" : "false")
+
+namespace
+{
+
+std::string
+GetProcessExecutableName(HANDLE process_handle)
+{
+ std::vector<char> file_name;
+ DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit
+ DWORD copied = 0;
+ do
+ {
+ file_name_size *= 2;
+ file_name.resize(file_name_size);
+ copied = ::GetModuleFileNameEx(process_handle, NULL, file_name.data(), file_name_size);
+ } while (copied >= file_name_size);
+ file_name.resize(copied);
+ return std::string(file_name.begin(), file_name.end());
+}
+
+std::string
+GetProcessExecutableName(DWORD pid)
+{
+ std::string file_name;
+ HANDLE process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
+ if (process_handle != NULL)
+ {
+ file_name = GetProcessExecutableName(process_handle);
+ ::CloseHandle(process_handle);
+ }
+ return file_name;
+}
+
+} // anonymous namespace
+
+namespace lldb_private
+{
+
+// We store a pointer to this class in the ProcessWindows, so that we don't expose Windows
+// OS specific types and implementation details from a public header file.
+class ProcessWindowsData
+{
+ public:
+ ProcessWindowsData(bool stop_at_entry)
+ : m_stop_at_entry(stop_at_entry)
+ , m_initial_stop_event(nullptr)
+ , m_initial_stop_received(false)
+ {
+ m_initial_stop_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ }
+
+ ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); }
+
+ lldb_private::Error m_launch_error;
+ lldb_private::DebuggerThreadSP m_debugger;
+ StopInfoSP m_pending_stop_info;
+ HANDLE m_initial_stop_event;
+ bool m_stop_at_entry;
+ bool m_initial_stop_received;
+ std::map<lldb::tid_t, HostThread> m_new_threads;
+ std::set<lldb::tid_t> m_exited_threads;
+};
+}
+//------------------------------------------------------------------------------
+// Static functions.
+
+ProcessSP
+ProcessWindowsLive::CreateInstance(lldb::TargetSP target_sp, Listener &listener, const FileSpec *)
+{
+ return ProcessSP(new ProcessWindowsLive(target_sp, listener));
+}
+
+void
+ProcessWindowsLive::Initialize()
+{
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, []()
+ {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+ });
+}
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessWindowsLive::ProcessWindowsLive(lldb::TargetSP target_sp, Listener &listener)
+ : lldb_private::ProcessWindows(target_sp, listener)
+{
+}
+
+ProcessWindowsLive::~ProcessWindowsLive()
+{
+}
+
+void
+ProcessWindowsLive::Terminate()
+{
+}
+
+lldb_private::ConstString
+ProcessWindowsLive::GetPluginNameStatic()
+{
+ static ConstString g_name("windows");
+ return g_name;
+}
+
+const char *
+ProcessWindowsLive::GetPluginDescriptionStatic()
+{
+ return "Process plugin for Windows";
+}
+
+Error
+ProcessWindowsLive::EnableBreakpointSite(BreakpointSite *bp_site)
+{
+ WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS, "EnableBreakpointSite called with bp_site 0x%p "
+ "(id=%d, addr=0x%x)",
+ bp_site->GetID(), bp_site->GetLoadAddress());
+
+ Error error = EnableSoftwareBreakpoint(bp_site);
+ if (!error.Success())
+ {
+ WINERR_IFALL(WINDOWS_LOG_BREAKPOINTS, "EnableBreakpointSite failed. %s", error.AsCString());
+ }
+ return error;
+}
+
+Error
+ProcessWindowsLive::DisableBreakpointSite(BreakpointSite *bp_site)
+{
+ WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS, "DisableBreakpointSite called with bp_site 0x%p "
+ "(id=%d, addr=0x%x)",
+ bp_site->GetID(), bp_site->GetLoadAddress());
+
+ Error error = DisableSoftwareBreakpoint(bp_site);
+
+ if (!error.Success())
+ {
+ WINERR_IFALL(WINDOWS_LOG_BREAKPOINTS, "DisableBreakpointSite failed. %s", error.AsCString());
+ }
+ return error;
+}
+
+bool
+ProcessWindowsLive::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ // Add all the threads that were previously running and for which we did not detect a thread
+ // exited event.
+ int new_size = 0;
+ int continued_threads = 0;
+ int exited_threads = 0;
+ int new_threads = 0;
+
+ for (ThreadSP old_thread : old_thread_list.Threads())
+ {
+ lldb::tid_t old_thread_id = old_thread->GetID();
+ auto exited_thread_iter = m_session_data->m_exited_threads.find(old_thread_id);
+ if (exited_thread_iter == m_session_data->m_exited_threads.end())
+ {
+ new_thread_list.AddThread(old_thread);
+ ++new_size;
+ ++continued_threads;
+ WINLOGV_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - Thread %u was running and is still running.",
+ old_thread_id);
+ }
+ else
+ {
+ WINLOGV_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - Thread %u was running and has exited.",
+ old_thread_id);
+ ++exited_threads;
+ }
+ }
+
+ // Also add all the threads that are new since the last time we broke into the debugger.
+ for (const auto &thread_info : m_session_data->m_new_threads)
+ {
+ ThreadSP thread(new TargetThreadWindowsLive(*this, thread_info.second));
+ thread->SetID(thread_info.first);
+ new_thread_list.AddThread(thread);
+ ++new_size;
+ ++new_threads;
+ WINLOGV_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - Thread %u is new since last update.", thread_info.first);
+ }
+
+ WINLOG_IFALL(WINDOWS_LOG_THREAD, "UpdateThreadList - %d new threads, %d old threads, %d exited threads.",
+ new_threads, continued_threads, exited_threads);
+
+ m_session_data->m_new_threads.clear();
+ m_session_data->m_exited_threads.clear();
+
+ return new_size > 0;
+}
+
+Error
+ProcessWindowsLive::DoLaunch(Module *exe_module,
+ ProcessLaunchInfo &launch_info)
+{
+ // Even though m_session_data is accessed here, it is before a debugger thread has been
+ // kicked off. So there's no race conditions, and it shouldn't be necessary to acquire
+ // the mutex.
+
+ Error result;
+ if (!launch_info.GetFlags().Test(eLaunchFlagDebug))
+ {
+ StreamString stream;
+ stream.Printf("ProcessWindows unable to launch '%s'. ProcessWindows can only be used for debug launches.",
+ launch_info.GetExecutableFile().GetPath().c_str());
+ std::string message = stream.GetString();
+ result.SetErrorString(message.c_str());
+
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, message.c_str());
+ return result;
+ }
+
+ bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);
+ m_session_data.reset(new ProcessWindowsData(stop_at_entry));
+
+ SetPrivateState(eStateLaunching);
+ DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
+ m_session_data->m_debugger.reset(new DebuggerThread(delegate));
+ DebuggerThreadSP debugger = m_session_data->m_debugger;
+
+ // Kick off the DebugLaunch asynchronously and wait for it to complete.
+ result = debugger->DebugLaunch(launch_info);
+ if (result.Fail())
+ {
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s",
+ launch_info.GetExecutableFile().GetPath().c_str(), result.AsCString());
+ return result;
+ }
+
+ HostProcess process;
+ Error error = WaitForDebuggerConnection(debugger, process);
+ if (error.Fail())
+ {
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s",
+ launch_info.GetExecutableFile().GetPath().c_str(), error.AsCString());
+ return error;
+ }
+
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch successfully launched '%s'",
+ launch_info.GetExecutableFile().GetPath().c_str());
+
+ // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the private state
+ // should already be set to eStateStopped as a result of hitting the initial breakpoint. If
+ // it was not set, the breakpoint should have already been resumed from and the private state
+ // should already be eStateRunning.
+ launch_info.SetProcessID(process.GetProcessId());
+ SetID(process.GetProcessId());
+
+ return result;
+}
+
+Error
+ProcessWindowsLive::DoAttachToProcessWithID(lldb::pid_t pid, const ProcessAttachInfo &attach_info)
+{
+ m_session_data.reset(new ProcessWindowsData(!attach_info.GetContinueOnceAttached()));
+
+ DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
+ DebuggerThreadSP debugger(new DebuggerThread(delegate));
+
+ m_session_data->m_debugger = debugger;
+
+ DWORD process_id = static_cast<DWORD>(pid);
+ Error error = debugger->DebugAttach(process_id, attach_info);
+ if (error.Fail())
+ {
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS,
+ "DoAttachToProcessWithID encountered an error occurred initiating the asynchronous attach. %s",
+ error.AsCString());
+ return error;
+ }
+
+ HostProcess process;
+ error = WaitForDebuggerConnection(debugger, process);
+ if (error.Fail())
+ {
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS,
+ "DoAttachToProcessWithID encountered an error waiting for the debugger to connect. %s",
+ error.AsCString());
+ return error;
+ }
+
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID successfully attached to process with pid=%u",
+ process_id);
+
+ // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the private state
+ // should already be set to eStateStopped as a result of hitting the initial breakpoint. If
+ // it was not set, the breakpoint should have already been resumed from and the private state
+ // should already be eStateRunning.
+ SetID(process.GetProcessId());
+ return error;
+}
+
+Error
+ProcessWindowsLive::WaitForDebuggerConnection(DebuggerThreadSP debugger, HostProcess &process)
+{
+ Error result;
+ WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_BREAKPOINTS, "WaitForDebuggerConnection Waiting for loader breakpoint.");
+
+ // Block this function until we receive the initial stop from the process.
+ if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == WAIT_OBJECT_0)
+ {
+ WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_BREAKPOINTS, "WaitForDebuggerConnection hit loader breakpoint, returning.");
+
+ process = debugger->GetProcess();
+ return m_session_data->m_launch_error;
+ }
+ else
+ return Error(::GetLastError(), eErrorTypeWin32);
+}
+
+Error
+ProcessWindowsLive::DoResume()
+{
+ llvm::sys::ScopedLock lock(m_mutex);
+ Error error;
+
+ StateType private_state = GetPrivateState();
+ if (private_state == eStateStopped || private_state == eStateCrashed)
+ {
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoResume called for process %I64u while state is %u. Resuming...",
+ m_session_data->m_debugger->GetProcess().GetProcessId(), GetPrivateState());
+
+ ExceptionRecordSP active_exception =
+ m_session_data->m_debugger->GetActiveException().lock();
+ if (active_exception)
+ {
+ // Resume the process and continue processing debug events. Mask
+ // the exception so that from the process's view, there is no
+ // indication that anything happened.
+ m_session_data->m_debugger->ContinueAsyncException(
+ ExceptionResult::MaskException);
+ }
+
+ WINLOG_IFANY(WINDOWS_LOG_PROCESS | WINDOWS_LOG_THREAD, "DoResume resuming %u threads.",
+ m_thread_list.GetSize());
+
+ for (int i = 0; i < m_thread_list.GetSize(); ++i)
+ {
+ auto thread = std::static_pointer_cast<TargetThreadWindowsLive>(
+ m_thread_list.GetThreadAtIndex(i));
+ thread->DoResume();
+ }
+
+ SetPrivateState(eStateRunning);
+ }
+ else
+ {
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoResume called for process %I64u but state is %u. Returning...",
+ m_session_data->m_debugger->GetProcess().GetProcessId(), GetPrivateState());
+ }
+ return error;
+}
+
+
+//------------------------------------------------------------------------------
+// ProcessInterface protocol.
+
+lldb_private::ConstString
+ProcessWindowsLive::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessWindowsLive::GetPluginVersion()
+{
+ return 1;
+}
+
+Error
+ProcessWindowsLive::DoDetach(bool keep_stopped)
+{
+ DebuggerThreadSP debugger_thread;
+ StateType private_state;
+ {
+ // Acquire the lock only long enough to get the DebuggerThread.
+ // StopDebugging() will trigger a call back into ProcessWindows which
+ // will also acquire the lock. Thus we have to release the lock before
+ // calling StopDebugging().
+ llvm::sys::ScopedLock lock(m_mutex);
+
+ private_state = GetPrivateState();
+
+ if (!m_session_data)
+ {
+ WINWARN_IFALL(WINDOWS_LOG_PROCESS, "DoDetach called while state = %u, but there is no active session.",
+ private_state);
+ return Error();
+ }
+
+ debugger_thread = m_session_data->m_debugger;
+ }
+
+ Error error;
+ if (private_state != eStateExited && private_state != eStateDetached)
+ {
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoDetach called for process %I64u while state = %u. Detaching...",
+ debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state);
+ error = debugger_thread->StopDebugging(false);
+ if (error.Success())
+ {
+ SetPrivateState(eStateDetached);
+ }
+
+ // By the time StopDebugging returns, there is no more debugger thread, so
+ // we can be assured that no other thread will race for the session data.
+ m_session_data.reset();
+ }
+ else
+ {
+ WINERR_IFALL(WINDOWS_LOG_PROCESS,
+ "DoDetach called for process %I64u while state = %u, but cannot destroy in this state.",
+ debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state);
+ }
+
+ return error;
+}
+
+Error
+ProcessWindowsLive::DoDestroy()
+{
+ DebuggerThreadSP debugger_thread;
+ StateType private_state;
+ {
+ // Acquire this lock inside an inner scope, only long enough to get the DebuggerThread.
+ // StopDebugging() will trigger a call back into ProcessWindows which will acquire the lock
+ // again, so we need to not deadlock.
+ llvm::sys::ScopedLock lock(m_mutex);
+
+ private_state = GetPrivateState();
+
+ if (!m_session_data)
+ {
+ WINWARN_IFALL(WINDOWS_LOG_PROCESS, "DoDestroy called while state = %u, but there is no active session.",
+ private_state);
+ return Error();
+ }
+
+ debugger_thread = m_session_data->m_debugger;
+ }
+
+ Error error;
+ if (private_state != eStateExited && private_state != eStateDetached)
+ {
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoDestroy called for process %I64u while state = %u. Shutting down...",
+ debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state);
+ error = debugger_thread->StopDebugging(true);
+
+ // By the time StopDebugging returns, there is no more debugger thread, so
+ // we can be assured that no other thread will race for the session data.
+ m_session_data.reset();
+ }
+ else
+ {
+ WINERR_IFALL(WINDOWS_LOG_PROCESS,
+ "DoDestroy called for process %I64u while state = %u, but cannot destroy in this state.",
+ debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state);
+ }
+
+ return error;
+}
+
+void
+ProcessWindowsLive::RefreshStateAfterStop()
+{
+ llvm::sys::ScopedLock lock(m_mutex);
+
+ if (!m_session_data)
+ {
+ WINWARN_IFALL(WINDOWS_LOG_PROCESS, "RefreshStateAfterStop called with no active session. Returning...");
+ return;
+ }
+
+ m_thread_list.RefreshStateAfterStop();
+
+ std::weak_ptr<ExceptionRecord> exception_record = m_session_data->m_debugger->GetActiveException();
+ ExceptionRecordSP active_exception = exception_record.lock();
+ if (!active_exception)
+ {
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, "RefreshStateAfterStop called for process %I64u but there is no "
+ "active exception. Why is the process stopped?",
+ m_session_data->m_debugger->GetProcess().GetProcessId());
+ return;
+ }
+
+ StopInfoSP stop_info;
+ m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID());
+ ThreadSP stop_thread = m_thread_list.GetSelectedThread();
+ if (!stop_thread)
+ return;
+
+ RegisterContextSP register_context = stop_thread->GetRegisterContext();
+
+ // The current EIP is AFTER the BP opcode, which is one byte.
+ uint64_t pc = register_context->GetPC() - 1;
+ if (active_exception->GetExceptionCode() == EXCEPTION_BREAKPOINT)
+ {
+ BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
+
+ if (site)
+ {
+ WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
+ "RefreshStateAfterStop detected breakpoint in process %I64u at "
+ "address 0x%I64x with breakpoint site %d",
+ m_session_data->m_debugger->GetProcess().GetProcessId(), pc, site->GetID());
+
+ if (site->ValidForThisThread(stop_thread.get()))
+ {
+ WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
+ "Breakpoint site %d is valid for this thread (0x%I64x), creating stop info.",
+ site->GetID(), stop_thread->GetID());
+
+ stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(
+ *stop_thread, site->GetID());
+ register_context->SetPC(pc);
+ }
+ else
+ {
+ WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
+ "Breakpoint site %d is not valid for this thread, creating empty stop info.",
+ site->GetID());
+ }
+ }
+ stop_thread->SetStopInfo(stop_info);
+ }
+ else if (active_exception->GetExceptionCode() == EXCEPTION_SINGLE_STEP)
+ {
+ stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
+ stop_thread->SetStopInfo(stop_info);
+ WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, "RefreshStateAfterStop single stepping thread %u",
+ stop_thread->GetID());
+ }
+ else
+ {
+ std::string desc;
+ llvm::raw_string_ostream desc_stream(desc);
+ desc_stream << "Exception " << llvm::format_hex(active_exception->GetExceptionCode(), 8)
+ << " encountered at address " << llvm::format_hex(pc, 8);
+ stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str());
+ stop_thread->SetStopInfo(stop_info);
+ WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, desc_stream.str().c_str());
+ }
+}
+
+bool
+ProcessWindowsLive::IsAlive()
+{
+ StateType state = GetPrivateState();
+ switch (state)
+ {
+ case eStateCrashed:
+ case eStateDetached:
+ case eStateUnloaded:
+ case eStateExited:
+ case eStateInvalid:
+ return false;
+ default:
+ return true;
+ }
+}
+
+Error
+ProcessWindowsLive::DoHalt(bool &caused_stop)
+{
+ Error error;
+ StateType state = GetPrivateState();
+ if (state == eStateStopped)
+ caused_stop = false;
+ else
+ {
+ llvm::sys::ScopedLock lock(m_mutex);
+ caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess().GetNativeProcess().GetSystemHandle());
+ if (!caused_stop)
+ {
+ error.SetError(::GetLastError(), eErrorTypeWin32);
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoHalt called DebugBreakProcess, but it failed with error %u",
+ error.GetError());
+ }
+ }
+ return error;
+}
+
+void
+ProcessWindowsLive::DidLaunch()
+{
+ ArchSpec arch_spec;
+ DidAttach(arch_spec);
+}
+
+void
+ProcessWindowsLive::DidAttach(ArchSpec &arch_spec)
+{
+ llvm::sys::ScopedLock lock(m_mutex);
+
+ // The initial stop won't broadcast the state change event, so account for that here.
+ if (m_session_data && GetPrivateState() == eStateStopped && m_session_data->m_stop_at_entry)
+ RefreshStateAfterStop();
+}
+
+size_t
+ProcessWindowsLive::DoReadMemory(lldb::addr_t vm_addr,
+ void *buf,
+ size_t size,
+ Error &error)
+{
+ llvm::sys::ScopedLock lock(m_mutex);
+
+ if (!m_session_data)
+ return 0;
+
+ WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory attempting to read %u bytes from address 0x%I64x", size, vm_addr);
+
+ HostProcess process = m_session_data->m_debugger->GetProcess();
+ void *addr = reinterpret_cast<void *>(vm_addr);
+ SIZE_T bytes_read = 0;
+ if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, buf, size, &bytes_read))
+ {
+ error.SetError(GetLastError(), eErrorTypeWin32);
+ WINERR_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory failed with error code %u", error.GetError());
+ }
+ return bytes_read;
+}
+
+size_t
+ProcessWindowsLive::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Error &error)
+{
+ llvm::sys::ScopedLock lock(m_mutex);
+ WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory attempting to write %u bytes into address 0x%I64x", size, vm_addr);
+
+ if (!m_session_data)
+ {
+ WINERR_IFANY(WINDOWS_LOG_MEMORY, "DoWriteMemory cannot write, there is no active debugger connection.");
+ return 0;
+ }
+
+ HostProcess process = m_session_data->m_debugger->GetProcess();
+ void *addr = reinterpret_cast<void *>(vm_addr);
+ SIZE_T bytes_written = 0;
+ lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
+ if (WriteProcessMemory(handle, addr, buf, size, &bytes_written))
+ FlushInstructionCache(handle, addr, bytes_written);
+ else
+ {
+ error.SetError(GetLastError(), eErrorTypeWin32);
+ WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory failed with error code %u", error.GetError());
+ }
+ return bytes_written;
+}
+
+Error
+ProcessWindowsLive::GetMemoryRegionInfo(lldb::addr_t vm_addr, MemoryRegionInfo &info)
+{
+ Error error;
+ llvm::sys::ScopedLock lock(m_mutex);
+
+ if (!m_session_data)
+ {
+ error.SetErrorString("GetMemoryRegionInfo called with no debugging session.");
+ WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString());
+ return error;
+ }
+
+ HostProcess process = m_session_data->m_debugger->GetProcess();
+ lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
+ if (handle == nullptr || handle == LLDB_INVALID_PROCESS)
+ {
+ error.SetErrorString("GetMemoryRegionInfo called with an invalid target process.");
+ WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString());
+ return error;
+ }
+
+ WINLOG_IFALL(WINDOWS_LOG_MEMORY, "GetMemoryRegionInfo getting info for address 0x%I64x", vm_addr);
+
+ void *addr = reinterpret_cast<void *>(vm_addr);
+ MEMORY_BASIC_INFORMATION mem_info = {0};
+ SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info));
+ if (result == 0)
+ {
+ error.SetError(::GetLastError(), eErrorTypeWin32);
+ WINERR_IFALL(WINDOWS_LOG_MEMORY,
+ "VirtualQueryEx returned error %u while getting memory region info for address 0x%I64x",
+ error.GetError(), vm_addr);
+ return error;
+ }
+ const bool readable = IsPageReadable(mem_info.Protect);
+ const bool executable = IsPageExecutable(mem_info.Protect);
+ const bool writable = IsPageWritable(mem_info.Protect);
+ info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+ info.SetExecutable(executable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+ info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+
+ error.SetError(::GetLastError(), eErrorTypeWin32);
+ WINLOGV_IFALL(WINDOWS_LOG_MEMORY, "Memory region info for address 0x%I64u: readable=%s, executable=%s, writable=%s",
+ BOOL_STR(readable), BOOL_STR(executable), BOOL_STR(writable));
+ return error;
+}
+
+bool
+ProcessWindowsLive::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name)
+{
+ if (plugin_specified_by_name)
+ return true;
+
+ // For now we are just making sure the file exists for a given module
+ ModuleSP exe_module_sp(target_sp->GetExecutableModule());
+ if (exe_module_sp.get())
+ return exe_module_sp->GetFileSpec().Exists();
+ // However, if there is no executable module, we return true since we might be preparing to attach.
+ return true;
+}
+
+void
+ProcessWindowsLive::OnExitProcess(uint32_t exit_code)
+{
+ // No need to acquire the lock since m_session_data isn't accessed.
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "Process %u exited with code %u", GetID(), exit_code);
+
+ TargetSP target = m_target_sp.lock();
+ if (target)
+ {
+ ModuleSP executable_module = target->GetExecutableModule();
+ ModuleList unloaded_modules;
+ unloaded_modules.Append(executable_module);
+ target->ModulesDidUnload(unloaded_modules, true);
+ }
+
+ SetProcessExitStatus(nullptr, GetID(), true, 0, exit_code);
+ SetPrivateState(eStateExited);
+}
+
+void
+ProcessWindowsLive::OnDebuggerConnected(lldb::addr_t image_base)
+{
+ DebuggerThreadSP debugger = m_session_data->m_debugger;
+
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "Debugger connected to process %I64u. Image base = 0x%I64x",
+ debugger->GetProcess().GetProcessId(), image_base);
+
+ ModuleSP module = GetTarget().GetExecutableModule();
+ if (!module)
+ {
+ // During attach, we won't have the executable module, so find it now.
+ const DWORD pid = debugger->GetProcess().GetProcessId();
+ const std::string file_name = GetProcessExecutableName(pid);
+ if (file_name.empty())
+ {
+ return;
+ }
+
+ FileSpec executable_file(file_name, true);
+ ModuleSpec module_spec(executable_file);
+ Error error;
+ module = GetTarget().GetSharedModule(module_spec, &error);
+ if (!module)
+ {
+ return;
+ }
+
+ GetTarget().SetExecutableModule(module, false);
+ }
+
+ bool load_addr_changed;
+ module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed);
+
+ ModuleList loaded_modules;
+ loaded_modules.Append(module);
+ GetTarget().ModulesDidLoad(loaded_modules);
+
+ // Add the main executable module to the list of pending module loads. We can't call
+ // GetTarget().ModulesDidLoad() here because we still haven't returned from DoLaunch() / DoAttach() yet
+ // so the target may not have set the process instance to `this` yet.
+ llvm::sys::ScopedLock lock(m_mutex);
+ const HostThreadWindows &wmain_thread = debugger->GetMainThread().GetNativeThread();
+ m_session_data->m_new_threads[wmain_thread.GetThreadId()] = debugger->GetMainThread();
+}
+
+ExceptionResult
+ProcessWindowsLive::OnDebugException(bool first_chance, const ExceptionRecord &record)
+{
+ llvm::sys::ScopedLock lock(m_mutex);
+
+ // FIXME: Without this check, occasionally when running the test suite there is
+ // an issue where m_session_data can be null. It's not clear how this could happen
+ // but it only surfaces while running the test suite. In order to properly diagnose
+ // this, we probably need to first figure allow the test suite to print out full
+ // lldb logs, and then add logging to the process plugin.
+ if (!m_session_data)
+ {
+ WINERR_IFANY(WINDOWS_LOG_EXCEPTION,
+ "Debugger thread reported exception 0x%x at address 0x%I64x, but there is no session.",
+ record.GetExceptionCode(), record.GetExceptionAddress());
+ return ExceptionResult::SendToApplication;
+ }
+
+ if (!first_chance)
+ {
+ // Any second chance exception is an application crash by definition.
+ SetPrivateState(eStateCrashed);
+ }
+
+ ExceptionResult result = ExceptionResult::SendToApplication;
+ switch (record.GetExceptionCode())
+ {
+ case EXCEPTION_BREAKPOINT:
+ // Handle breakpoints at the first chance.
+ result = ExceptionResult::BreakInDebugger;
+
+ if (!m_session_data->m_initial_stop_received)
+ {
+ WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS,
+ "Hit loader breakpoint at address 0x%I64x, setting initial stop event.",
+ record.GetExceptionAddress());
+ m_session_data->m_initial_stop_received = true;
+ ::SetEvent(m_session_data->m_initial_stop_event);
+ }
+ else
+ {
+ WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS,
+ "Hit non-loader breakpoint at address 0x%I64x.",
+ record.GetExceptionAddress());
+ }
+ SetPrivateState(eStateStopped);
+ break;
+ case EXCEPTION_SINGLE_STEP:
+ result = ExceptionResult::BreakInDebugger;
+ SetPrivateState(eStateStopped);
+ break;
+ default:
+ WINLOG_IFANY(WINDOWS_LOG_EXCEPTION,
+ "Debugger thread reported exception 0x%x at address 0x%I64x (first_chance=%s)",
+ record.GetExceptionCode(), record.GetExceptionAddress(), BOOL_STR(first_chance));
+ // For non-breakpoints, give the application a chance to handle the exception first.
+ if (first_chance)
+ result = ExceptionResult::SendToApplication;
+ else
+ result = ExceptionResult::BreakInDebugger;
+ }
+
+ return result;
+}
+
+void
+ProcessWindowsLive::OnCreateThread(const HostThread &new_thread)
+{
+ llvm::sys::ScopedLock lock(m_mutex);
+ const HostThreadWindows &wnew_thread = new_thread.GetNativeThread();
+ m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread;
+}
+
+void
+ProcessWindowsLive::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code)
+{
+ llvm::sys::ScopedLock lock(m_mutex);
+
+ // On a forced termination, we may get exit thread events after the session
+ // data has been cleaned up.
+ if (!m_session_data)
+ return;
+
+ // A thread may have started and exited before the debugger stopped allowing a refresh.
+ // Just remove it from the new threads list in that case.
+ auto iter = m_session_data->m_new_threads.find(thread_id);
+ if (iter != m_session_data->m_new_threads.end())
+ m_session_data->m_new_threads.erase(iter);
+ else
+ m_session_data->m_exited_threads.insert(thread_id);
+}
+
+void
+ProcessWindowsLive::OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr)
+{
+ // Confusingly, there is no Target::AddSharedModule. Instead, calling GetSharedModule() with
+ // a new module will add it to the module list and return a corresponding ModuleSP.
+ Error error;
+ ModuleSP module = GetTarget().GetSharedModule(module_spec, &error);
+ bool load_addr_changed = false;
+ module->SetLoadAddress(GetTarget(), module_addr, false, load_addr_changed);
+
+ ModuleList loaded_modules;
+ loaded_modules.Append(module);
+ GetTarget().ModulesDidLoad(loaded_modules);
+}
+
+void
+ProcessWindowsLive::OnUnloadDll(lldb::addr_t module_addr)
+{
+ Address resolved_addr;
+ if (GetTarget().ResolveLoadAddress(module_addr, resolved_addr))
+ {
+ ModuleSP module = resolved_addr.GetModule();
+ if (module)
+ {
+ ModuleList unloaded_modules;
+ unloaded_modules.Append(module);
+ GetTarget().ModulesDidUnload(unloaded_modules, false);
+ }
+ }
+}
+
+void
+ProcessWindowsLive::OnDebugString(const std::string &string)
+{
+}
+
+void
+ProcessWindowsLive::OnDebuggerError(const Error &error, uint32_t type)
+{
+ llvm::sys::ScopedLock lock(m_mutex);
+
+ if (m_session_data->m_initial_stop_received)
+ {
+ // This happened while debugging. Do we shutdown the debugging session, try to continue,
+ // or do something else?
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, "Error %u occurred during debugging. Unexpected behavior may result. %s",
+ error.GetError(), error.AsCString());
+ }
+ else
+ {
+ // If we haven't actually launched the process yet, this was an error launching the
+ // process. Set the internal error and signal the initial stop event so that the DoLaunch
+ // method wakes up and returns a failure.
+ m_session_data->m_launch_error = error;
+ ::SetEvent(m_session_data->m_initial_stop_event);
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, "Error %u occurred launching the process before the initial stop. %s",
+ error.GetError(), error.AsCString());
+ return;
+ }
+}
diff --git a/source/Plugins/Process/Windows/Live/ProcessWindowsLive.h b/source/Plugins/Process/Windows/Live/ProcessWindowsLive.h
new file mode 100644
index 000000000000..2429f873c823
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/ProcessWindowsLive.h
@@ -0,0 +1,125 @@
+//===-- ProcessWindowsLive.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_Plugins_Process_Windows_Live_ProcessWindowsLive_H_
+#define liblldb_Plugins_Process_Windows_Live_ProcessWindowsLive_H_
+
+// C Includes
+
+// C++ Includes
+#include <memory>
+#include <queue>
+
+// Other libraries and framework includes
+#include "ForwardDecl.h"
+#include "IDebugDelegate.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Target/Process.h"
+
+#include "llvm/Support/Mutex.h"
+
+#include "plugins/Process/Windows/Common/ProcessWindows.h"
+
+class ProcessMonitor;
+
+namespace lldb_private
+{
+class HostProcess;
+class ProcessWindowsData;
+
+class ProcessWindowsLive : public lldb_private::ProcessWindows, public lldb_private::IDebugDelegate
+{
+public:
+ //------------------------------------------------------------------
+ // Static functions.
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance(lldb::TargetSP target_sp,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessWindowsLive(lldb::TargetSP target_sp,
+ lldb_private::Listener &listener);
+
+ ~ProcessWindowsLive();
+
+ // lldb_private::Process overrides
+ lldb_private::ConstString GetPluginName() override;
+ uint32_t GetPluginVersion() override;
+
+ lldb_private::Error EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
+ lldb_private::Error DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
+
+ lldb_private::Error DoDetach(bool keep_stopped) override;
+ lldb_private::Error DoLaunch(lldb_private::Module *exe_module, lldb_private::ProcessLaunchInfo &launch_info) override;
+ lldb_private::Error DoAttachToProcessWithID(lldb::pid_t pid,
+ const lldb_private::ProcessAttachInfo &attach_info) override;
+ lldb_private::Error DoResume() override;
+ lldb_private::Error DoDestroy() override;
+ lldb_private::Error DoHalt(bool &caused_stop) override;
+
+ void DidLaunch() override;
+ void DidAttach(lldb_private::ArchSpec &arch_spec) override;
+
+ void RefreshStateAfterStop() override;
+
+ bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override;
+ bool
+ DestroyRequiresHalt() override
+ {
+ return false;
+ }
+ bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list) override;
+ bool IsAlive() override;
+
+ size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, lldb_private::Error &error) override;
+ size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, lldb_private::Error &error) override;
+ lldb_private::Error GetMemoryRegionInfo(lldb::addr_t vm_addr, lldb_private::MemoryRegionInfo &info) override;
+
+ // IDebugDelegate overrides.
+ void OnExitProcess(uint32_t exit_code) override;
+ void OnDebuggerConnected(lldb::addr_t image_base) override;
+ ExceptionResult OnDebugException(bool first_chance, const lldb_private::ExceptionRecord &record) override;
+ void OnCreateThread(const lldb_private::HostThread &thread) override;
+ void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override;
+ void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override;
+ void OnUnloadDll(lldb::addr_t module_addr) override;
+ void OnDebugString(const std::string &string) override;
+ void OnDebuggerError(const lldb_private::Error &error, uint32_t type) override;
+
+ private:
+ lldb_private::Error WaitForDebuggerConnection(lldb_private::DebuggerThreadSP debugger,
+ lldb_private::HostProcess &process);
+
+ llvm::sys::Mutex m_mutex;
+
+ // Data for the active debugging session.
+ std::unique_ptr<lldb_private::ProcessWindowsData> m_session_data;
+};
+
+}
+
+#endif // liblldb_Plugins_Process_Windows_Live_ProcessWindowsLive_H_
diff --git a/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.cpp b/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.cpp
new file mode 100644
index 000000000000..52b32716e674
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.cpp
@@ -0,0 +1,147 @@
+//===-- TargetThreadWindowsLive.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/Core/Log.h"
+#include "lldb/Core/Logging.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/HostNativeThreadBase.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+#include "lldb/Host/windows/windows.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "TargetThreadWindowsLive.h"
+#include "ProcessWindows.h"
+#include "ProcessWindowsLog.h"
+#include "UnwindLLDB.h"
+
+#if defined(_WIN64)
+#include "x64/RegisterContextWindowsLive_x64.h"
+#else
+#include "x86/RegisterContextWindowsLive_x86.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+TargetThreadWindowsLive::TargetThreadWindowsLive(ProcessWindows &process, const HostThread &thread)
+ : TargetThreadWindows(process, thread)
+ , m_host_thread(thread)
+{
+}
+
+TargetThreadWindowsLive::~TargetThreadWindowsLive()
+{
+ DestroyThread();
+}
+
+void
+TargetThreadWindowsLive::RefreshStateAfterStop()
+{
+ ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
+ SetState(eStateStopped);
+ GetRegisterContext()->InvalidateIfNeeded(false);
+}
+
+void
+TargetThreadWindowsLive::WillResume(lldb::StateType resume_state)
+{
+}
+
+void
+TargetThreadWindowsLive::DidStop()
+{
+}
+
+RegisterContextSP
+TargetThreadWindowsLive::GetRegisterContext()
+{
+ if (!m_reg_context_sp)
+ m_reg_context_sp = CreateRegisterContextForFrameIndex(0);
+
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+TargetThreadWindowsLive::CreateRegisterContextForFrame(StackFrame *frame)
+{
+ return CreateRegisterContextForFrameIndex(frame->GetConcreteFrameIndex());
+}
+
+RegisterContextSP
+TargetThreadWindowsLive::CreateRegisterContextForFrameIndex(uint32_t idx)
+{
+ if (!m_reg_context_sp)
+ {
+ ArchSpec arch = HostInfo::GetArchitecture();
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+#if defined(_WIN64)
+ // FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64
+#else
+ m_reg_context_sp.reset(new RegisterContextWindowsLive_x86(*this, idx));
+#endif
+ break;
+ case llvm::Triple::x86_64:
+#if defined(_WIN64)
+ m_reg_context_sp.reset(new RegisterContextWindowsLive_x64(*this, idx));
+#else
+ // LLDB is 32-bit, but the target process is 64-bit. We probably can't debug this.
+#endif
+ default:
+ break;
+ }
+ }
+ return m_reg_context_sp;
+}
+
+bool
+TargetThreadWindowsLive::CalculateStopInfo()
+{
+ SetStopInfo(m_stop_info_sp);
+ return true;
+}
+
+Unwind *
+TargetThreadWindowsLive::GetUnwinder()
+{
+ // FIXME: Implement an unwinder based on the Windows unwinder exposed through DIA SDK.
+ if (m_unwinder_ap.get() == NULL)
+ m_unwinder_ap.reset(new UnwindLLDB(*this));
+ return m_unwinder_ap.get();
+}
+
+bool
+TargetThreadWindowsLive::DoResume()
+{
+ StateType resume_state = GetTemporaryResumeState();
+ StateType current_state = GetState();
+ if (resume_state == current_state)
+ return true;
+
+ if (resume_state == eStateStepping)
+ {
+ uint32_t flags_index = GetRegisterContext()->ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+ uint64_t flags_value = GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0);
+ flags_value |= 0x100; // Set the trap flag on the CPU
+ GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
+ }
+
+ if (resume_state == eStateStepping || resume_state == eStateRunning)
+ {
+ DWORD previous_suspend_count = 0;
+ HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
+ do
+ {
+ previous_suspend_count = ::ResumeThread(thread_handle);
+ } while (previous_suspend_count > 0);
+ }
+ return true;
+}
diff --git a/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.h b/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.h
new file mode 100644
index 000000000000..15262b9e9423
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/TargetThreadWindowsLive.h
@@ -0,0 +1,55 @@
+//===-- TargetThreadWindowsLive.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_Plugins_Process_Windows_TargetThreadWindowsLive_H_
+#define liblldb_Plugins_Process_Windows_TargetThreadWindowsLive_H_
+
+#include "lldb/lldb-forward.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Target/Thread.h"
+
+#include "Plugins/Process/Windows/Common/TargetThreadWindows.h"
+
+namespace lldb_private
+{
+class ProcessWindows;
+class HostThread;
+class StackFrame;
+
+class TargetThreadWindowsLive : public lldb_private::TargetThreadWindows
+{
+ public:
+ TargetThreadWindowsLive(ProcessWindows &process, const HostThread &thread);
+ virtual ~TargetThreadWindowsLive();
+
+ // lldb_private::Thread overrides
+ void RefreshStateAfterStop() override;
+ void WillResume(lldb::StateType resume_state) override;
+ void DidStop() override;
+ lldb::RegisterContextSP GetRegisterContext() override;
+ lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame) override;
+ bool CalculateStopInfo() override;
+ Unwind *GetUnwinder() override;
+
+ bool DoResume();
+
+ HostThread
+ GetHostThread() const
+ {
+ return m_host_thread;
+ }
+
+ private:
+ lldb::RegisterContextSP CreateRegisterContextForFrameIndex(uint32_t idx);
+
+ HostThread m_host_thread;
+};
+}
+
+#endif
diff --git a/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.cpp b/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.cpp
new file mode 100644
index 000000000000..e74647ab68fb
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.cpp
@@ -0,0 +1,171 @@
+//===-- RegisterContextWindowsLive_x64.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/lldb-private-types.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+#include "lldb/Host/windows/windows.h"
+
+#include "lldb-x86-register-enums.h"
+#include "RegisterContextWindowsLive_x64.h"
+#include "TargetThreadWindows.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextWindowsLive_x64::RegisterContextWindowsLive_x64(Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContextWindows_x64(thread, concrete_frame_idx)
+{
+}
+
+RegisterContextWindowsLive_x64::~RegisterContextWindowsLive_x64()
+{
+}
+
+
+bool
+RegisterContextWindowsLive_x64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ if (!CacheAllRegisterValues())
+ return false;
+
+ switch (reg_info->kinds[eRegisterKindLLDB])
+ {
+ case lldb_rax_x86_64:
+ reg_value.SetUInt64(m_context.Rax);
+ break;
+ case lldb_rbx_x86_64:
+ reg_value.SetUInt64(m_context.Rbx);
+ break;
+ case lldb_rcx_x86_64:
+ reg_value.SetUInt64(m_context.Rcx);
+ break;
+ case lldb_rdx_x86_64:
+ reg_value.SetUInt64(m_context.Rdx);
+ break;
+ case lldb_rdi_x86_64:
+ reg_value.SetUInt64(m_context.Rdi);
+ break;
+ case lldb_rsi_x86_64:
+ reg_value.SetUInt64(m_context.Rsi);
+ break;
+ case lldb_r8_x86_64:
+ reg_value.SetUInt64(m_context.R8);
+ break;
+ case lldb_r9_x86_64:
+ reg_value.SetUInt64(m_context.R9);
+ break;
+ case lldb_r10_x86_64:
+ reg_value.SetUInt64(m_context.R10);
+ break;
+ case lldb_r11_x86_64:
+ reg_value.SetUInt64(m_context.R11);
+ break;
+ case lldb_r12_x86_64:
+ reg_value.SetUInt64(m_context.R12);
+ break;
+ case lldb_r13_x86_64:
+ reg_value.SetUInt64(m_context.R13);
+ break;
+ case lldb_r14_x86_64:
+ reg_value.SetUInt64(m_context.R14);
+ break;
+ case lldb_r15_x86_64:
+ reg_value.SetUInt64(m_context.R15);
+ break;
+ case lldb_rbp_x86_64:
+ reg_value.SetUInt64(m_context.Rbp);
+ break;
+ case lldb_rsp_x86_64:
+ reg_value.SetUInt64(m_context.Rsp);
+ break;
+ case lldb_rip_x86_64:
+ reg_value.SetUInt64(m_context.Rip);
+ break;
+ case lldb_rflags_x86_64:
+ reg_value.SetUInt64(m_context.EFlags);
+ break;
+ }
+ return true;
+}
+
+bool
+RegisterContextWindowsLive_x64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ // Since we cannot only write a single register value to the inferior, we need to make sure
+ // our cached copy of the register values are fresh. Otherwise when writing EAX, for example,
+ // we may also overwrite some other register with a stale value.
+ if (!CacheAllRegisterValues())
+ return false;
+
+ switch (reg_info->kinds[eRegisterKindLLDB])
+ {
+ case lldb_rax_x86_64:
+ m_context.Rax = reg_value.GetAsUInt64();
+ break;
+ case lldb_rbx_x86_64:
+ m_context.Rbx = reg_value.GetAsUInt64();
+ break;
+ case lldb_rcx_x86_64:
+ m_context.Rcx = reg_value.GetAsUInt64();
+ break;
+ case lldb_rdx_x86_64:
+ m_context.Rdx = reg_value.GetAsUInt64();
+ break;
+ case lldb_rdi_x86_64:
+ m_context.Rdi = reg_value.GetAsUInt64();
+ break;
+ case lldb_rsi_x86_64:
+ m_context.Rsi = reg_value.GetAsUInt64();
+ break;
+ case lldb_r8_x86_64:
+ m_context.R8 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r9_x86_64:
+ m_context.R9 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r10_x86_64:
+ m_context.R10 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r11_x86_64:
+ m_context.R11 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r12_x86_64:
+ m_context.R12 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r13_x86_64:
+ m_context.R13 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r14_x86_64:
+ m_context.R14 = reg_value.GetAsUInt64();
+ break;
+ case lldb_r15_x86_64:
+ m_context.R15 = reg_value.GetAsUInt64();
+ break;
+ case lldb_rbp_x86_64:
+ m_context.Rbp = reg_value.GetAsUInt64();
+ break;
+ case lldb_rsp_x86_64:
+ m_context.Rsp = reg_value.GetAsUInt64();
+ break;
+ case lldb_rip_x86_64:
+ m_context.Rip = reg_value.GetAsUInt64();
+ break;
+ case lldb_rflags_x86_64:
+ m_context.EFlags = reg_value.GetAsUInt64();
+ break;
+ }
+
+ // Physically update the registers in the target process.
+ TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
+ return ::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context);
+}
diff --git a/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.h b/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.h
new file mode 100644
index 000000000000..bd250a994d3a
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/x64/RegisterContextWindowsLive_x64.h
@@ -0,0 +1,40 @@
+//===-- RegisterContextWindowsLive_x64.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_RegisterContextWindowsLive_x64_H_
+#define liblldb_RegisterContextWindowsLive_x64_H_
+
+#include "lldb/lldb-forward.h"
+#include "../../Common/x64/RegisterContextWindows_x64.h"
+
+namespace lldb_private
+{
+
+class Thread;
+
+class RegisterContextWindowsLive_x64 : public RegisterContextWindows_x64
+{
+ public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextWindowsLive_x64(Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual ~RegisterContextWindowsLive_x64();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ bool ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value) override;
+
+ bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
+};
+}
+
+#endif // #ifndef liblldb_RegisterContextWindowsLive_x64_H_
diff --git a/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.cpp b/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.cpp
new file mode 100644
index 000000000000..f2decc72d16d
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.cpp
@@ -0,0 +1,100 @@
+//===-- RegisterContextWindowsLive_x86.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/lldb-private-types.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
+#include "lldb/Host/windows/windows.h"
+
+#include "lldb-x86-register-enums.h"
+#include "ProcessWindowsLog.h"
+#include "RegisterContextWindowsLive_x86.h"
+#include "TargetThreadWindows.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+
+namespace lldb_private
+{
+
+RegisterContextWindowsLive_x86::RegisterContextWindowsLive_x86(Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContextWindows_x86(thread, concrete_frame_idx)
+{
+}
+
+RegisterContextWindowsLive_x86::~RegisterContextWindowsLive_x86()
+{
+}
+
+
+bool
+RegisterContextWindowsLive_x86::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ // Since we cannot only write a single register value to the inferior, we need to make sure
+ // our cached copy of the register values are fresh. Otherwise when writing EAX, for example,
+ // we may also overwrite some other register with a stale value.
+ if (!CacheAllRegisterValues())
+ return false;
+
+ uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ switch (reg)
+ {
+ case lldb_eax_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EAX", reg_value.GetAsUInt32());
+ m_context.Eax = reg_value.GetAsUInt32();
+ break;
+ case lldb_ebx_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EBX", reg_value.GetAsUInt32());
+ m_context.Ebx = reg_value.GetAsUInt32();
+ break;
+ case lldb_ecx_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ECX", reg_value.GetAsUInt32());
+ m_context.Ecx = reg_value.GetAsUInt32();
+ break;
+ case lldb_edx_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EDX", reg_value.GetAsUInt32());
+ m_context.Edx = reg_value.GetAsUInt32();
+ break;
+ case lldb_edi_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EDI", reg_value.GetAsUInt32());
+ m_context.Edi = reg_value.GetAsUInt32();
+ break;
+ case lldb_esi_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ESI", reg_value.GetAsUInt32());
+ m_context.Esi = reg_value.GetAsUInt32();
+ break;
+ case lldb_ebp_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EBP", reg_value.GetAsUInt32());
+ m_context.Ebp = reg_value.GetAsUInt32();
+ break;
+ case lldb_esp_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to ESP", reg_value.GetAsUInt32());
+ m_context.Esp = reg_value.GetAsUInt32();
+ break;
+ case lldb_eip_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EIP", reg_value.GetAsUInt32());
+ m_context.Eip = reg_value.GetAsUInt32();
+ break;
+ case lldb_eflags_i386:
+ WINLOG_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to EFLAGS", reg_value.GetAsUInt32());
+ m_context.EFlags = reg_value.GetAsUInt32();
+ break;
+ default:
+ WINWARN_IFALL(WINDOWS_LOG_REGISTERS, "Write value 0x%x to unknown register %u", reg_value.GetAsUInt32(),
+ reg);
+ }
+
+ // Physically update the registers in the target process.
+ TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
+ return ::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context);
+}
+
+} // namespace lldb_private
diff --git a/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.h b/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.h
new file mode 100644
index 000000000000..9554f017408a
--- /dev/null
+++ b/source/Plugins/Process/Windows/Live/x86/RegisterContextWindowsLive_x86.h
@@ -0,0 +1,36 @@
+//===-- RegisterContextWindowsLive_x86.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_RegisterContextWindowsLive_x86_H_
+#define liblldb_RegisterContextWindowsLive_x86_H_
+
+#include "lldb/lldb-forward.h"
+#include "../../Common/x86/RegisterContextWindows_x86.h"
+
+namespace lldb_private
+{
+
+class Thread;
+
+class RegisterContextWindowsLive_x86 : public RegisterContextWindows_x86
+{
+ public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextWindowsLive_x86(Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual ~RegisterContextWindowsLive_x86();
+
+ bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
+};
+
+}
+
+#endif // #ifndef liblldb_RegisterContextWindowsLive_x86_H_
diff --git a/source/Plugins/Process/Windows/MiniDump/CMakeLists.txt b/source/Plugins/Process/Windows/MiniDump/CMakeLists.txt
new file mode 100644
index 000000000000..b43246b00351
--- /dev/null
+++ b/source/Plugins/Process/Windows/MiniDump/CMakeLists.txt
@@ -0,0 +1,21 @@
+include_directories(../../Utility)
+include_directories(../Common)
+
+set(PROC_WINDOWS_MINIDUMP_SOURCES
+ ProcessWinMiniDump.cpp
+ ThreadWinMiniDump.cpp
+ )
+
+if (CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(PROC_WINDOWS_MINIDUMP_SOURCES ${PROC_WINDOWS_MINIDUMP_SOURCES}
+ x86/RegisterContextWindowsMiniDump_x86.cpp
+ )
+elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(PROC_WINDOWS_MINIDUMP_SOURCES ${PROC_WINDOWS_MINIDUMP_SOURCES}
+ x64/RegisterContextWindowsMiniDump_x64.cpp
+ )
+endif()
+
+add_lldb_library(lldbPluginProcessWinMiniDump
+ ${PROC_WINDOWS_MINIDUMP_SOURCES}
+ )
diff --git a/source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp b/source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp
new file mode 100644
index 000000000000..fbc96f085ed4
--- /dev/null
+++ b/source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp
@@ -0,0 +1,550 @@
+//===-- ProcessWinMiniDump.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessWinMiniDump.h"
+
+#include "lldb/Host/windows/windows.h"
+#include <DbgHelp.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <memory>
+#include <mutex>
+
+#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "ExceptionRecord.h"
+#include "ThreadWinMiniDump.h"
+
+using namespace lldb_private;
+
+namespace
+{
+
+// Getting a string out of a mini dump is a chore. You're usually given a
+// relative virtual address (RVA), which points to a counted string that's in
+// Windows Unicode (UTF-16). This wrapper handles all the redirection and
+// returns a UTF-8 copy of the string.
+std::string
+GetMiniDumpString(const void *base_addr, const RVA rva)
+{
+ std::string result;
+ if (!base_addr)
+ {
+ return result;
+ }
+ auto md_string = reinterpret_cast<const MINIDUMP_STRING *>(static_cast<const char *>(base_addr) + rva);
+ auto source_start = reinterpret_cast<const UTF16 *>(md_string->Buffer);
+ const auto source_length = ::wcslen(md_string->Buffer);
+ const auto source_end = source_start + source_length;
+ result.resize(4*source_length); // worst case length
+ auto result_start = reinterpret_cast<UTF8 *>(&result[0]);
+ const auto result_end = result_start + result.size();
+ ConvertUTF16toUTF8(&source_start, source_end, &result_start, result_end, strictConversion);
+ const auto result_size = std::distance(reinterpret_cast<UTF8 *>(&result[0]), result_start);
+ result.resize(result_size); // shrink to actual length
+ return result;
+}
+
+} // anonymous namespace
+
+// Encapsulates the private data for ProcessWinMiniDump.
+// TODO(amccarth): Determine if we need a mutex for access.
+class ProcessWinMiniDump::Data
+{
+public:
+ Data();
+ ~Data();
+
+ FileSpec m_core_file;
+ HANDLE m_dump_file; // handle to the open minidump file
+ HANDLE m_mapping; // handle to the file mapping for the minidump file
+ void * m_base_addr; // base memory address of the minidump
+ std::shared_ptr<ExceptionRecord> m_exception_sp;
+};
+
+ConstString
+ProcessWinMiniDump::GetPluginNameStatic()
+{
+ static ConstString g_name("win-minidump");
+ return g_name;
+}
+
+const char *
+ProcessWinMiniDump::GetPluginDescriptionStatic()
+{
+ return "Windows minidump plug-in.";
+}
+
+void
+ProcessWinMiniDump::Terminate()
+{
+ PluginManager::UnregisterPlugin(ProcessWinMiniDump::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessWinMiniDump::CreateInstance(lldb::TargetSP target_sp, Listener &listener, const FileSpec *crash_file)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file)
+ {
+ process_sp.reset(new ProcessWinMiniDump(target_sp, listener, *crash_file));
+ }
+ return process_sp;
+}
+
+bool
+ProcessWinMiniDump::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name)
+{
+ // TODO(amccarth): Eventually, this needs some actual logic.
+ return true;
+}
+
+ProcessWinMiniDump::ProcessWinMiniDump(lldb::TargetSP target_sp, Listener &listener,
+ const FileSpec &core_file) :
+ ProcessWindows(target_sp, listener),
+ m_data_up(new Data)
+{
+ m_data_up->m_core_file = core_file;
+}
+
+ProcessWinMiniDump::~ProcessWinMiniDump()
+{
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+}
+
+ConstString
+ProcessWinMiniDump::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessWinMiniDump::GetPluginVersion()
+{
+ return 1;
+}
+
+
+Error
+ProcessWinMiniDump::DoLoadCore()
+{
+ Error error;
+
+ error = MapMiniDumpIntoMemory(m_data_up->m_core_file.GetCString());
+ if (error.Fail())
+ {
+ return error;
+ }
+
+ GetTarget().SetArchitecture(DetermineArchitecture());
+ ReadMiscInfo(); // notably for process ID
+ ReadModuleList();
+ ReadExceptionRecord();
+
+ return error;
+
+}
+
+DynamicLoader *
+ProcessWinMiniDump::GetDynamicLoader()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, DynamicLoaderWindowsDYLD::GetPluginNameStatic().GetCString()));
+ return m_dyld_ap.get();
+}
+
+bool
+ProcessWinMiniDump::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ size_t size = 0;
+ auto thread_list_ptr = static_cast<const MINIDUMP_THREAD_LIST *>(FindDumpStream(ThreadListStream, &size));
+ if (thread_list_ptr)
+ {
+ const ULONG32 thread_count = thread_list_ptr->NumberOfThreads;
+ for (ULONG32 i = 0; i < thread_count; ++i) {
+ const auto &mini_dump_thread = thread_list_ptr->Threads[i];
+ auto thread_sp = std::make_shared<ThreadWinMiniDump>(*this, mini_dump_thread.ThreadId);
+ if (mini_dump_thread.ThreadContext.DataSize >= sizeof(CONTEXT))
+ {
+ const CONTEXT *context = reinterpret_cast<const CONTEXT *>(static_cast<const char *>(m_data_up->m_base_addr) + mini_dump_thread.ThreadContext.Rva);
+ thread_sp->SetContext(context);
+ }
+ new_thread_list.AddThread(thread_sp);
+ }
+ }
+
+ return new_thread_list.GetSize(false) > 0;
+}
+
+void
+ProcessWinMiniDump::RefreshStateAfterStop()
+{
+ if (!m_data_up) return;
+ if (!m_data_up->m_exception_sp) return;
+
+ auto active_exception = m_data_up->m_exception_sp;
+ std::string desc;
+ llvm::raw_string_ostream desc_stream(desc);
+ desc_stream << "Exception "
+ << llvm::format_hex(active_exception->GetExceptionCode(), 8)
+ << " encountered at address "
+ << llvm::format_hex(active_exception->GetExceptionAddress(), 8);
+ m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID());
+ auto stop_thread = m_thread_list.GetSelectedThread();
+ auto stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str());
+ stop_thread->SetStopInfo(stop_info);
+}
+
+Error
+ProcessWinMiniDump::DoDestroy()
+{
+ return Error();
+}
+
+bool
+ProcessWinMiniDump::IsAlive()
+{
+ return true;
+}
+
+bool
+ProcessWinMiniDump::WarnBeforeDetach () const
+{
+ // Since this is post-mortem debugging, there's no need to warn the user
+ // that quitting the debugger will terminate the process.
+ return false;
+}
+
+size_t
+ProcessWinMiniDump::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Error &error)
+{
+ // Don't allow the caching that lldb_private::Process::ReadMemory does
+ // since we have it all cached our our dump file anyway.
+ return DoReadMemory(addr, buf, size, error);
+}
+
+size_t
+ProcessWinMiniDump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, Error &error)
+{
+ // I don't have a sense of how frequently this is called or how many memory
+ // ranges a mini dump typically has, so I'm not sure if searching for the
+ // appropriate range linearly each time is stupid. Perhaps we should build
+ // an index for faster lookups.
+ Range range = {0};
+ if (!FindMemoryRange(addr, &range))
+ {
+ return 0;
+ }
+
+ // There's at least some overlap between the beginning of the desired range
+ // (addr) and the current range. Figure out where the overlap begins and
+ // how much overlap there is, then copy it to the destination buffer.
+ lldbassert(range.start <= addr);
+ const size_t offset = addr - range.start;
+ lldbassert(offset < range.size);
+ const size_t overlap = std::min(size, range.size - offset);
+ std::memcpy(buf, range.ptr + offset, overlap);
+ return overlap;
+}
+
+Error
+ProcessWinMiniDump::GetMemoryRegionInfo(lldb::addr_t load_addr, lldb_private::MemoryRegionInfo &info)
+{
+ Error error;
+ size_t size;
+ const auto list = reinterpret_cast<const MINIDUMP_MEMORY_INFO_LIST *>(FindDumpStream(MemoryInfoListStream, &size));
+ if (list == nullptr || size < sizeof(MINIDUMP_MEMORY_INFO_LIST))
+ {
+ error.SetErrorString("the mini dump contains no memory range information");
+ return error;
+ }
+
+ if (list->SizeOfEntry < sizeof(MINIDUMP_MEMORY_INFO))
+ {
+ error.SetErrorString("the entries in the mini dump memory info list are smaller than expected");
+ return error;
+ }
+
+ if (size < list->SizeOfHeader + list->SizeOfEntry * list->NumberOfEntries)
+ {
+ error.SetErrorString("the mini dump memory info list is incomplete");
+ return error;
+ }
+
+ for (int i = 0; i < list->NumberOfEntries; ++i)
+ {
+ const auto entry = reinterpret_cast<const MINIDUMP_MEMORY_INFO *>(reinterpret_cast<const char *>(list) +
+ list->SizeOfHeader + i * list->SizeOfEntry);
+ const auto head = entry->BaseAddress;
+ const auto tail = head + entry->RegionSize;
+ if (head <= load_addr && load_addr < tail)
+ {
+ info.SetReadable(IsPageReadable(entry->Protect) ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+ info.SetWritable(IsPageWritable(entry->Protect) ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+ info.SetExecutable(IsPageExecutable(entry->Protect) ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+ return error;
+ }
+ }
+ // Note that the memory info list doesn't seem to contain ranges in kernel space,
+ // so if you're walking a stack that has kernel frames, the stack may appear
+ // truncated.
+ error.SetErrorString("address is not in a known range");
+ return error;
+}
+
+void
+ProcessWinMiniDump::Clear()
+{
+ m_thread_list.Clear();
+}
+
+void
+ProcessWinMiniDump::Initialize()
+{
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, []()
+ {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+ });
+}
+
+ArchSpec
+ProcessWinMiniDump::GetArchitecture()
+{
+ // TODO
+ return ArchSpec();
+}
+
+
+ProcessWinMiniDump::Data::Data() :
+ m_dump_file(INVALID_HANDLE_VALUE),
+ m_mapping(NULL),
+ m_base_addr(nullptr)
+{
+}
+
+ProcessWinMiniDump::Data::~Data()
+{
+ if (m_base_addr)
+ {
+ ::UnmapViewOfFile(m_base_addr);
+ m_base_addr = nullptr;
+ }
+ if (m_mapping)
+ {
+ ::CloseHandle(m_mapping);
+ m_mapping = NULL;
+ }
+ if (m_dump_file != INVALID_HANDLE_VALUE)
+ {
+ ::CloseHandle(m_dump_file);
+ m_dump_file = INVALID_HANDLE_VALUE;
+ }
+}
+
+bool
+ProcessWinMiniDump::FindMemoryRange(lldb::addr_t addr, Range *range_out) const
+{
+ size_t stream_size = 0;
+ auto mem_list_stream = static_cast<const MINIDUMP_MEMORY_LIST *>(FindDumpStream(MemoryListStream, &stream_size));
+ if (mem_list_stream)
+ {
+ for (ULONG32 i = 0; i < mem_list_stream->NumberOfMemoryRanges; ++i) {
+ const MINIDUMP_MEMORY_DESCRIPTOR &mem_desc = mem_list_stream->MemoryRanges[i];
+ const MINIDUMP_LOCATION_DESCRIPTOR &loc_desc = mem_desc.Memory;
+ const lldb::addr_t range_start = mem_desc.StartOfMemoryRange;
+ const size_t range_size = loc_desc.DataSize;
+ if (range_start <= addr && addr < range_start + range_size)
+ {
+ range_out->start = range_start;
+ range_out->size = range_size;
+ range_out->ptr = reinterpret_cast<const uint8_t *>(m_data_up->m_base_addr) + loc_desc.Rva;
+ return true;
+ }
+ }
+ }
+
+ // Some mini dumps have a Memory64ListStream that captures all the heap
+ // memory. We can't exactly use the same loop as above, because the mini
+ // dump uses slightly different data structures to describe those.
+ auto mem_list64_stream = static_cast<const MINIDUMP_MEMORY64_LIST *>(FindDumpStream(Memory64ListStream, &stream_size));
+ if (mem_list64_stream)
+ {
+ size_t base_rva = mem_list64_stream->BaseRva;
+ for (ULONG32 i = 0; i < mem_list64_stream->NumberOfMemoryRanges; ++i) {
+ const MINIDUMP_MEMORY_DESCRIPTOR64 &mem_desc = mem_list64_stream->MemoryRanges[i];
+ const lldb::addr_t range_start = mem_desc.StartOfMemoryRange;
+ const size_t range_size = mem_desc.DataSize;
+ if (range_start <= addr && addr < range_start + range_size)
+ {
+ range_out->start = range_start;
+ range_out->size = range_size;
+ range_out->ptr = reinterpret_cast<const uint8_t *>(m_data_up->m_base_addr) + base_rva;
+ return true;
+ }
+ base_rva += range_size;
+ }
+ }
+
+ return false;
+}
+
+
+Error
+ProcessWinMiniDump::MapMiniDumpIntoMemory(const char *file)
+{
+ Error error;
+
+ m_data_up->m_dump_file = ::CreateFile(file, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (m_data_up->m_dump_file == INVALID_HANDLE_VALUE)
+ {
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ return error;
+ }
+
+ m_data_up->m_mapping = ::CreateFileMapping(m_data_up->m_dump_file, NULL,
+ PAGE_READONLY, 0, 0, NULL);
+ if (m_data_up->m_mapping == NULL)
+ {
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ return error;
+ }
+
+ m_data_up->m_base_addr = ::MapViewOfFile(m_data_up->m_mapping, FILE_MAP_READ, 0, 0, 0);
+ if (m_data_up->m_base_addr == NULL)
+ {
+ error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ return error;
+ }
+
+ return error;
+}
+
+
+ArchSpec
+ProcessWinMiniDump::DetermineArchitecture()
+{
+ size_t size = 0;
+ auto system_info_ptr = static_cast<const MINIDUMP_SYSTEM_INFO *>(FindDumpStream(SystemInfoStream, &size));
+ if (system_info_ptr)
+ {
+ switch (system_info_ptr->ProcessorArchitecture)
+ {
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ return ArchSpec(eArchTypeCOFF, IMAGE_FILE_MACHINE_I386, LLDB_INVALID_CPUTYPE);
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ return ArchSpec(eArchTypeCOFF, IMAGE_FILE_MACHINE_AMD64, LLDB_INVALID_CPUTYPE);
+ default:
+ break;
+ }
+ }
+
+ return ArchSpec(); // invalid or unknown
+}
+
+void
+ProcessWinMiniDump::ReadExceptionRecord()
+{
+ size_t size = 0;
+ auto exception_stream_ptr = static_cast<MINIDUMP_EXCEPTION_STREAM*>(FindDumpStream(ExceptionStream, &size));
+ if (exception_stream_ptr)
+ {
+ m_data_up->m_exception_sp.reset(new ExceptionRecord(exception_stream_ptr->ExceptionRecord, exception_stream_ptr->ThreadId));
+ }
+}
+
+void
+ProcessWinMiniDump::ReadMiscInfo()
+{
+ size_t size = 0;
+ const auto misc_info_ptr = static_cast<MINIDUMP_MISC_INFO*>(FindDumpStream(MiscInfoStream, &size));
+ if (!misc_info_ptr || size < sizeof(MINIDUMP_MISC_INFO)) {
+ return;
+ }
+
+ if ((misc_info_ptr->Flags1 & MINIDUMP_MISC1_PROCESS_ID) != 0) {
+ // This misc info record has the process ID.
+ SetID(misc_info_ptr->ProcessId);
+ }
+}
+
+void
+ProcessWinMiniDump::ReadModuleList()
+{
+ size_t size = 0;
+ auto module_list_ptr = static_cast<MINIDUMP_MODULE_LIST*>(FindDumpStream(ModuleListStream, &size));
+ if (!module_list_ptr || module_list_ptr->NumberOfModules == 0)
+ {
+ return;
+ }
+
+ for (ULONG32 i = 0; i < module_list_ptr->NumberOfModules; ++i)
+ {
+ const auto &module = module_list_ptr->Modules[i];
+ const auto file_name = GetMiniDumpString(m_data_up->m_base_addr, module.ModuleNameRva);
+ ModuleSpec module_spec = FileSpec(file_name, true);
+
+ lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec);
+ if (!module_sp)
+ {
+ continue;
+ }
+ bool load_addr_changed = false;
+ module_sp->SetLoadAddress(GetTarget(), module.BaseOfImage, false, load_addr_changed);
+ }
+}
+
+void *
+ProcessWinMiniDump::FindDumpStream(unsigned stream_number, size_t *size_out) const
+{
+ void *stream = nullptr;
+ *size_out = 0;
+
+ assert(m_data_up != nullptr);
+ assert(m_data_up->m_base_addr != 0);
+
+ MINIDUMP_DIRECTORY *dir = nullptr;
+ if (::MiniDumpReadDumpStream(m_data_up->m_base_addr, stream_number, &dir, nullptr, nullptr) &&
+ dir != nullptr && dir->Location.DataSize > 0)
+ {
+ assert(dir->StreamType == stream_number);
+ *size_out = dir->Location.DataSize;
+ stream = static_cast<void*>(static_cast<char*>(m_data_up->m_base_addr) + dir->Location.Rva);
+ }
+
+ return stream;
+}
diff --git a/source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h b/source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h
new file mode 100644
index 000000000000..12864be37127
--- /dev/null
+++ b/source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h
@@ -0,0 +1,140 @@
+//===-- ProcessWinMiniDump.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_ProcessWinMiniDump_h_
+#define liblldb_ProcessWinMiniDump_h_
+
+#include <list>
+#include <vector>
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/Process.h"
+
+#include "Plugins/Process/Windows/Common/ProcessWindows.h"
+
+struct ThreadData;
+
+class ProcessWinMiniDump : public lldb_private::ProcessWindows
+{
+ public:
+ static lldb::ProcessSP
+ CreateInstance (lldb::TargetSP target_sp,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ ProcessWinMiniDump(lldb::TargetSP target_sp,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec &core_file);
+
+ virtual
+ ~ProcessWinMiniDump();
+
+ bool
+ CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override;
+
+ lldb_private::Error
+ DoLoadCore() override;
+
+ lldb_private::DynamicLoader *
+ GetDynamicLoader() override;
+
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+ lldb_private::Error
+ DoDestroy() override;
+
+ void
+ RefreshStateAfterStop() override;
+
+ bool
+ IsAlive() override;
+
+ bool
+ WarnBeforeDetach () const override;
+
+ size_t
+ ReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
+
+ size_t
+ DoReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
+
+ lldb_private::ArchSpec
+ GetArchitecture();
+
+ lldb_private::Error
+ GetMemoryRegionInfo(lldb::addr_t load_addr, lldb_private::MemoryRegionInfo &range_info) override;
+
+ protected:
+ void
+ Clear();
+
+ bool
+ UpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) override;
+
+ private:
+ // Describes a range of memory captured in the mini dump.
+ struct Range {
+ lldb::addr_t start; // virtual address of the beginning of the range
+ size_t size; // size of the range in bytes
+ const uint8_t *ptr; // absolute pointer to the first byte of the range
+ };
+
+ // If the mini dump has a memory range that contains the desired address, it
+ // returns true with the details of the range in *range_out. Otherwise, it
+ // returns false.
+ bool
+ FindMemoryRange(lldb::addr_t addr, Range *range_out) const;
+
+ lldb_private::Error
+ MapMiniDumpIntoMemory(const char *file);
+
+ lldb_private::ArchSpec
+ DetermineArchitecture();
+
+ void
+ ReadExceptionRecord();
+
+ void
+ ReadMiscInfo();
+
+ void
+ ReadModuleList();
+
+ // A thin wrapper around WinAPI's MiniDumpReadDumpStream to avoid redundant
+ // checks. If there's a failure (e.g., if the requested stream doesn't exist),
+ // the function returns nullptr and sets *size_out to 0.
+ void *
+ FindDumpStream(unsigned stream_number, size_t *size_out) const;
+
+ // Isolate the data to keep Windows-specific types out of this header. Can't
+ // use the typical pimpl idiom because the implementation of this class also
+ // needs access to public and protected members of the base class.
+ class Data;
+ std::unique_ptr<Data> m_data_up;
+};
+
+#endif // liblldb_ProcessWinMiniDump_h_
diff --git a/source/Plugins/Process/Windows/MiniDump/ThreadWinMiniDump.cpp b/source/Plugins/Process/Windows/MiniDump/ThreadWinMiniDump.cpp
new file mode 100644
index 000000000000..ddcd15b1ae12
--- /dev/null
+++ b/source/Plugins/Process/Windows/MiniDump/ThreadWinMiniDump.cpp
@@ -0,0 +1,104 @@
+//===-- ThreadWinMiniDump.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThreadWinMiniDump.h"
+
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/windows/windows.h"
+#include <DbgHelp.h>
+
+#include "ProcessWinMiniDump.h"
+#if defined(_WIN64)
+#include "x64/RegisterContextWindowsMiniDump_x64.h"
+#else
+#include "x86/RegisterContextWindowsMiniDump_x86.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+// This is a minimal implementation in order to get something running. It will
+// be fleshed out as more mini-dump functionality is added.
+
+class ThreadWinMiniDump::Data {
+ public:
+ Data() : m_context(nullptr) {}
+ const CONTEXT *m_context;
+};
+
+ThreadWinMiniDump::ThreadWinMiniDump(lldb_private::Process &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_data(new Data)
+{
+}
+
+ThreadWinMiniDump::~ThreadWinMiniDump()
+{
+}
+
+void
+ThreadWinMiniDump::RefreshStateAfterStop()
+{
+}
+
+lldb::RegisterContextSP
+ThreadWinMiniDump::GetRegisterContext()
+{
+ if (m_reg_context_sp.get() == NULL) {
+ m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+ }
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadWinMiniDump::CreateRegisterContextForFrame(lldb_private::StackFrame *frame)
+{
+ const uint32_t concrete_frame_idx = (frame) ? frame->GetConcreteFrameIndex() : 0;
+ RegisterContextSP reg_ctx_sp;
+ ArchSpec arch = HostInfo::GetArchitecture();
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+#if defined(_WIN64)
+ // FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64
+#else
+ reg_ctx_sp.reset(new RegisterContextWindowsMiniDump_x86(*this, concrete_frame_idx, m_data->m_context));
+#endif
+ break;
+ case llvm::Triple::x86_64:
+#if defined(_WIN64)
+ reg_ctx_sp.reset(new RegisterContextWindowsMiniDump_x64(*this, concrete_frame_idx, m_data->m_context));
+#else
+ // LLDB is 32-bit, but the target process is 64-bit. We probably can't debug this.
+#endif
+ default:
+ break;
+ }
+ return reg_ctx_sp;
+}
+
+void
+ThreadWinMiniDump::ClearStackFrames()
+{
+}
+
+void
+ThreadWinMiniDump::SetContext(const void *context)
+{
+ if (m_data)
+ {
+ m_data->m_context = static_cast<const CONTEXT *>(context);
+ }
+}
+
+bool
+ThreadWinMiniDump::CalculateStopInfo()
+{
+ return false;
+}
diff --git a/source/Plugins/Process/Windows/MiniDump/ThreadWinMiniDump.h b/source/Plugins/Process/Windows/MiniDump/ThreadWinMiniDump.h
new file mode 100644
index 000000000000..c78925422102
--- /dev/null
+++ b/source/Plugins/Process/Windows/MiniDump/ThreadWinMiniDump.h
@@ -0,0 +1,49 @@
+//===-- ThreadWinMiniDump.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_ThreadWinMiniDump_h_
+#define liblldb_ThreadWinMiniDump_h_
+
+#include <string>
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/Thread.h"
+
+class ThreadWinMiniDump : public lldb_private::Thread
+{
+public:
+ ThreadWinMiniDump(lldb_private::Process &process, lldb::tid_t tid);
+
+ virtual
+ ~ThreadWinMiniDump();
+
+ void
+ RefreshStateAfterStop() override;
+
+ lldb::RegisterContextSP
+ GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+ void
+ ClearStackFrames() override;
+
+ void
+ SetContext(const void *context);
+
+protected:
+ lldb::RegisterContextSP m_reg_context_sp;
+ class Data;
+ std::unique_ptr<Data> m_data; // for WinAPI-specific data
+
+ bool CalculateStopInfo() override;
+};
+
+#endif
diff --git a/source/Plugins/Process/Windows/MiniDump/x64/RegisterContextWindowsMiniDump_x64.cpp b/source/Plugins/Process/Windows/MiniDump/x64/RegisterContextWindowsMiniDump_x64.cpp
new file mode 100644
index 000000000000..41d9195f1eed
--- /dev/null
+++ b/source/Plugins/Process/Windows/MiniDump/x64/RegisterContextWindowsMiniDump_x64.cpp
@@ -0,0 +1,47 @@
+//===-- RegisterContextWindowsMiniDump_x64.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/lldb-private-types.h"
+#include "lldb/Host/windows/windows.h"
+
+#include "RegisterContextWindowsMiniDump_x64.h"
+
+using namespace lldb;
+
+namespace lldb_private
+{
+
+RegisterContextWindowsMiniDump_x64::RegisterContextWindowsMiniDump_x64(Thread &thread, uint32_t concrete_frame_idx, const CONTEXT *context)
+ : RegisterContextWindows_x64(thread, concrete_frame_idx)
+{
+ if (context)
+ {
+ m_context = *context;
+ m_context_stale = false;
+ }
+}
+
+RegisterContextWindowsMiniDump_x64::~RegisterContextWindowsMiniDump_x64()
+{
+}
+
+bool
+RegisterContextWindowsMiniDump_x64::WriteRegister(const RegisterInfo * /* reg_info */, const RegisterValue & /* reg_value */)
+{
+ return false;
+}
+
+bool
+RegisterContextWindowsMiniDump_x64::CacheAllRegisterValues()
+{
+ // Since this is post-mortem debugging, we either have the context or we don't.
+ return !m_context_stale;
+}
+
+} // namespace lldb_private
diff --git a/source/Plugins/Process/Windows/MiniDump/x64/RegisterContextWindowsMiniDump_x64.h b/source/Plugins/Process/Windows/MiniDump/x64/RegisterContextWindowsMiniDump_x64.h
new file mode 100644
index 000000000000..86d58046113f
--- /dev/null
+++ b/source/Plugins/Process/Windows/MiniDump/x64/RegisterContextWindowsMiniDump_x64.h
@@ -0,0 +1,36 @@
+//===-- RegisterContextWindowsMiniDump_x64.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_RegisterContextWindowsMiniDump_x64_H_
+#define liblldb_RegisterContextWindowsMiniDump_x64_H_
+
+#include "lldb/lldb-forward.h"
+#include "Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h"
+
+namespace lldb_private
+{
+
+class Thread;
+
+class RegisterContextWindowsMiniDump_x64 : public RegisterContextWindows_x64
+{
+ public:
+ RegisterContextWindowsMiniDump_x64(Thread &thread, uint32_t concrete_frame_idx, const CONTEXT *context);
+
+ virtual ~RegisterContextWindowsMiniDump_x64();
+
+ bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
+
+ protected:
+ bool CacheAllRegisterValues() override;
+};
+
+}
+
+#endif // #ifndef liblldb_RegisterContextWindowsMiniDump_x64_H_
diff --git a/source/Plugins/Process/Windows/MiniDump/x86/RegisterContextWindowsMiniDump_x86.cpp b/source/Plugins/Process/Windows/MiniDump/x86/RegisterContextWindowsMiniDump_x86.cpp
new file mode 100644
index 000000000000..2c8a069c5376
--- /dev/null
+++ b/source/Plugins/Process/Windows/MiniDump/x86/RegisterContextWindowsMiniDump_x86.cpp
@@ -0,0 +1,47 @@
+//===-- RegisterContextWindowsMiniDump_x86.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/lldb-private-types.h"
+#include "lldb/Host/windows/windows.h"
+
+#include "RegisterContextWindowsMiniDump_x86.h"
+
+using namespace lldb;
+
+namespace lldb_private
+{
+
+RegisterContextWindowsMiniDump_x86::RegisterContextWindowsMiniDump_x86(Thread &thread, uint32_t concrete_frame_idx, const CONTEXT *context)
+ : RegisterContextWindows_x86(thread, concrete_frame_idx)
+{
+ if (context)
+ {
+ m_context = *context;
+ m_context_stale = false;
+ }
+}
+
+RegisterContextWindowsMiniDump_x86::~RegisterContextWindowsMiniDump_x86()
+{
+}
+
+bool
+RegisterContextWindowsMiniDump_x86::WriteRegister(const RegisterInfo * /* reg_info */, const RegisterValue & /* reg_value */)
+{
+ return false;
+}
+
+bool
+RegisterContextWindowsMiniDump_x86::CacheAllRegisterValues()
+{
+ // Since this is post-mortem debugging, we either have the context or we don't.
+ return !m_context_stale;
+}
+
+} // namespace lldb_private
diff --git a/source/Plugins/Process/Windows/MiniDump/x86/RegisterContextWindowsMiniDump_x86.h b/source/Plugins/Process/Windows/MiniDump/x86/RegisterContextWindowsMiniDump_x86.h
new file mode 100644
index 000000000000..d36e0cfd9e7b
--- /dev/null
+++ b/source/Plugins/Process/Windows/MiniDump/x86/RegisterContextWindowsMiniDump_x86.h
@@ -0,0 +1,36 @@
+//===-- RegisterContextWindowsMiniDump_x86.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_RegisterContextWindowsMiniDump_x86_H_
+#define liblldb_RegisterContextWindowsMiniDump_x86_H_
+
+#include "lldb/lldb-forward.h"
+#include "Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h"
+
+namespace lldb_private
+{
+
+class Thread;
+
+class RegisterContextWindowsMiniDump_x86 : public RegisterContextWindows_x86
+{
+ public:
+ RegisterContextWindowsMiniDump_x86(Thread &thread, uint32_t concrete_frame_idx, const CONTEXT *context);
+
+ virtual ~RegisterContextWindowsMiniDump_x86();
+
+ bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
+
+ protected:
+ bool CacheAllRegisterValues() override;
+};
+
+}
+
+#endif // #ifndef liblldb_RegisterContextWindowsMiniDump_x86_H_
diff --git a/source/Plugins/Process/elf-core/CMakeLists.txt b/source/Plugins/Process/elf-core/CMakeLists.txt
new file mode 100644
index 000000000000..1a4dd7e9d333
--- /dev/null
+++ b/source/Plugins/Process/elf-core/CMakeLists.txt
@@ -0,0 +1,11 @@
+include_directories(../Utility)
+
+add_lldb_library(lldbPluginProcessElfCore
+ ProcessElfCore.cpp
+ ThreadElfCore.cpp
+ RegisterContextPOSIXCore_arm.cpp
+ RegisterContextPOSIXCore_arm64.cpp
+ RegisterContextPOSIXCore_mips64.cpp
+ RegisterContextPOSIXCore_powerpc.cpp
+ RegisterContextPOSIXCore_x86_64.cpp
+ )
diff --git a/source/Plugins/Process/elf-core/Makefile b/source/Plugins/Process/elf-core/Makefile
new file mode 100644
index 000000000000..8c5b3b800f5a
--- /dev/null
+++ b/source/Plugins/Process/elf-core/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Process/elf-core/Makefile -----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginProcessElfCore
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Process/gdb-remote/CMakeLists.txt b/source/Plugins/Process/gdb-remote/CMakeLists.txt
new file mode 100644
index 000000000000..8dbfa453f2c2
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/CMakeLists.txt
@@ -0,0 +1,16 @@
+if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ include_directories(${LIBXML2_INCLUDE_DIR})
+endif()
+
+add_lldb_library(lldbPluginProcessGDBRemote
+ GDBRemoteCommunication.cpp
+ GDBRemoteCommunicationClient.cpp
+ GDBRemoteCommunicationServer.cpp
+ GDBRemoteCommunicationServerCommon.cpp
+ GDBRemoteCommunicationServerLLGS.cpp
+ GDBRemoteCommunicationServerPlatform.cpp
+ GDBRemoteRegisterContext.cpp
+ ProcessGDBRemote.cpp
+ ProcessGDBRemoteLog.cpp
+ ThreadGDBRemote.cpp
+ )
diff --git a/source/Plugins/Process/gdb-remote/Makefile b/source/Plugins/Process/gdb-remote/Makefile
new file mode 100644
index 000000000000..8a9b61077875
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Process/gdb-remote/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginProcessGDBRemote
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 2e7a5b5384f4..be380a442e3c 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -109,35 +109,35 @@ namespace {
{ "target-definition-file" , OptionValue::eTypeFileSpec , true, 0 , NULL, NULL, "The file that provides the description for remote target registers." },
{ NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
};
-
+
enum
{
ePropertyPacketTimeout,
ePropertyTargetDefinitionFile
};
-
+
class PluginProperties : public Properties
{
public:
-
+
static ConstString
GetSettingName ()
{
return ProcessGDBRemote::GetPluginNameStatic();
}
-
+
PluginProperties() :
Properties ()
{
m_collection_sp.reset (new OptionValueProperties(GetSettingName()));
m_collection_sp->Initialize(g_properties);
}
-
+
virtual
~PluginProperties()
{
}
-
+
uint64_t
GetPacketTimeout()
{
@@ -159,9 +159,9 @@ namespace {
return m_collection_sp->GetPropertyAtIndexAsFileSpec (NULL, idx);
}
};
-
+
typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP;
-
+
static const ProcessKDPPropertiesSP &
GetGlobalPluginProperties()
{
@@ -170,7 +170,7 @@ namespace {
g_settings_sp.reset (new PluginProperties ());
return g_settings_sp;
}
-
+
} // anonymous namespace end
class ProcessGDBRemote::GDBLoadedModuleInfoList
@@ -446,7 +446,7 @@ ProcessGDBRemote::~ProcessGDBRemote()
// destruct this class, then Process::~Process() might have problems
// trying to fully destroy the broadcaster.
Finalize();
-
+
// The general Finalize is going to try to destroy the process and that SHOULD
// shut down the async thread. However, if we don't kill it it will get stranded and
// its connection will go away so when it wakes up it will crash. So kill it for sure here.
@@ -587,7 +587,7 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout);
}
- // Register info search order:
+ // Register info search order:
// 1 - Use the target definition python file if one is specified.
// 2 - If the target definition doesn't have any of the info from the target.xml (registers) then proceed to read the target.xml.
// 3 - Fall back on the qRegisterInfo packets.
@@ -614,12 +614,12 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
if (GetGDBServerRegisterInfo ())
return;
-
+
char packet[128];
uint32_t reg_offset = 0;
uint32_t reg_num = 0;
for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse;
- response_type == StringExtractorGDBRemote::eResponse;
+ response_type == StringExtractorGDBRemote::eResponse;
++reg_num)
{
const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num);
@@ -831,7 +831,7 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
{
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
Error error (WillLaunchOrAttach ());
-
+
if (error.Fail())
return error;
@@ -845,7 +845,7 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
if (pid == LLDB_INVALID_PROCESS_ID)
{
// We don't have a valid process ID, so note that we are connected
- // and could now request to launch or attach, or get remote process
+ // and could now request to launch or attach, or get remote process
// listings...
SetPrivateState (eStateConnected);
}
@@ -864,7 +864,7 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
HandleStopReplySequence();
Target &target = GetTarget();
- if (!target.GetArchitecture().IsValid())
+ if (!target.GetArchitecture().IsValid())
{
if (m_gdb_comm.GetProcessArchitecture().IsValid())
{
@@ -1058,11 +1058,11 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError);
m_gdb_comm.SendLaunchArchPacket (GetTarget().GetArchitecture().GetArchitectureName());
-
+
const char * launch_event_data = launch_info.GetLaunchEventData();
if (launch_event_data != NULL && *launch_event_data != '\0')
m_gdb_comm.SendLaunchEventDataPacket (launch_event_data);
-
+
if (working_dir)
{
m_gdb_comm.SetWorkingDir (working_dir);
@@ -1134,7 +1134,7 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
}
SetPrivateState (SetThreadStopInfo (response));
-
+
if (!disable_stdio)
{
if (pty.GetMasterFileDescriptor() != lldb_utility::PseudoTerminal::invalid_fd)
@@ -1152,8 +1152,8 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
{
// Set our user ID to an invalid process ID.
SetID(LLDB_INVALID_PROCESS_ID);
- error.SetErrorStringWithFormat ("failed to get object file from '%s' for arch %s",
- exe_module->GetFileSpec().GetFilename().AsCString(),
+ error.SetErrorStringWithFormat ("failed to get object file from '%s' for arch %s",
+ exe_module->GetFileSpec().GetFilename().AsCString(),
exe_module->GetArchitecture().GetArchitectureName());
}
return error;
@@ -1167,7 +1167,7 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
Error error;
// Only connect if we have a valid connect URL
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
-
+
if (connect_url && connect_url[0])
{
if (log)
@@ -1189,9 +1189,9 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
// If we were interrupted, don't keep retrying.
break;
}
-
+
retry_count++;
-
+
if (retry_count >= max_retry_count)
break;
@@ -1216,7 +1216,7 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
// We always seem to be able to open a connection to a local port
// so we need to make sure we can then send data to it. If we can't
// then we aren't actually connected to anything, so try and do the
- // handshake with the remote GDB server and make sure that goes
+ // handshake with the remote GDB server and make sure that goes
// alright.
if (!m_gdb_comm.HandshakeWithServer (&error))
{
@@ -1382,7 +1382,7 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process
char packet[64];
const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid);
- SetID (attach_pid);
+ SetID (attach_pid);
m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet, packet_len));
}
else
@@ -1405,9 +1405,9 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const Pro
if (error.Success())
{
StreamString packet;
-
+
m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
-
+
if (attach_info.GetWaitForLaunch())
{
if (!m_gdb_comm.GetVAttachOrWaitSupported())
@@ -1426,7 +1426,7 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const Pro
packet.PutCString("vAttachName");
packet.PutChar(';');
packet.PutBytesAsRawHex8(process_name, strlen(process_name), endian::InlHostByteOrder(), endian::InlHostByteOrder());
-
+
m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet.GetData(), packet.GetSize()));
}
@@ -1471,12 +1471,12 @@ ProcessGDBRemote::DoResume ()
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
if (log)
log->Printf ("ProcessGDBRemote::Resume()");
-
+
Listener listener ("gdb-remote.resume-packet-sent");
if (listener.StartListeningForEvents (&m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent))
{
listener.StartListeningForEvents (&m_async_broadcaster, ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit);
-
+
const size_t num_threads = GetThreadList().GetSize();
StreamString continue_packet;
@@ -1496,7 +1496,7 @@ ProcessGDBRemote::DoResume ()
else
{
continue_packet.PutCString ("vCont");
-
+
if (!m_continue_c_tids.empty())
{
if (m_gdb_comm.GetVContSupported ('c'))
@@ -1504,10 +1504,10 @@ ProcessGDBRemote::DoResume ()
for (tid_collection::const_iterator t_pos = m_continue_c_tids.begin(), t_end = m_continue_c_tids.end(); t_pos != t_end; ++t_pos)
continue_packet.Printf(";c:%4.4" PRIx64, *t_pos);
}
- else
+ else
continue_packet_error = true;
}
-
+
if (!continue_packet_error && !m_continue_C_tids.empty())
{
if (m_gdb_comm.GetVContSupported ('C'))
@@ -1515,7 +1515,7 @@ ProcessGDBRemote::DoResume ()
for (tid_sig_collection::const_iterator s_pos = m_continue_C_tids.begin(), s_end = m_continue_C_tids.end(); s_pos != s_end; ++s_pos)
continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first);
}
- else
+ else
continue_packet_error = true;
}
@@ -1526,10 +1526,10 @@ ProcessGDBRemote::DoResume ()
for (tid_collection::const_iterator t_pos = m_continue_s_tids.begin(), t_end = m_continue_s_tids.end(); t_pos != t_end; ++t_pos)
continue_packet.Printf(";s:%4.4" PRIx64, *t_pos);
}
- else
+ else
continue_packet_error = true;
}
-
+
if (!continue_packet_error && !m_continue_S_tids.empty())
{
if (m_gdb_comm.GetVContSupported ('S'))
@@ -1540,14 +1540,14 @@ ProcessGDBRemote::DoResume ()
else
continue_packet_error = true;
}
-
+
if (continue_packet_error)
continue_packet.GetString().clear();
}
}
else
continue_packet_error = true;
-
+
if (continue_packet_error)
{
// Either no vCont support, or we tried to use part of the vCont
@@ -1563,33 +1563,33 @@ ProcessGDBRemote::DoResume ()
{
// All threads are resuming...
m_gdb_comm.SetCurrentThreadForRun (-1);
- continue_packet.PutChar ('c');
+ continue_packet.PutChar ('c');
continue_packet_error = false;
}
else if (num_continue_c_tids == 1 &&
- num_continue_C_tids == 0 &&
- num_continue_s_tids == 0 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 0 &&
num_continue_S_tids == 0 )
{
// Only one thread is continuing
m_gdb_comm.SetCurrentThreadForRun (m_continue_c_tids.front());
- continue_packet.PutChar ('c');
+ continue_packet.PutChar ('c');
continue_packet_error = false;
}
}
if (continue_packet_error && num_continue_C_tids > 0)
{
- if ((num_continue_C_tids + num_continue_c_tids) == num_threads &&
- num_continue_C_tids > 0 &&
- num_continue_s_tids == 0 &&
+ if ((num_continue_C_tids + num_continue_c_tids) == num_threads &&
+ num_continue_C_tids > 0 &&
+ num_continue_s_tids == 0 &&
num_continue_S_tids == 0 )
{
const int continue_signo = m_continue_C_tids.front().second;
// Only one thread is continuing
if (num_continue_C_tids > 1)
{
- // More that one thread with a signal, yet we don't have
+ // More that one thread with a signal, yet we don't have
// vCont support and we are being asked to resume each
// thread with a signal, we need to make sure they are
// all the same signal, or we can't issue the continue
@@ -1641,13 +1641,13 @@ ProcessGDBRemote::DoResume ()
continue_packet_error = false;
}
else if (num_continue_c_tids == 0 &&
- num_continue_C_tids == 0 &&
- num_continue_s_tids == 1 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 1 &&
num_continue_S_tids == 0 )
{
// Only one thread is stepping
m_gdb_comm.SetCurrentThreadForRun (m_continue_s_tids.front());
- continue_packet.PutChar ('s');
+ continue_packet.PutChar ('s');
continue_packet_error = false;
}
}
@@ -1675,8 +1675,8 @@ ProcessGDBRemote::DoResume ()
}
}
else if (num_continue_c_tids == 0 &&
- num_continue_C_tids == 0 &&
- num_continue_s_tids == 0 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 0 &&
num_continue_S_tids == 1 )
{
// Only one thread is stepping with signal
@@ -1704,7 +1704,7 @@ ProcessGDBRemote::DoResume ()
log->Printf ("ProcessGDBRemote::DoResume: Trying to resume but the async thread is dead.");
return error;
}
-
+
m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (continue_packet.GetData(), continue_packet.GetSize()));
if (listener.WaitForEvent (&timeout, event_sp) == false)
@@ -1890,7 +1890,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD));
if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
log->Printf ("ProcessGDBRemote::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID());
-
+
size_t num_thread_ids = m_thread_ids.size();
// The "m_thread_ids" thread ID list should always be updated after each stop
// reply packet, but in case it isn't, update it here.
@@ -1926,7 +1926,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new
thread_sp->GetID());
}
// The m_thread_pcs vector has pc values in big-endian order, not target-endian, unlike most
- // of the register read/write packets in gdb-remote protocol.
+ // of the register read/write packets in gdb-remote protocol.
// Early in the process startup, we may not yet have set the process ByteOrder so we ignore these;
// they are a performance improvement over fetching thread register values individually, the
// method we will fall back to if needed.
@@ -1936,7 +1936,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new
RegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext());
if (reg_ctx_sp)
{
- uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber
+ uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber
(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
if (pc_regnum != LLDB_INVALID_REGNUM)
{
@@ -1947,7 +1947,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new
new_thread_list.AddThread(thread_sp);
}
}
-
+
// Whatever that is left in old_thread_list_copy are not
// present in new_thread_list. Remove non-existent threads from internal id table.
size_t old_num_thread_ids = old_thread_list_copy.GetSize(false);
@@ -1960,7 +1960,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new
m_thread_id_to_index_id_map.erase(old_thread_id);
}
}
-
+
return true;
}
@@ -2658,10 +2658,10 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
if (tid == LLDB_INVALID_THREAD_ID)
{
- // A thread id may be invalid if the response is old style 'S' packet which does not provide the
+ // A thread id may be invalid if the response is old style 'S' packet which does not provide the
// thread information. So update the thread list and choose the first one.
UpdateThreadIDList ();
-
+
if (!m_thread_ids.empty ())
{
tid = m_thread_ids.front ();
@@ -2742,7 +2742,7 @@ ProcessGDBRemote::RefreshStateAfterStop ()
// Let all threads recover from stopping and do any clean up based
// on the previous thread state (if any).
m_thread_list_real.RefreshStateAfterStop();
-
+
}
Error
@@ -2752,7 +2752,7 @@ ProcessGDBRemote::DoHalt (bool &caused_stop)
bool timed_out = false;
Mutex::Locker locker;
-
+
if (m_public_state.GetValue() == eStateAttaching)
{
// We are being asked to halt during an attach. We need to just close
@@ -2768,7 +2768,7 @@ ProcessGDBRemote::DoHalt (bool &caused_stop)
else
error.SetErrorString("unknown error sending interrupt packet");
}
-
+
caused_stop = m_gdb_comm.GetInterruptWasSent ();
}
return error;
@@ -2781,7 +2781,7 @@ ProcessGDBRemote::DoDetach(bool keep_stopped)
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
if (log)
log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped);
-
+
error = m_gdb_comm.Detach (keep_stopped);
if (log)
{
@@ -2790,7 +2790,7 @@ ProcessGDBRemote::DoDetach(bool keep_stopped)
else
log->Printf ("ProcessGDBRemote::DoDetach() detach packet send failed: %s", error.AsCString() ? error.AsCString() : "<unknown error>");
}
-
+
if (!error.Success())
return error;
@@ -2833,7 +2833,7 @@ ProcessGDBRemote::DoDestroy ()
if (!m_gdb_comm.GetThreadSuffixSupported() && m_public_state.GetValue() != eStateRunning)
{
PlatformSP platform_sp = GetTarget().GetPlatform();
-
+
// FIXME: These should be ConstStrings so we aren't doing strcmp'ing.
if (platform_sp
&& platform_sp->GetName()
@@ -2845,18 +2845,18 @@ ProcessGDBRemote::DoDestroy ()
log->PutCString ("ProcessGDBRemote::DoDestroy() - Tried resuming to destroy once already, not doing it again.");
}
else
- {
+ {
// At present, the plans are discarded and the breakpoints disabled Process::Destroy,
// but we really need it to happen here and it doesn't matter if we do it twice.
m_thread_list.DiscardThreadPlans();
DisableAllBreakpointSites();
-
+
bool stop_looks_like_crash = false;
ThreadList &threads = GetThreadList();
-
+
{
Mutex::Locker locker(threads.GetMutex());
-
+
size_t num_threads = threads.GetSize();
for (size_t i = 0; i < num_threads; i++)
{
@@ -2877,21 +2877,21 @@ ProcessGDBRemote::DoDestroy ()
}
}
}
-
+
if (stop_looks_like_crash)
{
if (log)
log->PutCString ("ProcessGDBRemote::DoDestroy() - Stopped at a breakpoint, continue and then kill.");
m_destroy_tried_resuming = true;
-
- // If we are going to run again before killing, it would be good to suspend all the threads
+
+ // If we are going to run again before killing, it would be good to suspend all the threads
// before resuming so they won't get into more trouble. Sadly, for the threads stopped with
// the breakpoint or exception, the exception doesn't get cleared if it is suspended, so we do
// have to run the risk of letting those threads proceed a bit.
-
+
{
Mutex::Locker locker(threads.GetMutex());
-
+
size_t num_threads = threads.GetSize();
for (size_t i = 0; i < num_threads; i++)
{
@@ -2916,7 +2916,7 @@ ProcessGDBRemote::DoDestroy ()
}
}
}
-
+
// Interrupt if our inferior is running...
int exit_status = SIGABRT;
std::string exit_string;
@@ -3098,7 +3098,7 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro
if (size > m_max_memory_size)
{
// Keep memory read sizes down to a sane limit. This function will be
- // called multiple times in order to complete the task by
+ // called multiple times in order to complete the task by
// lldb_private::Process so it is ok to do this.
size = m_max_memory_size;
}
@@ -3156,7 +3156,7 @@ ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Erro
if (size > m_max_memory_size)
{
// Keep memory read sizes down to a sane limit. This function will be
- // called multiple times in order to complete the task by
+ // called multiple times in order to complete the task by
// lldb_private::Process so it is ok to do this.
size = m_max_memory_size;
}
@@ -3191,7 +3191,7 @@ ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &er
{
Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS));
addr_t allocated_addr = LLDB_INVALID_ADDRESS;
-
+
LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
switch (supported)
{
@@ -3222,7 +3222,7 @@ ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &er
}
break;
}
-
+
if (allocated_addr == LLDB_INVALID_ADDRESS)
error.SetErrorStringWithFormat("unable to allocate %" PRIu64 " bytes of memory with permissions %s", (uint64_t)size, GetPermissionsAsCString (permissions));
else
@@ -3231,10 +3231,10 @@ ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &er
}
Error
-ProcessGDBRemote::GetMemoryRegionInfo (addr_t load_addr,
+ProcessGDBRemote::GetMemoryRegionInfo (addr_t load_addr,
MemoryRegionInfo &region_info)
{
-
+
Error error (m_gdb_comm.GetMemoryRegionInfo (load_addr, region_info));
return error;
}
@@ -3242,7 +3242,7 @@ ProcessGDBRemote::GetMemoryRegionInfo (addr_t load_addr,
Error
ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num)
{
-
+
Error error (m_gdb_comm.GetWatchpointSupportInfo (num));
return error;
}
@@ -3257,13 +3257,13 @@ ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num, bool& after)
Error
ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr)
{
- Error error;
+ Error error;
LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
switch (supported)
{
case eLazyBoolCalculate:
- // We should never be deallocating memory without allocating memory
+ // We should never be deallocating memory without allocating memory
// first so we should never get eLazyBoolCalculate
error.SetErrorString ("tried to deallocate memory without ever allocating memory");
break;
@@ -3272,7 +3272,7 @@ ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr)
if (!m_gdb_comm.DeallocateMemory (addr))
error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
break;
-
+
case eLazyBoolNo:
// Call munmap() to deallocate memory in the inferior..
{
@@ -3448,7 +3448,7 @@ ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site)
stoppoint_type = eBreakpointHardware;
else
stoppoint_type = eBreakpointSoftware;
-
+
if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, bp_op_size))
error.SetErrorToGenericError();
}
@@ -3554,7 +3554,7 @@ ProcessGDBRemote::DisableWatchpoint (Watchpoint *wp, bool notify)
wp->SetEnabled(false, notify);
return error;
}
-
+
if (wp->IsHardware())
{
GDBStoppointType type = GetGDBStoppointType(wp);
@@ -3565,7 +3565,7 @@ ProcessGDBRemote::DisableWatchpoint (Watchpoint *wp, bool notify)
return error;
}
else
- error.SetErrorString("sending gdb watchpoint packet failed");
+ error.SetErrorString("sending gdb watchpoint packet failed");
}
// TODO: clear software watchpoints if we implement them
}
@@ -3669,7 +3669,7 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info
if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
StartAsyncThread ();
-
+
if (error.Fail())
{
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
@@ -3678,7 +3678,7 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info
log->Printf("failed to start debugserver process: %s", error.AsCString());
return error;
}
-
+
if (m_gdb_comm.IsConnected())
{
// Finish the connection process by doing the handshake without connecting (send NULL URL)
@@ -3708,7 +3708,7 @@ ProcessGDBRemote::MonitorDebugserverProcess
// The baton is a "ProcessGDBRemote *". Now this class might be gone
// and might not exist anymore, so we need to carefully try to get the
// target for this process first since we have a race condition when
- // we are done running between getting the notice that the inferior
+ // we are done running between getting the notice that the inferior
// process has died and the debugserver that was debugging this process.
// In our test suite, we are also continually running process after
// process, so we must be very careful to make sure:
@@ -3738,7 +3738,7 @@ ProcessGDBRemote::MonitorDebugserverProcess
ProcessSP process_sp (target_sp->GetProcessSP());
// Now we have a shared pointer to the process that can't go away on us
// so we now make sure it was the same as the one passed in, and also make
- // sure that our previous "process *" didn't get deleted and have a new
+ // sure that our previous "process *" didn't get deleted and have a new
// "process *" created in its place with the same pointer. To verify this
// we make sure the process has our debugserver process ID. If we pass all
// of these tests, then we are sure that this process is the one we were
@@ -3752,7 +3752,7 @@ ProcessGDBRemote::MonitorDebugserverProcess
// If our process hasn't yet exited, debugserver might have died.
// If the process did exit, the we are reaping it.
const StateType state = process->GetState();
-
+
if (process->m_debugserver_pid != LLDB_INVALID_PROCESS_ID &&
state != eStateInvalid &&
state != eStateUnloaded &&
@@ -3828,7 +3828,7 @@ ProcessGDBRemote::StartAsyncThread ()
if (log)
log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
-
+
Mutex::Locker start_locker(m_async_thread_state_mutex);
if (!m_async_thread.IsJoinable())
{
@@ -3855,7 +3855,7 @@ ProcessGDBRemote::StopAsyncThread ()
if (m_async_thread.IsJoinable())
{
m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit);
-
+
// This will shut down the async thread.
m_gdb_comm.Disconnect(); // Disconnect from the debug server.
@@ -3972,7 +3972,7 @@ ProcessGDBRemote::AsyncThread (void *arg)
process->SetLastStopPacket (response);
process->ClearThreadIDList();
response.SetFilePos(1);
-
+
int exit_status = response.GetHexU8();
const char *desc_cstr = NULL;
StringExtractor extractor;
@@ -4091,7 +4091,7 @@ ProcessGDBRemote::AsyncThread (void *arg)
// {
// return Host::ListProcessesMatchingName (name, matches, pids);
// }
-// else
+// else
// {
// // FIXME: Implement talking to the remote debugserver.
// return 0;
@@ -4105,7 +4105,7 @@ ProcessGDBRemote::NewThreadNotifyBreakpointHit (void *baton,
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id)
{
- // I don't think I have to do anything here, just make sure I notice the new thread when it starts to
+ // I don't think I have to do anything here, just make sure I notice the new thread when it starts to
// run so I can stop it if that's what I want to do.
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log)
@@ -4148,7 +4148,7 @@ ProcessGDBRemote::StartNoticingNewThreads()
bool
ProcessGDBRemote::StopNoticingNewThreads()
-{
+{
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log && log->GetVerbose())
log->Printf ("Disabling new thread notification breakpoint.");
@@ -4158,7 +4158,7 @@ ProcessGDBRemote::StopNoticingNewThreads()
return true;
}
-
+
DynamicLoader *
ProcessGDBRemote::GetDynamicLoader ()
{
@@ -4172,9 +4172,9 @@ ProcessGDBRemote::SendEventData(const char *data)
{
int return_value;
bool was_supported;
-
+
Error error;
-
+
return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported);
if (return_value != 0)
{
@@ -4284,8 +4284,8 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_addres
// Establish the largest memory read/write payloads we should use.
// If the remote stub has a max packet size, stay under that size.
-//
-// If the remote stub's max packet size is crazy large, use a
+//
+// If the remote stub's max packet size is crazy large, use a
// reasonable largeish default.
//
// If the remote stub doesn't advertise a max packet size, use a
@@ -4398,7 +4398,7 @@ struct RegisterSetInfo
};
typedef std::map<uint32_t, RegisterSetInfo> RegisterSetMap;
-
+
struct GdbServerTargetInfo
{
std::string arch;
@@ -4407,13 +4407,13 @@ struct GdbServerTargetInfo
RegisterSetMap reg_set_map;
XMLNode feature_node;
};
-
+
bool
ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp)
{
if (!feature_node)
return false;
-
+
uint32_t cur_reg_num = 0;
uint32_t reg_offset = 0;
@@ -4443,7 +4443,7 @@ ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemot
NULL,
NULL
};
-
+
reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, &reg_name, &alt_name, &set_name, &value_regs, &invalidate_regs, &encoding_set, &format_set, &reg_info, &cur_reg_num, &reg_offset](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
if (name == "name")
{
@@ -4538,7 +4538,7 @@ ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemot
}
return true; // Keep iterating through all attributes
});
-
+
if (!gdb_type.empty() && !(encoding_set || format_set))
{
if (gdb_type.find("int") == 0)
@@ -4557,12 +4557,12 @@ ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemot
reg_info.encoding = eEncodingIEEE754;
}
}
-
+
// Only update the register set name if we didn't get a "reg_set" attribute.
// "set_name" will be empty if we didn't have a "reg_set" attribute.
if (!set_name && !gdb_group.empty())
set_name.SetCString(gdb_group.c_str());
-
+
reg_info.byte_offset = reg_offset;
assert (reg_info.byte_size != 0);
reg_offset += reg_info.byte_size;
@@ -4576,16 +4576,16 @@ ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemot
invalidate_regs.push_back(LLDB_INVALID_REGNUM);
reg_info.invalidate_regs = invalidate_regs.data();
}
-
+
++cur_reg_num;
AugmentRegisterInfoViaABI (reg_info, reg_name, abi_sp);
dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name);
-
+
return true; // Keep iterating through all "reg" elements
});
return true;
}
-
+
} // namespace {}
@@ -4617,14 +4617,14 @@ ProcessGDBRemote::GetGDBServerRegisterInfo ()
{
return false;
}
-
+
XMLDocument xml_document;
if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml"))
{
GdbServerTargetInfo target_info;
-
+
XMLNode target_node = xml_document.GetRootElement("target");
if (target_node)
{
@@ -4655,7 +4655,7 @@ ProcessGDBRemote::GetGDBServerRegisterInfo ()
node.ForEachChildElementWithName("group", [&target_info](const XMLNode &node) -> bool {
uint32_t set_id = UINT32_MAX;
RegisterSetInfo set_info;
-
+
node.ForEachAttribute([&set_id, &set_info](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
if (name == "id")
set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
@@ -4663,7 +4663,7 @@ ProcessGDBRemote::GetGDBServerRegisterInfo ()
set_info.name = ConstString(value);
return true; // Keep iterating through all attributes
});
-
+
if (set_id != UINT32_MAX)
target_info.reg_set_map[set_id] = set_info;
return true; // Keep iterating through all "group" elements
@@ -4671,12 +4671,12 @@ ProcessGDBRemote::GetGDBServerRegisterInfo ()
}
return true; // Keep iterating through all children of the target_node
});
-
+
if (feature_node)
{
ParseRegisters(feature_node, target_info, this->m_register_info, GetABI());
}
-
+
for (const auto &include : target_info.includes)
{
// request register file
@@ -4730,7 +4730,7 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
if (log)
log->Printf ("parsing: %s", raw.c_str());
XMLDocument doc;
-
+
if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml"))
return Error (0, ErrorType::eErrorTypeGeneric);
@@ -4750,7 +4750,7 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
GDBLoadedModuleInfoList::LoadedModuleInfo module;
library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
-
+
if (name == "name")
module.set_name (value.str());
else if (name == "lm")
@@ -4770,7 +4770,7 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
// the memory address of the libraries PT_DYAMIC section.
module.set_dynamic(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0));
}
-
+
return true; // Keep iterating over all properties of "library"
});
@@ -5075,7 +5075,7 @@ protected:
class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed
{
private:
-
+
public:
CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter,
@@ -5084,11 +5084,11 @@ public:
NULL)
{
}
-
+
~CommandObjectProcessGDBRemotePacketHistory ()
{
}
-
+
bool
DoExecute (Args& command, CommandReturnObject &result) override
{
@@ -5115,7 +5115,7 @@ public:
class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed
{
private:
-
+
public:
CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter,
@@ -5124,11 +5124,11 @@ public:
NULL)
{
}
-
+
~CommandObjectProcessGDBRemotePacketXferSize ()
{
}
-
+
bool
DoExecute (Args& command, CommandReturnObject &result) override
{
@@ -5162,7 +5162,7 @@ public:
class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed
{
private:
-
+
public:
CommandObjectProcessGDBRemotePacketSend(CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter,
@@ -5172,11 +5172,11 @@ public:
NULL)
{
}
-
+
~CommandObjectProcessGDBRemotePacketSend ()
{
}
-
+
bool
DoExecute (Args& command, CommandReturnObject &result) override
{
@@ -5187,7 +5187,7 @@ public:
result.SetStatus (eReturnStatusFailed);
return false;
}
-
+
ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
if (process)
{
@@ -5201,7 +5201,7 @@ public:
Stream &output_strm = result.GetOutputStream();
output_strm.Printf (" packet: %s\n", packet_cstr);
std::string &response_str = response.GetStringRef();
-
+
if (strstr(packet_cstr, "qGetProfileData") != NULL)
{
response_str = process->GetGDBRemote().HarmonizeThreadIdsForProfileData(process, response);
@@ -5220,7 +5220,7 @@ public:
class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw
{
private:
-
+
public:
CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter) :
CommandObjectRaw (interpreter,
@@ -5230,11 +5230,11 @@ public:
NULL)
{
}
-
+
~CommandObjectProcessGDBRemotePacketMonitor ()
{
}
-
+
bool
DoExecute (const char *command, CommandReturnObject &result) override
{
@@ -5244,7 +5244,7 @@ public:
result.SetStatus (eReturnStatusFailed);
return false;
}
-
+
ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
if (process)
{
@@ -5252,7 +5252,7 @@ public:
packet.PutCString("qRcmd,");
packet.PutBytesAsRawHex8(command, strlen(command));
const char *packet_cstr = packet.GetString().c_str();
-
+
bool send_async = true;
StringExtractorGDBRemote response;
process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async);
@@ -5260,7 +5260,7 @@ public:
Stream &output_strm = result.GetOutputStream();
output_strm.Printf (" packet: %s\n", packet_cstr);
const std::string &response_str = response.GetStringRef();
-
+
if (response_str.empty())
output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n");
else
@@ -5273,7 +5273,7 @@ public:
class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword
{
private:
-
+
public:
CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter) :
CommandObjectMultiword (interpreter,
@@ -5287,10 +5287,10 @@ public:
LoadSubCommand ("xfer-size", CommandObjectSP (new CommandObjectProcessGDBRemotePacketXferSize (interpreter)));
LoadSubCommand ("speed-test", CommandObjectSP (new CommandObjectProcessGDBRemoteSpeedTest (interpreter)));
}
-
+
~CommandObjectProcessGDBRemotePacket ()
{
- }
+ }
};
class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword
diff --git a/source/Plugins/Process/mach-core/CMakeLists.txt b/source/Plugins/Process/mach-core/CMakeLists.txt
new file mode 100644
index 000000000000..ac54658cf4dc
--- /dev/null
+++ b/source/Plugins/Process/mach-core/CMakeLists.txt
@@ -0,0 +1,6 @@
+include_directories(../Utility)
+
+add_lldb_library(lldbPluginProcessMachCore
+ ProcessMachCore.cpp
+ ThreadMachCore.cpp
+ )
diff --git a/source/Plugins/Process/mach-core/Makefile b/source/Plugins/Process/mach-core/Makefile
new file mode 100644
index 000000000000..6db849872267
--- /dev/null
+++ b/source/Plugins/Process/mach-core/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Process/mach-core/Makefile -----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginProcessMachCore
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/source/Plugins/Process/mach-core/ProcessMachCore.cpp
new file mode 100644
index 000000000000..b199ec606367
--- /dev/null
+++ b/source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -0,0 +1,520 @@
+//===-- ProcessMachCore.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+#include <stdlib.h>
+
+// C++ Includes
+#include "llvm/Support/MathExtras.h"
+#include <mutex>
+
+// Other libraries and framework includes
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+// Project includes
+#include "ProcessMachCore.h"
+#include "ThreadMachCore.h"
+#include "StopInfoMachException.h"
+
+// Needed for the plug-in names for the dynamic loaders.
+#include "lldb/Utility/SafeMachO.h"
+
+#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
+#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
+#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ConstString
+ProcessMachCore::GetPluginNameStatic()
+{
+ static ConstString g_name("mach-o-core");
+ return g_name;
+}
+
+const char *
+ProcessMachCore::GetPluginDescriptionStatic()
+{
+ return "Mach-O core file debugging plug-in.";
+}
+
+void
+ProcessMachCore::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessMachCore::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessMachCore::CreateInstance (lldb::TargetSP target_sp, Listener &listener, const FileSpec *crash_file)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file)
+ {
+ const size_t header_size = sizeof(llvm::MachO::mach_header);
+ lldb::DataBufferSP data_sp (crash_file->ReadFileContents(0, header_size));
+ if (data_sp && data_sp->GetByteSize() == header_size)
+ {
+ DataExtractor data(data_sp, lldb::eByteOrderLittle, 4);
+
+ lldb::offset_t data_offset = 0;
+ llvm::MachO::mach_header mach_header;
+ if (ObjectFileMachO::ParseHeader(data, &data_offset, mach_header))
+ {
+ if (mach_header.filetype == llvm::MachO::MH_CORE)
+ process_sp.reset(new ProcessMachCore (target_sp, listener, *crash_file));
+ }
+ }
+
+ }
+ return process_sp;
+}
+
+bool
+ProcessMachCore::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name)
+{
+ if (plugin_specified_by_name)
+ return true;
+
+ // For now we are just making sure the file exists for a given module
+ if (!m_core_module_sp && m_core_file.Exists())
+ {
+ // Don't add the Target's architecture to the ModuleSpec - we may be working
+ // with a core file that doesn't have the correct cpusubtype in the header
+ // but we should still try to use it - ModuleSpecList::FindMatchingModuleSpec
+ // enforces a strict arch mach.
+ ModuleSpec core_module_spec(m_core_file);
+ Error error (ModuleList::GetSharedModule (core_module_spec,
+ m_core_module_sp,
+ NULL,
+ NULL,
+ NULL));
+
+ if (m_core_module_sp)
+ {
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+ if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessMachCore constructor
+//----------------------------------------------------------------------
+ProcessMachCore::ProcessMachCore(lldb::TargetSP target_sp, Listener &listener, const FileSpec &core_file) :
+ Process (target_sp, listener),
+ m_core_aranges (),
+ m_core_module_sp (),
+ m_core_file (core_file),
+ m_dyld_addr (LLDB_INVALID_ADDRESS),
+ m_mach_kernel_addr (LLDB_INVALID_ADDRESS),
+ m_dyld_plugin_name ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessMachCore::~ProcessMachCore()
+{
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+ConstString
+ProcessMachCore::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessMachCore::GetPluginVersion()
+{
+ return 1;
+}
+
+bool
+ProcessMachCore::GetDynamicLoaderAddress (lldb::addr_t addr)
+{
+ llvm::MachO::mach_header header;
+ Error error;
+ if (DoReadMemory (addr, &header, sizeof(header), error) != sizeof(header))
+ return false;
+ if (header.magic == llvm::MachO::MH_CIGAM ||
+ header.magic == llvm::MachO::MH_CIGAM_64)
+ {
+ header.magic = llvm::ByteSwap_32(header.magic);
+ header.cputype = llvm::ByteSwap_32(header.cputype);
+ header.cpusubtype = llvm::ByteSwap_32(header.cpusubtype);
+ header.filetype = llvm::ByteSwap_32(header.filetype);
+ header.ncmds = llvm::ByteSwap_32(header.ncmds);
+ header.sizeofcmds = llvm::ByteSwap_32(header.sizeofcmds);
+ header.flags = llvm::ByteSwap_32(header.flags);
+ }
+
+ // TODO: swap header if needed...
+ //printf("0x%16.16" PRIx64 ": magic = 0x%8.8x, file_type= %u\n", vaddr, header.magic, header.filetype);
+ if (header.magic == llvm::MachO::MH_MAGIC ||
+ header.magic == llvm::MachO::MH_MAGIC_64)
+ {
+ // Check MH_EXECUTABLE to see if we can find the mach image
+ // that contains the shared library list. The dynamic loader
+ // (dyld) is what contains the list for user applications,
+ // and the mach kernel contains a global that has the list
+ // of kexts to load
+ switch (header.filetype)
+ {
+ case llvm::MachO::MH_DYLINKER:
+ //printf("0x%16.16" PRIx64 ": file_type = MH_DYLINKER\n", vaddr);
+ // Address of dyld "struct mach_header" in the core file
+ m_dyld_addr = addr;
+ return true;
+
+ case llvm::MachO::MH_EXECUTE:
+ //printf("0x%16.16" PRIx64 ": file_type = MH_EXECUTE\n", vaddr);
+ // Check MH_EXECUTABLE file types to see if the dynamic link object flag
+ // is NOT set. If it isn't, then we have a mach_kernel.
+ if ((header.flags & llvm::MachO::MH_DYLDLINK) == 0)
+ {
+ // Address of the mach kernel "struct mach_header" in the core file.
+ m_mach_kernel_addr = addr;
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessMachCore::DoLoadCore ()
+{
+ Error error;
+ if (!m_core_module_sp)
+ {
+ error.SetErrorString ("invalid core module");
+ return error;
+ }
+
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+ if (core_objfile == NULL)
+ {
+ error.SetErrorString ("invalid core object file");
+ return error;
+ }
+
+ if (core_objfile->GetNumThreadContexts() == 0)
+ {
+ error.SetErrorString ("core file doesn't contain any LC_THREAD load commands, or the LC_THREAD architecture is not supported in this lldb");
+ return error;
+ }
+
+ SectionList *section_list = core_objfile->GetSectionList();
+ if (section_list == NULL)
+ {
+ error.SetErrorString ("core file has no sections");
+ return error;
+ }
+
+ const uint32_t num_sections = section_list->GetNumSections(0);
+ if (num_sections == 0)
+ {
+ error.SetErrorString ("core file has no sections");
+ return error;
+ }
+
+ SetCanJIT(false);
+
+ llvm::MachO::mach_header header;
+ DataExtractor data (&header,
+ sizeof(header),
+ m_core_module_sp->GetArchitecture().GetByteOrder(),
+ m_core_module_sp->GetArchitecture().GetAddressByteSize());
+
+ bool ranges_are_sorted = true;
+ addr_t vm_addr = 0;
+ for (uint32_t i=0; i<num_sections; ++i)
+ {
+ Section *section = section_list->GetSectionAtIndex (i).get();
+ if (section)
+ {
+ lldb::addr_t section_vm_addr = section->GetFileAddress();
+ FileRange file_range (section->GetFileOffset(), section->GetFileSize());
+ VMRangeToFileOffset::Entry range_entry (section_vm_addr,
+ section->GetByteSize(),
+ file_range);
+
+ if (vm_addr > section_vm_addr)
+ ranges_are_sorted = false;
+ vm_addr = section->GetFileAddress();
+ VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();
+// printf ("LC_SEGMENT[%u] arange=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), frange=[0x%8.8x - 0x%8.8x)\n",
+// i,
+// range_entry.GetRangeBase(),
+// range_entry.GetRangeEnd(),
+// range_entry.data.GetRangeBase(),
+// range_entry.data.GetRangeEnd());
+
+ if (last_entry &&
+ last_entry->GetRangeEnd() == range_entry.GetRangeBase() &&
+ last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase())
+ {
+ last_entry->SetRangeEnd (range_entry.GetRangeEnd());
+ last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd());
+ //puts("combine");
+ }
+ else
+ {
+ m_core_aranges.Append(range_entry);
+ }
+ }
+ }
+ if (!ranges_are_sorted)
+ {
+ m_core_aranges.Sort();
+ }
+
+ if (m_dyld_addr == LLDB_INVALID_ADDRESS || m_mach_kernel_addr == LLDB_INVALID_ADDRESS)
+ {
+ // We need to locate the main executable in the memory ranges
+ // we have in the core file. We need to search for both a user-process dyld binary
+ // and a kernel binary in memory; we must look at all the pages in the binary so
+ // we don't miss one or the other. Step through all memory segments searching for
+ // a kernel binary and for a user process dyld -- we'll decide which to prefer
+ // later if both are present.
+
+ const size_t num_core_aranges = m_core_aranges.GetSize();
+ for (size_t i = 0;
+ i < num_core_aranges && (m_dyld_addr == LLDB_INVALID_ADDRESS || m_mach_kernel_addr == LLDB_INVALID_ADDRESS);
+ ++i)
+ {
+ const VMRangeToFileOffset::Entry *entry = m_core_aranges.GetEntryAtIndex(i);
+ lldb::addr_t section_vm_addr_start = entry->GetRangeBase();
+ lldb::addr_t section_vm_addr_end = entry->GetRangeEnd();
+ for (lldb::addr_t section_vm_addr = section_vm_addr_start;
+ section_vm_addr < section_vm_addr_end;
+ section_vm_addr += 0x1000)
+ {
+ GetDynamicLoaderAddress (section_vm_addr);
+ }
+ }
+ }
+
+ // If we found both a user-process dyld and a kernel binary, we need to decide
+ // which to prefer.
+ if (GetCorefilePreference() == eKernelCorefile)
+ {
+ if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
+ }
+ else if (m_dyld_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
+ }
+ }
+ else
+ {
+ if (m_dyld_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
+ }
+ else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
+ }
+ }
+
+ // Even if the architecture is set in the target, we need to override
+ // it to match the core file which is always single arch.
+ ArchSpec arch (m_core_module_sp->GetArchitecture());
+ if (arch.GetCore() == ArchSpec::eCore_x86_32_i486)
+ {
+ arch.SetTriple ("i386", GetTarget().GetPlatform().get());
+ }
+ if (arch.IsValid())
+ GetTarget().SetArchitecture(arch);
+
+ return error;
+}
+
+lldb_private::DynamicLoader *
+ProcessMachCore::GetDynamicLoader ()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, m_dyld_plugin_name.IsEmpty() ? NULL : m_dyld_plugin_name.GetCString()));
+ return m_dyld_ap.get();
+}
+
+bool
+ProcessMachCore::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ if (old_thread_list.GetSize(false) == 0)
+ {
+ // Make up the thread the first time this is called so we can setup our one and only
+ // core thread state.
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+
+ if (core_objfile)
+ {
+ const uint32_t num_threads = core_objfile->GetNumThreadContexts ();
+ for (lldb::tid_t tid = 0; tid < num_threads; ++tid)
+ {
+ ThreadSP thread_sp(new ThreadMachCore (*this, tid));
+ new_thread_list.AddThread (thread_sp);
+ }
+ }
+ }
+ else
+ {
+ const uint32_t num_threads = old_thread_list.GetSize(false);
+ for (uint32_t i=0; i<num_threads; ++i)
+ new_thread_list.AddThread (old_thread_list.GetThreadAtIndex (i, false));
+ }
+ return new_thread_list.GetSize(false) > 0;
+}
+
+void
+ProcessMachCore::RefreshStateAfterStop ()
+{
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_thread_list.RefreshStateAfterStop();
+ //SetThreadStopInfo (m_last_stop_packet);
+}
+
+Error
+ProcessMachCore::DoDestroy ()
+{
+ return Error();
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessMachCore::IsAlive ()
+{
+ return true;
+}
+
+bool
+ProcessMachCore::WarnBeforeDetach () const
+{
+ return false;
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessMachCore::ReadMemory (addr_t addr, void *buf, size_t size, Error &error)
+{
+ // Don't allow the caching that lldb_private::Process::ReadMemory does
+ // since in core files we have it all cached our our core file anyway.
+ return DoReadMemory (addr, buf, size, error);
+}
+
+size_t
+ProcessMachCore::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error)
+{
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+
+ if (core_objfile)
+ {
+ const VMRangeToFileOffset::Entry *core_memory_entry = m_core_aranges.FindEntryThatContains (addr);
+ if (core_memory_entry)
+ {
+ const addr_t offset = addr - core_memory_entry->GetRangeBase();
+ const addr_t bytes_left = core_memory_entry->GetRangeEnd() - addr;
+ size_t bytes_to_read = size;
+ if (bytes_to_read > bytes_left)
+ bytes_to_read = bytes_left;
+ return core_objfile->CopyData (core_memory_entry->data.GetRangeBase() + offset, bytes_to_read, buf);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("core file does not contain 0x%" PRIx64, addr);
+ }
+ }
+ return 0;
+}
+
+void
+ProcessMachCore::Clear()
+{
+ m_thread_list.Clear();
+}
+
+void
+ProcessMachCore::Initialize()
+{
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+ });
+}
+
+addr_t
+ProcessMachCore::GetImageInfoAddress()
+{
+ // If we found both a user-process dyld and a kernel binary, we need to decide
+ // which to prefer.
+ if (GetCorefilePreference() == eKernelCorefile)
+ {
+ if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS)
+ {
+ return m_mach_kernel_addr;
+ }
+ return m_dyld_addr;
+ }
+ else
+ {
+ if (m_dyld_addr != LLDB_INVALID_ADDRESS)
+ {
+ return m_dyld_addr;
+ }
+ return m_mach_kernel_addr;
+ }
+}
+
+
+lldb_private::ObjectFile *
+ProcessMachCore::GetCoreObjectFile ()
+{
+ return m_core_module_sp->GetObjectFile();
+}
diff --git a/source/Plugins/Process/mach-core/ProcessMachCore.h b/source/Plugins/Process/mach-core/ProcessMachCore.h
new file mode 100644
index 000000000000..2de0b772370c
--- /dev/null
+++ b/source/Plugins/Process/mach-core/ProcessMachCore.h
@@ -0,0 +1,164 @@
+//===-- ProcessMachCore.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_ProcessMachCore_h_
+#define liblldb_ProcessMachCore_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/Process.h"
+
+class ThreadKDP;
+
+class ProcessMachCore : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessMachCore(lldb::TargetSP target_sp,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec &core_file);
+
+ ~ProcessMachCore() override;
+
+ static lldb::ProcessSP
+ CreateInstance (lldb::TargetSP target_sp,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ bool
+ CanDebug (lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) override;
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ lldb_private::Error
+ DoLoadCore () override;
+
+ lldb_private::DynamicLoader *
+ GetDynamicLoader () override;
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ lldb_private::Error
+ DoDestroy () override;
+
+ void
+ RefreshStateAfterStop() override;
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ bool
+ IsAlive () override;
+
+ bool
+ WarnBeforeDetach () const override;
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ size_t
+ ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
+
+ size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
+
+ lldb::addr_t
+ GetImageInfoAddress () override;
+
+protected:
+ friend class ThreadMachCore;
+
+ void
+ Clear ( );
+
+ bool
+ UpdateThreadList (lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) override;
+
+ lldb_private::ObjectFile *
+ GetCoreObjectFile ();
+private:
+ bool
+ GetDynamicLoaderAddress (lldb::addr_t addr);
+
+ typedef enum CorefilePreference { eUserProcessCorefile, eKernelCorefile } CorefilePreferences;
+
+ //------------------------------------------------------------------
+ /// If a core file can be interpreted multiple ways, this establishes
+ /// which style wins.
+ ///
+ /// If a core file contains both a kernel binary and a user-process
+ /// dynamic loader, lldb needs to pick one over the other. This could
+ /// be a kernel corefile that happens to have a coyp of dyld in its
+ /// memory. Or it could be a user process coredump of lldb while doing
+ /// kernel debugging - so a copy of the kernel is in its heap. This
+ /// should become a setting so it can be over-ridden when necessary.
+ //------------------------------------------------------------------
+ CorefilePreference
+ GetCorefilePreference ()
+ {
+ // For now, if both user process and kernel binaries a present,
+ // assume this is a kernel coredump which has a copy of a user
+ // process dyld in one of its pages.
+ return eKernelCorefile;
+ }
+
+ //------------------------------------------------------------------
+ // For ProcessMachCore only
+ //------------------------------------------------------------------
+ typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
+ typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange> VMRangeToFileOffset;
+
+ VMRangeToFileOffset m_core_aranges;
+ lldb::ModuleSP m_core_module_sp;
+ lldb_private::FileSpec m_core_file;
+ lldb::addr_t m_dyld_addr;
+ lldb::addr_t m_mach_kernel_addr;
+ lldb_private::ConstString m_dyld_plugin_name;
+
+ DISALLOW_COPY_AND_ASSIGN (ProcessMachCore);
+};
+
+#endif // liblldb_ProcessMachCore_h_
diff --git a/source/Plugins/Process/mach-core/ThreadMachCore.cpp b/source/Plugins/Process/mach-core/ThreadMachCore.cpp
new file mode 100644
index 000000000000..2720c910e4d1
--- /dev/null
+++ b/source/Plugins/Process/mach-core/ThreadMachCore.cpp
@@ -0,0 +1,132 @@
+//===-- ThreadMachCore.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ThreadMachCore.h"
+
+#include "lldb/Utility/SafeMachO.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/State.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+
+#include "ProcessMachCore.h"
+//#include "RegisterContextKDP_arm.h"
+//#include "RegisterContextKDP_i386.h"
+//#include "RegisterContextKDP_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadMachCore::ThreadMachCore (Process &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_thread_name (),
+ m_dispatch_queue_name (),
+ m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS),
+ m_thread_reg_ctx_sp ()
+{
+}
+
+ThreadMachCore::~ThreadMachCore ()
+{
+ DestroyThread();
+}
+
+const char *
+ThreadMachCore::GetName ()
+{
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+void
+ThreadMachCore::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context. We don't set "force" to
+ // true because the stop reply packet might have had some register values
+ // that were expedited and these will already be copied into the register
+ // context by the time this function gets called. The KDPRegisterContext
+ // class has been made smart enough to detect when it needs to invalidate
+ // which registers are valid by putting hooks in the register read and
+ // register supply functions where they check the process stop ID and do
+ // the right thing.
+ const bool force = false;
+ GetRegisterContext()->InvalidateIfNeeded (force);
+}
+
+bool
+ThreadMachCore::ThreadIDIsValid (lldb::tid_t thread)
+{
+ return thread != 0;
+}
+
+lldb::RegisterContextSP
+ThreadMachCore::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadMachCore::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+ if (concrete_frame_idx == 0)
+ {
+ if (!m_thread_reg_ctx_sp)
+ {
+ ProcessSP process_sp (GetProcess());
+
+ ObjectFile *core_objfile = static_cast<ProcessMachCore *>(process_sp.get())->GetCoreObjectFile ();
+ if (core_objfile)
+ m_thread_reg_ctx_sp = core_objfile->GetThreadContextAtIndex (GetID(), *this);
+ }
+ reg_ctx_sp = m_thread_reg_ctx_sp;
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadMachCore::CalculateStopInfo ()
+{
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, SIGSTOP));
+ return true;
+ }
+ return false;
+}
+
+
diff --git a/source/Plugins/Process/mach-core/ThreadMachCore.h b/source/Plugins/Process/mach-core/ThreadMachCore.h
new file mode 100644
index 000000000000..25973540db16
--- /dev/null
+++ b/source/Plugins/Process/mach-core/ThreadMachCore.h
@@ -0,0 +1,91 @@
+//===-- ThreadMachCore.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_ThreadMachCore_h_
+#define liblldb_ThreadMachCore_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Thread.h"
+
+class ProcessMachCore;
+
+class ThreadMachCore : public lldb_private::Thread
+{
+public:
+ ThreadMachCore (lldb_private::Process &process,
+ lldb::tid_t tid);
+
+ ~ThreadMachCore() override;
+
+ void
+ RefreshStateAfterStop() override;
+
+ const char *
+ GetName() override;
+
+ lldb::RegisterContextSP
+ GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread);
+
+ bool
+ ShouldStop (bool &step_more);
+
+ const char *
+ GetBasicInfoAsString ();
+
+ void
+ SetName(const char *name) override
+ {
+ if (name && name[0])
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+ }
+
+ lldb::addr_t
+ GetThreadDispatchQAddr ()
+ {
+ return m_thread_dispatch_qaddr;
+ }
+
+ void
+ SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr)
+ {
+ m_thread_dispatch_qaddr = thread_dispatch_qaddr;
+ }
+
+protected:
+ friend class ProcessMachCore;
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::string m_thread_name;
+ std::string m_dispatch_queue_name;
+ lldb::addr_t m_thread_dispatch_qaddr;
+ lldb::RegisterContextSP m_thread_reg_ctx_sp;
+
+ //------------------------------------------------------------------
+ // Protected member functions.
+ //------------------------------------------------------------------
+ bool
+ CalculateStopInfo() override;
+};
+
+#endif // liblldb_ThreadMachCore_h_
diff --git a/source/Plugins/ScriptInterpreter/CMakeLists.txt b/source/Plugins/ScriptInterpreter/CMakeLists.txt
new file mode 100644
index 000000000000..dc2a27d95a31
--- /dev/null
+++ b/source/Plugins/ScriptInterpreter/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(None)
+add_subdirectory(Python)
diff --git a/source/Plugins/ScriptInterpreter/None/CMakeLists.txt b/source/Plugins/ScriptInterpreter/None/CMakeLists.txt
new file mode 100644
index 000000000000..5692d2f90710
--- /dev/null
+++ b/source/Plugins/ScriptInterpreter/None/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginScriptInterpreterNone
+ ScriptInterpreterNone.cpp
+ ) \ No newline at end of file
diff --git a/source/Plugins/ScriptInterpreter/None/Makefile b/source/Plugins/ScriptInterpreter/None/Makefile
new file mode 100644
index 000000000000..1e2523198520
--- /dev/null
+++ b/source/Plugins/ScriptInterpreter/None/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ScriptInterpreter/None/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginScriptInterpreterNone
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
new file mode 100644
index 000000000000..71f5807b6f62
--- /dev/null
+++ b/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_lldb_library(lldbPluginScriptInterpreterPython
+ PythonDataObjects.cpp
+ PythonExceptionState.cpp
+ ScriptInterpreterPython.cpp
+ )
diff --git a/source/Plugins/ScriptInterpreter/Python/Makefile b/source/Plugins/ScriptInterpreter/Python/Makefile
new file mode 100644
index 000000000000..cf605014d458
--- /dev/null
+++ b/source/Plugins/ScriptInterpreter/Python/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/ScriptInterpreter/Python/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginScriptInterpreterPython
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/SymbolFile/CMakeLists.txt b/source/Plugins/SymbolFile/CMakeLists.txt
new file mode 100644
index 000000000000..add6697389f9
--- /dev/null
+++ b/source/Plugins/SymbolFile/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(DWARF)
+add_subdirectory(Symtab)
diff --git a/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/source/Plugins/SymbolFile/DWARF/CMakeLists.txt
new file mode 100644
index 000000000000..b4658115dfeb
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/CMakeLists.txt
@@ -0,0 +1,33 @@
+add_lldb_library(lldbPluginSymbolFileDWARF
+ DIERef.cpp
+ DWARFAbbreviationDeclaration.cpp
+ DWARFASTParserClang.cpp
+ DWARFASTParserGo.cpp
+ DWARFAttribute.cpp
+ DWARFCompileUnit.cpp
+ DWARFDataExtractor.cpp
+ DWARFDebugAbbrev.cpp
+ DWARFDebugAranges.cpp
+ DWARFDebugArangeSet.cpp
+ DWARFDebugInfo.cpp
+ DWARFDebugInfoEntry.cpp
+ DWARFDebugLine.cpp
+ DWARFDebugMacro.cpp
+ DWARFDebugMacinfo.cpp
+ DWARFDebugMacinfoEntry.cpp
+ DWARFDebugPubnames.cpp
+ DWARFDebugPubnamesSet.cpp
+ DWARFDebugRanges.cpp
+ DWARFDeclContext.cpp
+ DWARFDefines.cpp
+ DWARFDIE.cpp
+ DWARFDIECollection.cpp
+ DWARFFormValue.cpp
+ HashedNameToDIE.cpp
+ LogChannelDWARF.cpp
+ NameToDIE.cpp
+ SymbolFileDWARF.cpp
+ SymbolFileDWARFDwo.cpp
+ SymbolFileDWARFDebugMap.cpp
+ UniqueDWARFASTType.cpp
+ )
diff --git a/source/Plugins/SymbolFile/DWARF/Makefile b/source/Plugins/SymbolFile/DWARF/Makefile
new file mode 100644
index 000000000000..509065650ab9
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/SymbolFile/DWARF/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginSymbolFileDWARF
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
index 775bb6718b8a..fe02adbb6c87 100644
--- a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
+++ b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
@@ -69,7 +69,7 @@ NameToDIE::Dump (Stream *s)
{
const char *cstr = m_map.GetCStringAtIndex(i);
const DIERef& die_ref = m_map.GetValueAtIndexUnchecked(i);
- s->Printf("%p: {0x%8.8x/0x%8.8x} \"%s\"\n", cstr, die_ref.cu_offset, die_ref.die_offset, cstr);
+ s->Printf("%p: {0x%8.8x/0x%8.8x} \"%s\"\n", (const void*) cstr, die_ref.cu_offset, die_ref.die_offset, cstr);
}
}
diff --git a/source/Plugins/SymbolFile/Symtab/CMakeLists.txt b/source/Plugins/SymbolFile/Symtab/CMakeLists.txt
new file mode 100644
index 000000000000..20e406b08ab2
--- /dev/null
+++ b/source/Plugins/SymbolFile/Symtab/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginSymbolFileSymtab
+ SymbolFileSymtab.cpp
+ )
diff --git a/source/Plugins/SymbolFile/Symtab/Makefile b/source/Plugins/SymbolFile/Symtab/Makefile
new file mode 100644
index 000000000000..2c3dbb6d86ab
--- /dev/null
+++ b/source/Plugins/SymbolFile/Symtab/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/SymbolFile/Symtab/Makefile -----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginSymbolFileSymtab
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/SymbolVendor/CMakeLists.txt b/source/Plugins/SymbolVendor/CMakeLists.txt
new file mode 100644
index 000000000000..94862d588727
--- /dev/null
+++ b/source/Plugins/SymbolVendor/CMakeLists.txt
@@ -0,0 +1,5 @@
+if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ add_subdirectory(MacOSX)
+endif()
+
+add_subdirectory(ELF)
diff --git a/source/Plugins/SymbolVendor/ELF/CMakeLists.txt b/source/Plugins/SymbolVendor/ELF/CMakeLists.txt
new file mode 100644
index 000000000000..cffc2ef74597
--- /dev/null
+++ b/source/Plugins/SymbolVendor/ELF/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginSymbolVendorELF
+ SymbolVendorELF.cpp
+ )
diff --git a/source/Plugins/SymbolVendor/ELF/Makefile b/source/Plugins/SymbolVendor/ELF/Makefile
new file mode 100644
index 000000000000..47c24a2bda34
--- /dev/null
+++ b/source/Plugins/SymbolVendor/ELF/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/SymbolVendor/ELF/Makefile ---------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginSymbolVendorELF
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/SymbolVendor/MacOSX/CMakeLists.txt b/source/Plugins/SymbolVendor/MacOSX/CMakeLists.txt
new file mode 100644
index 000000000000..093766ac07d5
--- /dev/null
+++ b/source/Plugins/SymbolVendor/MacOSX/CMakeLists.txt
@@ -0,0 +1,5 @@
+include_directories(${LIBXML2_INCLUDE_DIR})
+
+add_lldb_library(lldbPluginSymbolVendorMacOSX
+ SymbolVendorMacOSX.cpp
+ )
diff --git a/source/Plugins/SymbolVendor/MacOSX/Makefile b/source/Plugins/SymbolVendor/MacOSX/Makefile
new file mode 100644
index 000000000000..9f71ad669aa0
--- /dev/null
+++ b/source/Plugins/SymbolVendor/MacOSX/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/SymbolVendor/MacOSX/Makefile ---------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginSymbolVendorMacOSX
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
new file mode 100644
index 000000000000..7d21fbc0ede4
--- /dev/null
+++ b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
@@ -0,0 +1,251 @@
+//===-- SymbolVendorMacOSX.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolVendorMacOSX.h"
+
+#include <string.h>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Host/XML.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// SymbolVendorMacOSX constructor
+//----------------------------------------------------------------------
+SymbolVendorMacOSX::SymbolVendorMacOSX(const lldb::ModuleSP &module_sp) :
+ SymbolVendor (module_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SymbolVendorMacOSX::~SymbolVendorMacOSX()
+{
+}
+
+
+static bool
+UUIDsMatch(Module *module, ObjectFile *ofile, lldb_private::Stream *feedback_strm)
+{
+ if (module && ofile)
+ {
+ // Make sure the UUIDs match
+ lldb_private::UUID dsym_uuid;
+
+ if (!ofile->GetUUID(&dsym_uuid))
+ {
+ if (feedback_strm)
+ {
+ feedback_strm->PutCString("warning: failed to get the uuid for object file: '");
+ ofile->GetFileSpec().Dump(feedback_strm);
+ feedback_strm->PutCString("\n");
+ }
+ return false;
+ }
+
+ if (dsym_uuid == module->GetUUID())
+ return true;
+
+ // Emit some warning messages since the UUIDs do not match!
+ if (feedback_strm)
+ {
+ feedback_strm->PutCString("warning: UUID mismatch detected between modules:\n ");
+ module->GetUUID().Dump(feedback_strm);
+ feedback_strm->PutChar(' ');
+ module->GetFileSpec().Dump(feedback_strm);
+ feedback_strm->PutCString("\n ");
+ dsym_uuid.Dump(feedback_strm);
+ feedback_strm->PutChar(' ');
+ ofile->GetFileSpec().Dump(feedback_strm);
+ feedback_strm->EOL();
+ }
+ }
+ return false;
+}
+
+void
+SymbolVendorMacOSX::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolVendorMacOSX::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+SymbolVendorMacOSX::GetPluginNameStatic()
+{
+ static ConstString g_name("macosx");
+ return g_name;
+}
+
+const char *
+SymbolVendorMacOSX::GetPluginDescriptionStatic()
+{
+ return "Symbol vendor for MacOSX that looks for dSYM files that match executables.";
+}
+
+
+
+//----------------------------------------------------------------------
+// CreateInstance
+//
+// Platforms can register a callback to use when creating symbol
+// vendors to allow for complex debug information file setups, and to
+// also allow for finding separate debug information files.
+//----------------------------------------------------------------------
+SymbolVendor*
+SymbolVendorMacOSX::CreateInstance (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm)
+{
+ if (!module_sp)
+ return NULL;
+
+ ObjectFile * obj_file = module_sp->GetObjectFile();
+ if (!obj_file)
+ return NULL;
+
+ static ConstString obj_file_macho("mach-o");
+ ConstString obj_name = obj_file->GetPluginName();
+ if (obj_name != obj_file_macho)
+ return NULL;
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolVendorMacOSX::CreateInstance (module = %s)",
+ module_sp->GetFileSpec().GetPath().c_str());
+ SymbolVendorMacOSX* symbol_vendor = new SymbolVendorMacOSX(module_sp);
+ if (symbol_vendor)
+ {
+ char path[PATH_MAX];
+ path[0] = '\0';
+
+ // Try and locate the dSYM file on Mac OS X
+ Timer scoped_timer2 ("SymbolVendorMacOSX::CreateInstance () locate dSYM",
+ "SymbolVendorMacOSX::CreateInstance (module = %s) locate dSYM",
+ module_sp->GetFileSpec().GetPath().c_str());
+
+ // First check to see if the module has a symbol file in mind already.
+ // If it does, then we MUST use that.
+ FileSpec dsym_fspec (module_sp->GetSymbolFileFileSpec());
+
+ ObjectFileSP dsym_objfile_sp;
+ if (!dsym_fspec)
+ {
+ // No symbol file was specified in the module, lets try and find
+ // one ourselves.
+ FileSpec file_spec = obj_file->GetFileSpec();
+ if (!file_spec)
+ file_spec = module_sp->GetFileSpec();
+
+ ModuleSpec module_spec(file_spec, module_sp->GetArchitecture());
+ module_spec.GetUUID() = module_sp->GetUUID();
+ dsym_fspec = Symbols::LocateExecutableSymbolFile (module_spec);
+ if (module_spec.GetSourceMappingList().GetSize())
+ module_sp->GetSourceMappingList().Append (module_spec.GetSourceMappingList (), true);
+ }
+
+ if (dsym_fspec)
+ {
+ DataBufferSP dsym_file_data_sp;
+ lldb::offset_t dsym_file_data_offset = 0;
+ dsym_objfile_sp = ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), dsym_file_data_sp, dsym_file_data_offset);
+ if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm))
+ {
+ // We need a XML parser if we hope to parse a plist...
+ if (XMLDocument::XMLEnabled())
+ {
+ char dsym_path[PATH_MAX];
+ if (module_sp->GetSourceMappingList().IsEmpty() && dsym_fspec.GetPath(dsym_path, sizeof(dsym_path)))
+ {
+ lldb_private::UUID dsym_uuid;
+ if (dsym_objfile_sp->GetUUID(&dsym_uuid))
+ {
+ std::string uuid_str = dsym_uuid.GetAsString ();
+ if (!uuid_str.empty())
+ {
+ char *resources = strstr (dsym_path, "/Contents/Resources/");
+ if (resources)
+ {
+ char dsym_uuid_plist_path[PATH_MAX];
+ resources[strlen("/Contents/Resources/")] = '\0';
+ snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), "%s%s.plist", dsym_path, uuid_str.c_str());
+ FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path, false);
+ if (dsym_uuid_plist_spec.Exists())
+ {
+ ApplePropertyList plist(dsym_uuid_plist_path);
+ if (plist)
+ {
+ std::string DBGBuildSourcePath;
+ std::string DBGSourcePath;
+
+ plist.GetValueAsString("DBGBuildSourcePath", DBGBuildSourcePath);
+ plist.GetValueAsString("DBGSourcePath", DBGSourcePath);
+ if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty())
+ {
+ if (DBGSourcePath[0] == '~')
+ {
+ FileSpec resolved_source_path(DBGSourcePath.c_str(), true);
+ DBGSourcePath = resolved_source_path.GetPath();
+ }
+ module_sp->GetSourceMappingList().Append (ConstString(DBGBuildSourcePath), ConstString(DBGSourcePath), true);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp);
+ return symbol_vendor;
+ }
+ }
+
+ // Just create our symbol vendor using the current objfile as this is either
+ // an executable with no dSYM (that we could locate), an executable with
+ // a dSYM that has a UUID that doesn't match.
+ symbol_vendor->AddSymbolFileRepresentation(obj_file->shared_from_this());
+ }
+ return symbol_vendor;
+}
+
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+SymbolVendorMacOSX::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolVendorMacOSX::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h
new file mode 100644
index 000000000000..31a842ade86f
--- /dev/null
+++ b/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h
@@ -0,0 +1,58 @@
+//===-- SymbolVendorMacOSX.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_SymbolVendorMacOSX_h_
+#define liblldb_SymbolVendorMacOSX_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+class SymbolVendorMacOSX : public lldb_private::SymbolVendor
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolVendor*
+ CreateInstance (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolVendorMacOSX (const lldb::ModuleSP &module_sp);
+
+ virtual
+ ~SymbolVendorMacOSX();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolVendorMacOSX);
+};
+
+#endif // liblldb_SymbolVendorMacOSX_h_
diff --git a/source/Plugins/SystemRuntime/CMakeLists.txt b/source/Plugins/SystemRuntime/CMakeLists.txt
new file mode 100644
index 000000000000..0955a9eb74c2
--- /dev/null
+++ b/source/Plugins/SystemRuntime/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(MacOSX)
diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp
new file mode 100644
index 000000000000..2ca367c0cce8
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp
@@ -0,0 +1,383 @@
+//===-- AppleGetItemInfoHandler.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AppleGetItemInfoHandler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/FunctionCaller.h"
+#include "lldb/Expression/UtilityFunction.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *AppleGetItemInfoHandler::g_get_item_info_function_name = "__lldb_backtrace_recording_get_item_info";
+const char *AppleGetItemInfoHandler::g_get_item_info_function_code = " \n\
+extern \"C\" \n\
+{ \n\
+ /* \n\
+ * mach defines \n\
+ */ \n\
+ \n\
+ typedef unsigned int uint32_t; \n\
+ typedef unsigned long long uint64_t; \n\
+ typedef uint32_t mach_port_t; \n\
+ typedef mach_port_t vm_map_t; \n\
+ typedef int kern_return_t; \n\
+ typedef uint64_t mach_vm_address_t; \n\
+ typedef uint64_t mach_vm_size_t; \n\
+ \n\
+ mach_port_t mach_task_self (); \n\
+ kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); \n\
+ \n\
+ /* \n\
+ * libBacktraceRecording defines \n\
+ */ \n\
+ \n\
+ typedef uint32_t queue_list_scope_t; \n\
+ typedef void *dispatch_queue_t; \n\
+ typedef void *introspection_dispatch_queue_info_t; \n\
+ typedef void *introspection_dispatch_item_info_ref; \n\
+ \n\
+ extern uint64_t __introspection_dispatch_queue_item_get_info (introspection_dispatch_item_info_ref item_info_ref, \n\
+ introspection_dispatch_item_info_ref *returned_queues_buffer, \n\
+ uint64_t *returned_queues_buffer_size); \n\
+ extern int printf(const char *format, ...); \n\
+ \n\
+ /* \n\
+ * return type define \n\
+ */ \n\
+ \n\
+ struct get_item_info_return_values \n\
+ { \n\
+ uint64_t item_info_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */ \n\
+ uint64_t item_info_buffer_size; /* the size of the items buffer from libBacktraceRecording */ \n\
+ }; \n\
+ \n\
+ void __lldb_backtrace_recording_get_item_info \n\
+ (struct get_item_info_return_values *return_buffer, \n\
+ int debug, \n\
+ uint64_t /* introspection_dispatch_item_info_ref item_info_ref */ item, \n\
+ void *page_to_free, \n\
+ uint64_t page_to_free_size) \n\
+{ \n\
+ if (debug) \n\
+ printf (\"entering get_item_info with args return_buffer == %p, debug == %d, item == 0x%llx, page_to_free == %p, page_to_free_size == 0x%llx\\n\", return_buffer, debug, item, page_to_free, page_to_free_size); \n\
+ if (page_to_free != 0) \n\
+ { \n\
+ mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\
+ } \n\
+ \n\
+ __introspection_dispatch_queue_item_get_info ((void*) item, \n\
+ (void**)&return_buffer->item_info_buffer_ptr, \n\
+ &return_buffer->item_info_buffer_size); \n\
+} \n\
+} \n\
+";
+
+AppleGetItemInfoHandler::AppleGetItemInfoHandler (Process *process) :
+ m_process (process),
+ m_get_item_info_impl_code (),
+ m_get_item_info_function_mutex(),
+ m_get_item_info_return_buffer_addr (LLDB_INVALID_ADDRESS),
+ m_get_item_info_retbuffer_mutex()
+{
+}
+
+AppleGetItemInfoHandler::~AppleGetItemInfoHandler ()
+{
+}
+
+void
+AppleGetItemInfoHandler::Detach ()
+{
+
+ if (m_process && m_process->IsAlive() && m_get_item_info_return_buffer_addr != LLDB_INVALID_ADDRESS)
+ {
+ Mutex::Locker locker;
+ locker.TryLock (m_get_item_info_retbuffer_mutex); // Even if we don't get the lock, deallocate the buffer
+ m_process->DeallocateMemory (m_get_item_info_return_buffer_addr);
+ }
+}
+
+// Compile our __lldb_backtrace_recording_get_item_info() function (from the
+// source above in g_get_item_info_function_code) if we don't find that function in the inferior
+// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for testing.)
+//
+// Insert the __lldb_backtrace_recording_get_item_info into the inferior process if needed.
+//
+// Write the get_item_info_arglist into the inferior's memory space to prepare for the call.
+//
+// Returns the address of the arguments written down in the inferior process, which can be used to
+// make the function call.
+
+lldb::addr_t
+AppleGetItemInfoHandler::SetupGetItemInfoFunction (Thread &thread, ValueList &get_item_info_arglist)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ StreamString errors;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+ FunctionCaller *get_item_info_caller = nullptr;
+
+ // Scope for mutex locker:
+ {
+ Mutex::Locker locker(m_get_item_info_function_mutex);
+
+ // First stage is to make the UtilityFunction to hold our injected function:
+
+ if (!m_get_item_info_impl_code.get())
+ {
+ if (g_get_item_info_function_code != NULL)
+ {
+ Error error;
+ m_get_item_info_impl_code.reset(exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage (g_get_item_info_function_code,
+ eLanguageTypeObjC,
+ g_get_item_info_function_name,
+ error));
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("Failed to get utility function: %s.", error.AsCString());
+ return args_addr;
+ }
+
+ if (!m_get_item_info_impl_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install get-item-info introspection: %s.", errors.GetData());
+ m_get_item_info_impl_code.reset();
+ return args_addr;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("No get-item-info introspection code found.");
+ errors.Printf ("No get-item-info introspection code found.");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // Next make the runner function for our implementation utility function.
+ Error error;
+
+ TypeSystem *type_system = thread.GetProcess()->GetTarget().GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC);
+ CompilerType get_item_info_return_type = type_system->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType();
+
+ get_item_info_caller = m_get_item_info_impl_code->MakeFunctionCaller(get_item_info_return_type,
+ get_item_info_arglist,
+ error);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("Error Inserting get-item-info function: \"%s\".", error.AsCString());
+ return args_addr;
+ }
+ }
+ else
+ {
+ // If it's already made, then we can just retrieve the caller:
+ get_item_info_caller = m_get_item_info_impl_code->GetFunctionCaller();
+ if (!get_item_info_caller)
+ {
+ if (log)
+ log->Printf ("Failed to get get-item-info introspection caller.");
+ m_get_item_info_impl_code.reset();
+ return args_addr;
+ }
+ }
+ }
+
+ errors.Clear();
+
+ // Now write down the argument values for this particular call. This looks like it might be a race condition
+ // if other threads were calling into here, but actually it isn't because we allocate a new args structure for
+ // this call by passing args_addr = LLDB_INVALID_ADDRESS...
+
+ if (!get_item_info_caller->WriteFunctionArguments (exe_ctx, args_addr, get_item_info_arglist, errors))
+ {
+ if (log)
+ log->Printf ("Error writing get-item-info function arguments: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ return args_addr;
+}
+
+AppleGetItemInfoHandler::GetItemInfoReturnInfo
+AppleGetItemInfoHandler::GetItemInfo (Thread &thread, uint64_t item, addr_t page_to_free, uint64_t page_to_free_size, Error &error)
+{
+ lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
+ ProcessSP process_sp (thread.CalculateProcess());
+ TargetSP target_sp (thread.CalculateTarget());
+ ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+
+ GetItemInfoReturnInfo return_value;
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return_value.item_buffer_size = 0;
+
+ error.Clear();
+
+ if (thread.SafeToCallFunctions() == false)
+ {
+ if (log)
+ log->Printf ("Not safe to call functions on thread 0x%" PRIx64, thread.GetID());
+ error.SetErrorString ("Not safe to call functions on this thread.");
+ return return_value;
+ }
+
+ // Set up the arguments for a call to
+
+ // struct get_item_info_return_values
+ // {
+ // uint64_t item_info_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */
+ // uint64_t item_info_buffer_size; /* the size of the items buffer from libBacktraceRecording */
+ // };
+ //
+ // void __lldb_backtrace_recording_get_item_info
+ // (struct get_item_info_return_values *return_buffer,
+ // int debug,
+ // uint64_t item,
+ // void *page_to_free,
+ // uint64_t page_to_free_size)
+
+ // Where the return_buffer argument points to a 24 byte region of memory already allocated by lldb in
+ // the inferior process.
+
+ CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ Value return_buffer_ptr_value;
+ return_buffer_ptr_value.SetValueType (Value::eValueTypeScalar);
+ return_buffer_ptr_value.SetCompilerType (clang_void_ptr_type);
+
+ CompilerType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt);
+ Value debug_value;
+ debug_value.SetValueType (Value::eValueTypeScalar);
+ debug_value.SetCompilerType (clang_int_type);
+
+ CompilerType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong);
+ Value item_value;
+ item_value.SetValueType (Value::eValueTypeScalar);
+ item_value.SetCompilerType (clang_uint64_type);
+
+ Value page_to_free_value;
+ page_to_free_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_value.SetCompilerType (clang_void_ptr_type);
+
+ Value page_to_free_size_value;
+ page_to_free_size_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_size_value.SetCompilerType (clang_uint64_type);
+
+
+ Mutex::Locker locker(m_get_item_info_retbuffer_mutex);
+ if (m_get_item_info_return_buffer_addr == LLDB_INVALID_ADDRESS)
+ {
+ addr_t bufaddr = process_sp->AllocateMemory (32, ePermissionsReadable | ePermissionsWritable, error);
+ if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("Failed to allocate memory for return buffer for get current queues func call");
+ return return_value;
+ }
+ m_get_item_info_return_buffer_addr = bufaddr;
+ }
+
+ ValueList argument_values;
+
+ return_buffer_ptr_value.GetScalar() = m_get_item_info_return_buffer_addr;
+ argument_values.PushValue (return_buffer_ptr_value);
+
+ debug_value.GetScalar() = 0;
+ argument_values.PushValue (debug_value);
+
+ item_value.GetScalar() = item;
+ argument_values.PushValue (item_value);
+
+ if (page_to_free != LLDB_INVALID_ADDRESS)
+ page_to_free_value.GetScalar() = page_to_free;
+ else
+ page_to_free_value.GetScalar() = 0;
+ argument_values.PushValue (page_to_free_value);
+
+ page_to_free_size_value.GetScalar() = page_to_free_size;
+ argument_values.PushValue (page_to_free_size_value);
+
+ addr_t args_addr = SetupGetItemInfoFunction (thread, argument_values);
+
+ StreamString errors;
+ ExecutionContext exe_ctx;
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError (true);
+ options.SetIgnoreBreakpoints (true);
+ options.SetStopOthers (true);
+ options.SetTimeoutUsec(500000);
+ options.SetTryAllThreads (false);
+ thread.CalculateExecutionContext (exe_ctx);
+
+ if (!m_get_item_info_impl_code)
+ {
+ error.SetErrorString ("Unable to compile function to call __introspection_dispatch_queue_item_get_info");
+ return return_value;
+ }
+
+
+ ExpressionResults func_call_ret;
+ Value results;
+ FunctionCaller *func_caller = m_get_item_info_impl_code->GetFunctionCaller();
+ if (!func_caller)
+ {
+ if (log)
+ log->Printf ("Could not retrieve function caller for __introspection_dispatch_queue_item_get_info.");
+ error.SetErrorString("Could not retrieve function caller for __introspection_dispatch_queue_item_get_info.");
+ return return_value;
+ }
+
+ func_call_ret = func_caller->ExecuteFunction (exe_ctx, &args_addr, options, errors, results);
+ if (func_call_ret != eExpressionCompleted || !error.Success())
+ {
+ if (log)
+ log->Printf ("Unable to call __introspection_dispatch_queue_item_get_info(), got ExpressionResults %d, error contains %s", func_call_ret, error.AsCString(""));
+ error.SetErrorString ("Unable to call __introspection_dispatch_queue_get_item_info() for list of queues");
+ return return_value;
+ }
+
+ return_value.item_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory (m_get_item_info_return_buffer_addr, 8, LLDB_INVALID_ADDRESS, error);
+ if (!error.Success() || return_value.item_buffer_ptr == LLDB_INVALID_ADDRESS)
+ {
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.item_buffer_size = m_process->ReadUnsignedIntegerFromMemory (m_get_item_info_return_buffer_addr + 8, 8, 0, error);
+
+ if (!error.Success())
+ {
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+ if (log)
+ log->Printf ("AppleGetItemInfoHandler called __introspection_dispatch_queue_item_get_info (page_to_free == 0x%" PRIx64 ", size = %" PRId64 "), returned page is at 0x%" PRIx64 ", size %" PRId64, page_to_free, page_to_free_size, return_value.item_buffer_ptr, return_value.item_buffer_size);
+
+
+ return return_value;
+}
diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h b/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h
new file mode 100644
index 000000000000..51182a624939
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h
@@ -0,0 +1,117 @@
+//===-- AppleGetItemInfoHandler.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_AppleGetItemInfoHandler_h_
+#define lldb_AppleGetItemInfoHandler_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Expression/UtilityFunction.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/CompilerType.h"
+
+// This class will insert a UtilityFunction into the inferior process for
+// calling libBacktraceRecording's __introspection_dispatch_queue_item_get_info()
+// function. The function in the inferior will return a struct by value
+// with these members:
+//
+// struct get_item_info_return_values
+// {
+// introspection_dispatch_item_info_ref *item_buffer;
+// uint64_t item_buffer_size;
+// };
+//
+// The item_buffer pointer is an address in the inferior program's address
+// space (item_buffer_size in size) which must be mach_vm_deallocate'd by
+// lldb.
+//
+// The AppleGetItemInfoHandler object should persist so that the UtilityFunction
+// can be reused multiple times.
+
+namespace lldb_private
+{
+
+class AppleGetItemInfoHandler {
+public:
+
+ AppleGetItemInfoHandler (lldb_private::Process *process);
+
+ ~AppleGetItemInfoHandler();
+
+ struct GetItemInfoReturnInfo
+ {
+ lldb::addr_t item_buffer_ptr; /* the address of the item buffer from libBacktraceRecording */
+ lldb::addr_t item_buffer_size; /* the size of the item buffer from libBacktraceRecording */
+
+ GetItemInfoReturnInfo() :
+ item_buffer_ptr(LLDB_INVALID_ADDRESS),
+ item_buffer_size(0)
+ {}
+ };
+
+ //----------------------------------------------------------
+ /// Get the information about a work item by calling
+ /// __introspection_dispatch_queue_item_get_info. If there's a page of
+ /// memory that needs to be freed, pass in the address and size and it will
+ /// be freed before getting the list of queues.
+ ///
+ /// @param [in] thread
+ /// The thread to run this plan on.
+ ///
+ /// @param [in] item
+ /// The introspection_dispatch_item_info_ref value for the item of interest.
+ ///
+ /// @param [in] page_to_free
+ /// An address of an inferior process vm page that needs to be deallocated,
+ /// LLDB_INVALID_ADDRESS if this is not needed.
+ ///
+ /// @param [in] page_to_free_size
+ /// The size of the vm page that needs to be deallocated if an address was
+ /// passed in to page_to_free.
+ ///
+ /// @param [out] error
+ /// This object will be updated with the error status / error string from any failures encountered.
+ ///
+ /// @returns
+ /// The result of the inferior function call execution. If there was a failure of any kind while getting
+ /// the information, the item_buffer_ptr value will be LLDB_INVALID_ADDRESS.
+ //----------------------------------------------------------
+ GetItemInfoReturnInfo
+ GetItemInfo (Thread &thread, lldb::addr_t item, lldb::addr_t page_to_free, uint64_t page_to_free_size, lldb_private::Error &error);
+
+
+ void
+ Detach ();
+
+private:
+
+ lldb::addr_t
+ SetupGetItemInfoFunction (Thread &thread, ValueList &get_item_info_arglist);
+
+ static const char *g_get_item_info_function_name;
+ static const char *g_get_item_info_function_code;
+
+ lldb_private::Process *m_process;
+ std::unique_ptr<UtilityFunction> m_get_item_info_impl_code;
+ Mutex m_get_item_info_function_mutex;
+
+ lldb::addr_t m_get_item_info_return_buffer_addr;
+ Mutex m_get_item_info_retbuffer_mutex;
+
+};
+
+} // using namespace lldb_private
+
+#endif // lldb_AppleGetItemInfoHandler_h_
diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp
new file mode 100644
index 000000000000..97699878f5ee
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp
@@ -0,0 +1,383 @@
+//===-- AppleGetPendingItemsHandler.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AppleGetPendingItemsHandler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/FunctionCaller.h"
+#include "lldb/Expression/UtilityFunction.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *AppleGetPendingItemsHandler::g_get_pending_items_function_name = "__lldb_backtrace_recording_get_pending_items";
+const char *AppleGetPendingItemsHandler::g_get_pending_items_function_code = " \n\
+extern \"C\" \n\
+{ \n\
+ /* \n\
+ * mach defines \n\
+ */ \n\
+ \n\
+ typedef unsigned int uint32_t; \n\
+ typedef unsigned long long uint64_t; \n\
+ typedef uint32_t mach_port_t; \n\
+ typedef mach_port_t vm_map_t; \n\
+ typedef int kern_return_t; \n\
+ typedef uint64_t mach_vm_address_t; \n\
+ typedef uint64_t mach_vm_size_t; \n\
+ \n\
+ mach_port_t mach_task_self (); \n\
+ kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); \n\
+ \n\
+ /* \n\
+ * libBacktraceRecording defines \n\
+ */ \n\
+ \n\
+ typedef uint32_t queue_list_scope_t; \n\
+ typedef void *dispatch_queue_t; \n\
+ typedef void *introspection_dispatch_queue_info_t; \n\
+ typedef void *introspection_dispatch_item_info_ref; \n\
+ \n\
+ extern uint64_t __introspection_dispatch_queue_get_pending_items (dispatch_queue_t queue, \n\
+ introspection_dispatch_item_info_ref *returned_queues_buffer, \n\
+ uint64_t *returned_queues_buffer_size); \n\
+ extern int printf(const char *format, ...); \n\
+ \n\
+ /* \n\
+ * return type define \n\
+ */ \n\
+ \n\
+ struct get_pending_items_return_values \n\
+ { \n\
+ uint64_t pending_items_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */ \n\
+ uint64_t pending_items_buffer_size; /* the size of the items buffer from libBacktraceRecording */ \n\
+ uint64_t count; /* the number of items included in the queues buffer */ \n\
+ }; \n\
+ \n\
+ void __lldb_backtrace_recording_get_pending_items \n\
+ (struct get_pending_items_return_values *return_buffer, \n\
+ int debug, \n\
+ uint64_t /* dispatch_queue_t */ queue, \n\
+ void *page_to_free, \n\
+ uint64_t page_to_free_size) \n\
+{ \n\
+ if (debug) \n\
+ printf (\"entering get_pending_items with args return_buffer == %p, debug == %d, queue == 0x%llx, page_to_free == %p, page_to_free_size == 0x%llx\\n\", return_buffer, debug, queue, page_to_free, page_to_free_size); \n\
+ if (page_to_free != 0) \n\
+ { \n\
+ mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\
+ } \n\
+ \n\
+ return_buffer->count = __introspection_dispatch_queue_get_pending_items ( \n\
+ (void*) queue, \n\
+ (void**)&return_buffer->pending_items_buffer_ptr, \n\
+ &return_buffer->pending_items_buffer_size); \n\
+ if (debug) \n\
+ printf(\"result was count %lld\\n\", return_buffer->count); \n\
+} \n\
+} \n\
+";
+
+AppleGetPendingItemsHandler::AppleGetPendingItemsHandler (Process *process) :
+ m_process (process),
+ m_get_pending_items_impl_code (),
+ m_get_pending_items_function_mutex(),
+ m_get_pending_items_return_buffer_addr (LLDB_INVALID_ADDRESS),
+ m_get_pending_items_retbuffer_mutex()
+{
+}
+
+AppleGetPendingItemsHandler::~AppleGetPendingItemsHandler ()
+{
+}
+
+void
+AppleGetPendingItemsHandler::Detach ()
+{
+
+ if (m_process && m_process->IsAlive() && m_get_pending_items_return_buffer_addr != LLDB_INVALID_ADDRESS)
+ {
+ Mutex::Locker locker;
+ locker.TryLock (m_get_pending_items_retbuffer_mutex); // Even if we don't get the lock, deallocate the buffer
+ m_process->DeallocateMemory (m_get_pending_items_return_buffer_addr);
+ }
+}
+
+// Compile our __lldb_backtrace_recording_get_pending_items() function (from the
+// source above in g_get_pending_items_function_code) if we don't find that function in the inferior
+// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for testing.)
+//
+// Insert the __lldb_backtrace_recording_get_pending_items into the inferior process if needed.
+//
+// Write the get_pending_items_arglist into the inferior's memory space to prepare for the call.
+//
+// Returns the address of the arguments written down in the inferior process, which can be used to
+// make the function call.
+
+lldb::addr_t
+AppleGetPendingItemsHandler::SetupGetPendingItemsFunction (Thread &thread, ValueList &get_pending_items_arglist)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ StreamString errors;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+ FunctionCaller *get_pending_items_caller = nullptr;
+
+ // Scope for mutex locker:
+ {
+ Mutex::Locker locker(m_get_pending_items_function_mutex);
+
+ // First stage is to make the ClangUtility to hold our injected function:
+
+ if (!m_get_pending_items_impl_code.get())
+ {
+ if (g_get_pending_items_function_code != NULL)
+ {
+ Error error;
+ m_get_pending_items_impl_code.reset (exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(g_get_pending_items_function_code,
+ eLanguageTypeObjC,
+ g_get_pending_items_function_name,
+ error));
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("Failed to get UtilityFunction for pending-items introspection: %s.", error.AsCString());
+ return args_addr;
+ }
+
+ if (!m_get_pending_items_impl_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install pending-items introspection: %s.", errors.GetData());
+ m_get_pending_items_impl_code.reset();
+ return args_addr;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("No pending-items introspection code found.");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // Next make the runner function for our implementation utility function.
+ Error error;
+ ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext();
+ CompilerType get_pending_items_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ get_pending_items_caller = m_get_pending_items_impl_code->MakeFunctionCaller (get_pending_items_return_type,
+ get_pending_items_arglist,
+ error);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("Failed to install pending-items introspection function caller: %s.", error.AsCString());
+ m_get_pending_items_impl_code.reset();
+ return args_addr;
+ }
+ }
+
+ }
+
+ errors.Clear();
+
+ if (get_pending_items_caller == nullptr)
+ {
+ if (log)
+ log->Printf ("Failed to get get_pending_items_caller.");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // Now write down the argument values for this particular call. This looks like it might be a race condition
+ // if other threads were calling into here, but actually it isn't because we allocate a new args structure for
+ // this call by passing args_addr = LLDB_INVALID_ADDRESS...
+
+ if (!get_pending_items_caller->WriteFunctionArguments (exe_ctx, args_addr, get_pending_items_arglist, errors))
+ {
+ if (log)
+ log->Printf ("Error writing pending-items function arguments: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ return args_addr;
+}
+
+AppleGetPendingItemsHandler::GetPendingItemsReturnInfo
+AppleGetPendingItemsHandler::GetPendingItems (Thread &thread, addr_t queue, addr_t page_to_free, uint64_t page_to_free_size, Error &error)
+{
+ lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
+ ProcessSP process_sp (thread.CalculateProcess());
+ TargetSP target_sp (thread.CalculateTarget());
+ ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+
+ GetPendingItemsReturnInfo return_value;
+ return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return_value.items_buffer_size = 0;
+ return_value.count = 0;
+
+ error.Clear();
+
+ if (thread.SafeToCallFunctions() == false)
+ {
+ if (log)
+ log->Printf ("Not safe to call functions on thread 0x%" PRIx64, thread.GetID());
+ error.SetErrorString ("Not safe to call functions on this thread.");
+ return return_value;
+ }
+
+ // Set up the arguments for a call to
+
+ // struct get_pending_items_return_values
+ // {
+ // uint64_t pending_items_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */
+ // uint64_t pending_items_buffer_size; /* the size of the items buffer from libBacktraceRecording */
+ // uint64_t count; /* the number of items included in the queues buffer */
+ // };
+ //
+ // void __lldb_backtrace_recording_get_pending_items
+ // (struct get_pending_items_return_values *return_buffer,
+ // int debug,
+ // uint64_t /* dispatch_queue_t */ queue
+ // void *page_to_free,
+ // uint64_t page_to_free_size)
+
+ // Where the return_buffer argument points to a 24 byte region of memory already allocated by lldb in
+ // the inferior process.
+
+ CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ Value return_buffer_ptr_value;
+ return_buffer_ptr_value.SetValueType (Value::eValueTypeScalar);
+ return_buffer_ptr_value.SetCompilerType (clang_void_ptr_type);
+
+ CompilerType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt);
+ Value debug_value;
+ debug_value.SetValueType (Value::eValueTypeScalar);
+ debug_value.SetCompilerType (clang_int_type);
+
+ CompilerType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong);
+ Value queue_value;
+ queue_value.SetValueType (Value::eValueTypeScalar);
+ queue_value.SetCompilerType (clang_uint64_type);
+
+ Value page_to_free_value;
+ page_to_free_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_value.SetCompilerType (clang_void_ptr_type);
+
+ Value page_to_free_size_value;
+ page_to_free_size_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_size_value.SetCompilerType (clang_uint64_type);
+
+
+ Mutex::Locker locker(m_get_pending_items_retbuffer_mutex);
+ if (m_get_pending_items_return_buffer_addr == LLDB_INVALID_ADDRESS)
+ {
+ addr_t bufaddr = process_sp->AllocateMemory (32, ePermissionsReadable | ePermissionsWritable, error);
+ if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("Failed to allocate memory for return buffer for get current queues func call");
+ return return_value;
+ }
+ m_get_pending_items_return_buffer_addr = bufaddr;
+ }
+
+ ValueList argument_values;
+
+ return_buffer_ptr_value.GetScalar() = m_get_pending_items_return_buffer_addr;
+ argument_values.PushValue (return_buffer_ptr_value);
+
+ debug_value.GetScalar() = 0;
+ argument_values.PushValue (debug_value);
+
+ queue_value.GetScalar() = queue;
+ argument_values.PushValue (queue_value);
+
+ if (page_to_free != LLDB_INVALID_ADDRESS)
+ page_to_free_value.GetScalar() = page_to_free;
+ else
+ page_to_free_value.GetScalar() = 0;
+ argument_values.PushValue (page_to_free_value);
+
+ page_to_free_size_value.GetScalar() = page_to_free_size;
+ argument_values.PushValue (page_to_free_size_value);
+
+ addr_t args_addr = SetupGetPendingItemsFunction (thread, argument_values);
+
+ StreamString errors;
+ ExecutionContext exe_ctx;
+ FunctionCaller *get_pending_items_caller = m_get_pending_items_impl_code->GetFunctionCaller();
+
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError (true);
+ options.SetIgnoreBreakpoints (true);
+ options.SetStopOthers (true);
+ options.SetTimeoutUsec(500000);
+ options.SetTryAllThreads (false);
+ thread.CalculateExecutionContext (exe_ctx);
+
+ if (get_pending_items_caller == NULL)
+ {
+ error.SetErrorString ("Unable to compile function to call __introspection_dispatch_queue_get_pending_items");
+ return return_value;
+ }
+
+
+ ExpressionResults func_call_ret;
+ Value results;
+ func_call_ret = get_pending_items_caller->ExecuteFunction (exe_ctx, &args_addr, options, errors, results);
+ if (func_call_ret != eExpressionCompleted || !error.Success())
+ {
+ if (log)
+ log->Printf ("Unable to call __introspection_dispatch_queue_get_pending_items(), got ExpressionResults %d, error contains %s", func_call_ret, error.AsCString(""));
+ error.SetErrorString ("Unable to call __introspection_dispatch_queue_get_pending_items() for list of queues");
+ return return_value;
+ }
+
+ return_value.items_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory (m_get_pending_items_return_buffer_addr, 8, LLDB_INVALID_ADDRESS, error);
+ if (!error.Success() || return_value.items_buffer_ptr == LLDB_INVALID_ADDRESS)
+ {
+ return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.items_buffer_size = m_process->ReadUnsignedIntegerFromMemory (m_get_pending_items_return_buffer_addr + 8, 8, 0, error);
+
+ if (!error.Success())
+ {
+ return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.count = m_process->ReadUnsignedIntegerFromMemory (m_get_pending_items_return_buffer_addr + 16, 8, 0, error);
+ if (!error.Success())
+ {
+ return_value.items_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ if (log)
+ log->Printf ("AppleGetPendingItemsHandler called __introspection_dispatch_queue_get_pending_items (page_to_free == 0x%" PRIx64 ", size = %" PRId64 "), returned page is at 0x%" PRIx64 ", size %" PRId64 ", count = %" PRId64, page_to_free, page_to_free_size, return_value.items_buffer_ptr, return_value.items_buffer_size, return_value.count);
+
+ return return_value;
+}
diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h b/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h
new file mode 100644
index 000000000000..445c4a0fb82b
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h
@@ -0,0 +1,119 @@
+//===-- AppleGetPendingItemsHandler.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_AppleGetPendingItemsHandler_h_
+#define lldb_AppleGetPendingItemsHandler_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/CompilerType.h"
+
+// This class will insert a UtilityFunction into the inferior process for
+// calling libBacktraceRecording's __introspection_dispatch_queue_get_pending_items()
+// function. The function in the inferior will return a struct by value
+// with these members:
+//
+// struct get_pending_items_return_values
+// {
+// introspection_dispatch_item_info_ref *items_buffer;
+// uint64_t items_buffer_size;
+// uint64_t count;
+// };
+//
+// The items_buffer pointer is an address in the inferior program's address
+// space (items_buffer_size in size) which must be mach_vm_deallocate'd by
+// lldb. count is the number of items that were stored in the buffer.
+//
+// The AppleGetPendingItemsHandler object should persist so that the UtilityFunction
+// can be reused multiple times.
+
+namespace lldb_private
+{
+
+class AppleGetPendingItemsHandler {
+public:
+
+ AppleGetPendingItemsHandler (lldb_private::Process *process);
+
+ ~AppleGetPendingItemsHandler();
+
+ struct GetPendingItemsReturnInfo
+ {
+ lldb::addr_t items_buffer_ptr; /* the address of the pending items buffer from libBacktraceRecording */
+ lldb::addr_t items_buffer_size; /* the size of the pending items buffer from libBacktraceRecording */
+ uint64_t count; /* the number of pending items included in the buffer */
+
+ GetPendingItemsReturnInfo () :
+ items_buffer_ptr(LLDB_INVALID_ADDRESS),
+ items_buffer_size(0),
+ count(0)
+ {}
+ };
+
+ //----------------------------------------------------------
+ /// Get the list of pending items for a given queue via a call to
+ /// __introspection_dispatch_queue_get_pending_items. If there's a page of
+ /// memory that needs to be freed, pass in the address and size and it will
+ /// be freed before getting the list of queues.
+ ///
+ /// @param [in] thread
+ /// The thread to run this plan on.
+ ///
+ /// @param [in] queue
+ /// The dispatch_queue_t value for the queue of interest.
+ ///
+ /// @param [in] page_to_free
+ /// An address of an inferior process vm page that needs to be deallocated,
+ /// LLDB_INVALID_ADDRESS if this is not needed.
+ ///
+ /// @param [in] page_to_free_size
+ /// The size of the vm page that needs to be deallocated if an address was
+ /// passed in to page_to_free.
+ ///
+ /// @param [out] error
+ /// This object will be updated with the error status / error string from any failures encountered.
+ ///
+ /// @returns
+ /// The result of the inferior function call execution. If there was a failure of any kind while getting
+ /// the information, the items_buffer_ptr value will be LLDB_INVALID_ADDRESS.
+ //----------------------------------------------------------
+ GetPendingItemsReturnInfo
+ GetPendingItems (Thread &thread, lldb::addr_t queue, lldb::addr_t page_to_free, uint64_t page_to_free_size, lldb_private::Error &error);
+
+
+ void
+ Detach ();
+
+private:
+
+ lldb::addr_t
+ SetupGetPendingItemsFunction (Thread &thread, ValueList &get_pending_items_arglist);
+
+ static const char *g_get_pending_items_function_name;
+ static const char *g_get_pending_items_function_code;
+
+ lldb_private::Process *m_process;
+ std::unique_ptr<UtilityFunction> m_get_pending_items_impl_code;
+ Mutex m_get_pending_items_function_mutex;
+
+ lldb::addr_t m_get_pending_items_return_buffer_addr;
+ Mutex m_get_pending_items_retbuffer_mutex;
+
+};
+
+} // using namespace lldb_private
+
+#endif // lldb_AppleGetPendingItemsHandler_h_
diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp
new file mode 100644
index 000000000000..3370b3257a25
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp
@@ -0,0 +1,382 @@
+//===-- AppleGetQueuesHandler.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AppleGetQueuesHandler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/FunctionCaller.h"
+#include "lldb/Expression/UtilityFunction.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *AppleGetQueuesHandler::g_get_current_queues_function_name = "__lldb_backtrace_recording_get_current_queues";
+const char *AppleGetQueuesHandler::g_get_current_queues_function_code = " \n\
+extern \"C\" \n\
+{ \n\
+ /* \n\
+ * mach defines \n\
+ */ \n\
+ \n\
+ typedef unsigned int uint32_t; \n\
+ typedef unsigned long long uint64_t; \n\
+ typedef uint32_t mach_port_t; \n\
+ typedef mach_port_t vm_map_t; \n\
+ typedef int kern_return_t; \n\
+ typedef uint64_t mach_vm_address_t; \n\
+ typedef uint64_t mach_vm_size_t; \n\
+ \n\
+ mach_port_t mach_task_self (); \n\
+ kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); \n\
+ \n\
+ /* \n\
+ * libBacktraceRecording defines \n\
+ */ \n\
+ \n\
+ typedef uint32_t queue_list_scope_t; \n\
+ typedef void *introspection_dispatch_queue_info_t; \n\
+ \n\
+ extern uint64_t __introspection_dispatch_get_queues (queue_list_scope_t scope, \n\
+ introspection_dispatch_queue_info_t *returned_queues_buffer, \n\
+ uint64_t *returned_queues_buffer_size); \n\
+ extern int printf(const char *format, ...); \n\
+ \n\
+ /* \n\
+ * return type define \n\
+ */ \n\
+ \n\
+ struct get_current_queues_return_values \n\
+ { \n\
+ uint64_t queues_buffer_ptr; /* the address of the queues buffer from libBacktraceRecording */ \n\
+ uint64_t queues_buffer_size; /* the size of the queues buffer from libBacktraceRecording */ \n\
+ uint64_t count; /* the number of queues included in the queues buffer */ \n\
+ }; \n\
+ \n\
+ void __lldb_backtrace_recording_get_current_queues \n\
+ (struct get_current_queues_return_values *return_buffer, \n\
+ int debug, \n\
+ void *page_to_free, \n\
+ uint64_t page_to_free_size) \n\
+{ \n\
+ if (debug) \n\
+ printf (\"entering get_current_queues with args %p, %d, 0x%p, 0x%llx\\n\", return_buffer, debug, page_to_free, page_to_free_size); \n\
+ if (page_to_free != 0) \n\
+ { \n\
+ mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\
+ } \n\
+ \n\
+ return_buffer->count = __introspection_dispatch_get_queues ( \n\
+ /* QUEUES_WITH_ANY_ITEMS */ 2, \n\
+ (void**)&return_buffer->queues_buffer_ptr, \n\
+ &return_buffer->queues_buffer_size); \n\
+ if (debug) \n\
+ printf(\"result was count %lld\\n\", return_buffer->count); \n\
+} \n\
+} \n\
+";
+
+AppleGetQueuesHandler::AppleGetQueuesHandler (Process *process) :
+ m_process (process),
+ m_get_queues_impl_code_up (),
+ m_get_queues_function_mutex(),
+ m_get_queues_return_buffer_addr (LLDB_INVALID_ADDRESS),
+ m_get_queues_retbuffer_mutex()
+{
+}
+
+AppleGetQueuesHandler::~AppleGetQueuesHandler ()
+{
+}
+
+void
+AppleGetQueuesHandler::Detach ()
+{
+
+ if (m_process && m_process->IsAlive() && m_get_queues_return_buffer_addr != LLDB_INVALID_ADDRESS)
+ {
+ Mutex::Locker locker;
+ locker.TryLock (m_get_queues_retbuffer_mutex); // Even if we don't get the lock, deallocate the buffer
+ m_process->DeallocateMemory (m_get_queues_return_buffer_addr);
+ }
+}
+
+// Construct a CompilerType for the structure that g_get_current_queues_function_code will return by value
+// so we can extract the fields after performing the function call.
+// i.e. we are getting this struct returned to us:
+//
+// struct get_current_queues_return_values
+// {
+// introspection_dispatch_queue_info_t *queues_buffer;
+// uint64_t queues_buffer_size;
+// uint64_t count;
+// };
+
+
+// Compile our __lldb_backtrace_recording_get_current_queues() function (from the
+// source above in g_get_current_queues_function_code) if we don't find that function in the inferior
+// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for testing.)
+//
+// Insert the __lldb_backtrace_recording_get_current_queues into the inferior process if needed.
+//
+// Write the get_queues_arglist into the inferior's memory space to prepare for the call.
+//
+// Returns the address of the arguments written down in the inferior process, which can be used to
+// make the function call.
+
+lldb::addr_t
+AppleGetQueuesHandler::SetupGetQueuesFunction (Thread &thread, ValueList &get_queues_arglist)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Address impl_code_address;
+ StreamString errors;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+
+ FunctionCaller *get_queues_caller = nullptr;
+
+ // Scope for mutex locker:
+ {
+ Mutex::Locker locker(m_get_queues_function_mutex);
+
+ // First stage is to make the ClangUtility to hold our injected function:
+
+ if (!m_get_queues_impl_code_up.get())
+ {
+ if (g_get_current_queues_function_code != NULL)
+ {
+ Error error;
+ m_get_queues_impl_code_up.reset (exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(g_get_current_queues_function_code,
+ eLanguageTypeC,
+ g_get_current_queues_function_name,
+ error));
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("Failed to get UtilityFunction for queues introspection: %s.", error.AsCString());
+ return args_addr;
+ }
+
+ if (!m_get_queues_impl_code_up->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install queues introspection: %s.", errors.GetData());
+ m_get_queues_impl_code_up.reset();
+ return args_addr;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("No queues introspection code found.");
+ errors.Printf ("No queues introspection code found.");
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+
+ // Next make the runner function for our implementation utility function.
+ ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext();
+ CompilerType get_queues_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ Error error;
+ get_queues_caller = m_get_queues_impl_code_up->MakeFunctionCaller (get_queues_return_type,
+ get_queues_arglist,
+ error);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("Could not get function caller for get-queues function: %s.", error.AsCString());
+ return args_addr;
+ }
+ }
+
+ errors.Clear();
+
+ // Now write down the argument values for this particular call. This looks like it might be a race condition
+ // if other threads were calling into here, but actually it isn't because we allocate a new args structure for
+ // this call by passing args_addr = LLDB_INVALID_ADDRESS...
+
+ if (!get_queues_caller->WriteFunctionArguments (exe_ctx, args_addr, get_queues_arglist, errors))
+ {
+ if (log)
+ log->Printf ("Error writing get-queues function arguments: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ return args_addr;
+}
+
+AppleGetQueuesHandler::GetQueuesReturnInfo
+AppleGetQueuesHandler::GetCurrentQueues (Thread &thread, addr_t page_to_free, uint64_t page_to_free_size, Error &error)
+{
+ lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
+ ProcessSP process_sp (thread.CalculateProcess());
+ TargetSP target_sp (thread.CalculateTarget());
+ ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+
+ GetQueuesReturnInfo return_value;
+ return_value.queues_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return_value.queues_buffer_size = 0;
+ return_value.count = 0;
+
+ error.Clear();
+
+ if (thread.SafeToCallFunctions() == false)
+ {
+ if (log)
+ log->Printf ("Not safe to call functions on thread 0x%" PRIx64, thread.GetID());
+ error.SetErrorString ("Not safe to call functions on this thread.");
+ return return_value;
+ }
+
+ // Set up the arguments for a call to
+
+ // struct get_current_queues_return_values
+ // {
+ // uint64_t queues_buffer_ptr; /* the address of the queues buffer from libBacktraceRecording */
+ // uint64_t queues_buffer_size; /* the size of the queues buffer from libBacktraceRecording */
+ // uint64_t count; /* the number of queues included in the queues buffer */
+ // };
+ //
+ // void
+ // __lldb_backtrace_recording_get_current_queues
+ // (struct get_current_queues_return_values *return_buffer,
+ // void *page_to_free,
+ // uint64_t page_to_free_size);
+
+ // Where the return_buffer argument points to a 24 byte region of memory already allocated by lldb in
+ // the inferior process.
+
+ CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ Value return_buffer_ptr_value;
+ return_buffer_ptr_value.SetValueType (Value::eValueTypeScalar);
+ return_buffer_ptr_value.SetCompilerType (clang_void_ptr_type);
+
+ CompilerType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt);
+ Value debug_value;
+ debug_value.SetValueType (Value::eValueTypeScalar);
+ debug_value.SetCompilerType (clang_int_type);
+
+ Value page_to_free_value;
+ page_to_free_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_value.SetCompilerType (clang_void_ptr_type);
+
+ CompilerType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong);
+ Value page_to_free_size_value;
+ page_to_free_size_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_size_value.SetCompilerType (clang_uint64_type);
+
+
+ Mutex::Locker locker(m_get_queues_retbuffer_mutex);
+ if (m_get_queues_return_buffer_addr == LLDB_INVALID_ADDRESS)
+ {
+ addr_t bufaddr = process_sp->AllocateMemory (32, ePermissionsReadable | ePermissionsWritable, error);
+ if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("Failed to allocate memory for return buffer for get current queues func call");
+ return return_value;
+ }
+ m_get_queues_return_buffer_addr = bufaddr;
+ }
+
+ ValueList argument_values;
+
+ return_buffer_ptr_value.GetScalar() = m_get_queues_return_buffer_addr;
+ argument_values.PushValue (return_buffer_ptr_value);
+
+ debug_value.GetScalar() = 0;
+ argument_values.PushValue (debug_value);
+
+ if (page_to_free != LLDB_INVALID_ADDRESS)
+ page_to_free_value.GetScalar() = page_to_free;
+ else
+ page_to_free_value.GetScalar() = 0;
+ argument_values.PushValue (page_to_free_value);
+
+ page_to_free_size_value.GetScalar() = page_to_free_size;
+ argument_values.PushValue (page_to_free_size_value);
+
+ addr_t args_addr = SetupGetQueuesFunction (thread, argument_values);
+
+ if (!m_get_queues_impl_code_up)
+ {
+ error.SetErrorString ("Unable to compile __introspection_dispatch_get_queues.");
+ return return_value;
+ }
+
+ FunctionCaller *get_queues_caller = m_get_queues_impl_code_up->GetFunctionCaller();
+
+ if (get_queues_caller == NULL)
+ {
+ error.SetErrorString ("Unable to get caller for call __introspection_dispatch_get_queues");
+ return return_value;
+ }
+
+ StreamString errors;
+ ExecutionContext exe_ctx;
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError (true);
+ options.SetIgnoreBreakpoints (true);
+ options.SetStopOthers (true);
+ options.SetTimeoutUsec(500000);
+ options.SetTryAllThreads (false);
+ thread.CalculateExecutionContext (exe_ctx);
+
+ ExpressionResults func_call_ret;
+ Value results;
+ func_call_ret = get_queues_caller->ExecuteFunction (exe_ctx, &args_addr, options, errors, results);
+ if (func_call_ret != eExpressionCompleted || !error.Success())
+ {
+ if (log)
+ log->Printf ("Unable to call introspection_get_dispatch_queues(), got ExpressionResults %d, error contains %s", func_call_ret, error.AsCString(""));
+ error.SetErrorString ("Unable to call introspection_get_dispatch_queues() for list of queues");
+ return return_value;
+ }
+
+ return_value.queues_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory (m_get_queues_return_buffer_addr, 8, LLDB_INVALID_ADDRESS, error);
+ if (!error.Success() || return_value.queues_buffer_ptr == LLDB_INVALID_ADDRESS)
+ {
+ return_value.queues_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.queues_buffer_size = m_process->ReadUnsignedIntegerFromMemory (m_get_queues_return_buffer_addr + 8, 8, 0, error);
+
+ if (!error.Success())
+ {
+ return_value.queues_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.count = m_process->ReadUnsignedIntegerFromMemory (m_get_queues_return_buffer_addr + 16, 8, 0, error);
+ if (!error.Success())
+ {
+ return_value.queues_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ if (log)
+ log->Printf ("AppleGetQueuesHandler called __introspection_dispatch_get_queues (page_to_free == 0x%" PRIx64 ", size = %" PRId64 "), returned page is at 0x%" PRIx64 ", size %" PRId64 ", count = %" PRId64, page_to_free, page_to_free_size, return_value.queues_buffer_ptr, return_value.queues_buffer_size, return_value.count);
+
+ return return_value;
+}
diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h b/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h
new file mode 100644
index 000000000000..6f3df5f62807
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h
@@ -0,0 +1,116 @@
+//===-- AppleGetQueuesHandler.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_AppleGetQueuesHandler_h_
+#define lldb_AppleGetQueuesHandler_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/CompilerType.h"
+
+// This class will insert a UtilityFunction into the inferior process for
+// calling libBacktraceRecording's introspection_get_dispatch_queues()
+// function. The function in the inferior will return a struct by value
+// with these members:
+//
+// struct get_current_queues_return_values
+// {
+// introspection_dispatch_queue_info_t *queues_buffer;
+// uint64_t queues_buffer_size;
+// uint64_t count;
+// };
+//
+// The queues_buffer pointer is an address in the inferior program's address
+// space (queues_buffer_size in size) which must be mach_vm_deallocate'd by
+// lldb. count is the number of queues that were stored in the buffer.
+//
+// The AppleGetQueuesHandler object should persist so that the UtilityFunction
+// can be reused multiple times.
+
+namespace lldb_private
+{
+
+class AppleGetQueuesHandler {
+public:
+
+ AppleGetQueuesHandler (lldb_private::Process *process);
+
+ ~AppleGetQueuesHandler();
+
+ struct GetQueuesReturnInfo
+ {
+ lldb::addr_t queues_buffer_ptr; /* the address of the queues buffer from libBacktraceRecording */
+ lldb::addr_t queues_buffer_size; /* the size of the queues buffer from libBacktraceRecording */
+ uint64_t count; /* the number of queues included in the queues buffer */
+
+ GetQueuesReturnInfo() :
+ queues_buffer_ptr(LLDB_INVALID_ADDRESS),
+ queues_buffer_size(0),
+ count(0)
+ {}
+ };
+
+ //----------------------------------------------------------
+ /// Get the list of queues that exist (with any active or pending items) via
+ /// a call to introspection_get_dispatch_queues(). If there's a page of
+ /// memory that needs to be freed, pass in the address and size and it will
+ /// be freed before getting the list of queues.
+ ///
+ /// @param [in] thread
+ /// The thread to run this plan on.
+ ///
+ /// @param [in] page_to_free
+ /// An address of an inferior process vm page that needs to be deallocated,
+ /// LLDB_INVALID_ADDRESS if this is not needed.
+ ///
+ /// @param [in] page_to_free_size
+ /// The size of the vm page that needs to be deallocated if an address was
+ /// passed in to page_to_free.
+ ///
+ /// @param [out] error
+ /// This object will be updated with the error status / error string from any failures encountered.
+ ///
+ /// @returns
+ /// The result of the inferior function call execution. If there was a failure of any kind while getting
+ /// the information, the queues_buffer_ptr value will be LLDB_INVALID_ADDRESS.
+ //----------------------------------------------------------
+ GetQueuesReturnInfo
+ GetCurrentQueues (Thread &thread, lldb::addr_t page_to_free, uint64_t page_to_free_size, lldb_private::Error &error);
+
+
+ void
+ Detach ();
+
+private:
+
+ lldb::addr_t
+ SetupGetQueuesFunction (Thread &thread, ValueList &get_queues_arglist);
+
+ static const char *g_get_current_queues_function_name;
+ static const char *g_get_current_queues_function_code;
+
+ lldb_private::Process *m_process;
+ std::unique_ptr<UtilityFunction> m_get_queues_impl_code_up;
+ Mutex m_get_queues_function_mutex;
+
+ lldb::addr_t m_get_queues_return_buffer_addr;
+ Mutex m_get_queues_retbuffer_mutex;
+
+};
+
+} // using namespace lldb_private
+
+#endif // lldb_AppleGetQueuesHandler_h_
diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp
new file mode 100644
index 000000000000..ba03f51152c0
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp
@@ -0,0 +1,385 @@
+//===-- AppleGetThreadItemInfoHandler.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AppleGetThreadItemInfoHandler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/Expression.h"
+#include "lldb/Expression/FunctionCaller.h"
+#include "lldb/Expression/UtilityFunction.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *AppleGetThreadItemInfoHandler::g_get_thread_item_info_function_name = "__lldb_backtrace_recording_get_thread_item_info";
+const char *AppleGetThreadItemInfoHandler::g_get_thread_item_info_function_code = " \n\
+extern \"C\" \n\
+{ \n\
+ /* \n\
+ * mach defines \n\
+ */ \n\
+ \n\
+ typedef unsigned int uint32_t; \n\
+ typedef unsigned long long uint64_t; \n\
+ typedef uint32_t mach_port_t; \n\
+ typedef mach_port_t vm_map_t; \n\
+ typedef int kern_return_t; \n\
+ typedef uint64_t mach_vm_address_t; \n\
+ typedef uint64_t mach_vm_size_t; \n\
+ \n\
+ mach_port_t mach_task_self (); \n\
+ kern_return_t mach_vm_deallocate (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); \n\
+ \n\
+ typedef void *pthread_t; \n\
+ extern int printf(const char *format, ...); \n\
+ extern pthread_t pthread_self(void); \n\
+ \n\
+ /* \n\
+ * libBacktraceRecording defines \n\
+ */ \n\
+ \n\
+ typedef uint32_t queue_list_scope_t; \n\
+ typedef void *dispatch_queue_t; \n\
+ typedef void *introspection_dispatch_queue_info_t; \n\
+ typedef void *introspection_dispatch_item_info_ref; \n\
+ \n\
+ extern void __introspection_dispatch_thread_get_item_info (uint64_t thread_id, \n\
+ introspection_dispatch_item_info_ref *returned_queues_buffer, \n\
+ uint64_t *returned_queues_buffer_size); \n\
+ \n\
+ /* \n\
+ * return type define \n\
+ */ \n\
+ \n\
+ struct get_thread_item_info_return_values \n\
+ { \n\
+ uint64_t item_info_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */ \n\
+ uint64_t item_info_buffer_size; /* the size of the items buffer from libBacktraceRecording */ \n\
+ }; \n\
+ \n\
+ void __lldb_backtrace_recording_get_thread_item_info \n\
+ (struct get_thread_item_info_return_values *return_buffer, \n\
+ int debug, \n\
+ uint64_t thread_id, \n\
+ void *page_to_free, \n\
+ uint64_t page_to_free_size) \n\
+{ \n\
+ void *pthread_id = pthread_self (); \n\
+ if (debug) \n\
+ printf (\"entering get_thread_item_info with args return_buffer == %p, debug == %d, thread id == 0x%llx, page_to_free == %p, page_to_free_size == 0x%llx\\n\", return_buffer, debug, (uint64_t) thread_id, page_to_free, page_to_free_size); \n\
+ if (page_to_free != 0) \n\
+ { \n\
+ mach_vm_deallocate (mach_task_self(), (mach_vm_address_t) page_to_free, (mach_vm_size_t) page_to_free_size); \n\
+ } \n\
+ \n\
+ __introspection_dispatch_thread_get_item_info (thread_id, \n\
+ (void**)&return_buffer->item_info_buffer_ptr, \n\
+ &return_buffer->item_info_buffer_size); \n\
+} \n\
+} \n\
+";
+
+AppleGetThreadItemInfoHandler::AppleGetThreadItemInfoHandler (Process *process) :
+ m_process (process),
+ m_get_thread_item_info_impl_code (),
+ m_get_thread_item_info_function_mutex(),
+ m_get_thread_item_info_return_buffer_addr (LLDB_INVALID_ADDRESS),
+ m_get_thread_item_info_retbuffer_mutex()
+{
+}
+
+AppleGetThreadItemInfoHandler::~AppleGetThreadItemInfoHandler ()
+{
+}
+
+void
+AppleGetThreadItemInfoHandler::Detach ()
+{
+
+ if (m_process && m_process->IsAlive() && m_get_thread_item_info_return_buffer_addr != LLDB_INVALID_ADDRESS)
+ {
+ Mutex::Locker locker;
+ locker.TryLock (m_get_thread_item_info_retbuffer_mutex); // Even if we don't get the lock, deallocate the buffer
+ m_process->DeallocateMemory (m_get_thread_item_info_return_buffer_addr);
+ }
+}
+
+// Compile our __lldb_backtrace_recording_get_thread_item_info() function (from the
+// source above in g_get_thread_item_info_function_code) if we don't find that function in the inferior
+// already with USE_BUILTIN_FUNCTION defined. (e.g. this would be the case for testing.)
+//
+// Insert the __lldb_backtrace_recording_get_thread_item_info into the inferior process if needed.
+//
+// Write the get_thread_item_info_arglist into the inferior's memory space to prepare for the call.
+//
+// Returns the address of the arguments written down in the inferior process, which can be used to
+// make the function call.
+
+lldb::addr_t
+AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction (Thread &thread, ValueList &get_thread_item_info_arglist)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Address impl_code_address;
+ StreamString errors;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+ lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
+ FunctionCaller *get_thread_item_info_caller = nullptr;
+
+ // Scope for mutex locker:
+ {
+ Mutex::Locker locker(m_get_thread_item_info_function_mutex);
+
+ // First stage is to make the ClangUtility to hold our injected function:
+
+ if (!m_get_thread_item_info_impl_code.get())
+ {
+ Error error;
+ if (g_get_thread_item_info_function_code != NULL)
+ {
+ m_get_thread_item_info_impl_code.reset (exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage (g_get_thread_item_info_function_code,
+ eLanguageTypeC,
+ g_get_thread_item_info_function_name,
+ error));
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("Failed to get UtilityFunction for get-thread-item-info introspection: %s.",
+ error.AsCString());
+ m_get_thread_item_info_impl_code.reset();
+ return args_addr;
+ }
+
+ if (!m_get_thread_item_info_impl_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install get-thread-item-info introspection: %s.", errors.GetData());
+ m_get_thread_item_info_impl_code.reset();
+ return args_addr;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("No get-thread-item-info introspection code found.");
+ errors.Printf ("No get-thread-item-info introspection code found.");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // Also make the FunctionCaller for this UtilityFunction:
+
+ ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext();
+ CompilerType get_thread_item_info_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+
+ get_thread_item_info_caller = m_get_thread_item_info_impl_code->MakeFunctionCaller (get_thread_item_info_return_type,
+ get_thread_item_info_arglist,
+ error);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("Failed to install get-thread-item-info introspection caller: %s.", error.AsCString());
+ m_get_thread_item_info_impl_code.reset();
+ return args_addr;
+ }
+
+ }
+ else
+ {
+ get_thread_item_info_caller = m_get_thread_item_info_impl_code->GetFunctionCaller();
+ }
+ }
+
+ errors.Clear();
+
+ // Now write down the argument values for this particular call. This looks like it might be a race condition
+ // if other threads were calling into here, but actually it isn't because we allocate a new args structure for
+ // this call by passing args_addr = LLDB_INVALID_ADDRESS...
+
+ if (!get_thread_item_info_caller->WriteFunctionArguments (exe_ctx, args_addr, get_thread_item_info_arglist, errors))
+ {
+ if (log)
+ log->Printf ("Error writing get-thread-item-info function arguments: \"%s\".", errors.GetData());
+ return args_addr;
+ }
+
+ return args_addr;
+}
+
+AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo
+AppleGetThreadItemInfoHandler::GetThreadItemInfo (Thread &thread, tid_t thread_id, addr_t page_to_free, uint64_t page_to_free_size, Error &error)
+{
+ lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
+ ProcessSP process_sp (thread.CalculateProcess());
+ TargetSP target_sp (thread.CalculateTarget());
+ ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+
+ GetThreadItemInfoReturnInfo return_value;
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return_value.item_buffer_size = 0;
+
+ error.Clear();
+
+ if (thread.SafeToCallFunctions() == false)
+ {
+ if (log)
+ log->Printf ("Not safe to call functions on thread 0x%" PRIx64, thread.GetID());
+ error.SetErrorString ("Not safe to call functions on this thread.");
+ return return_value;
+ }
+
+ // Set up the arguments for a call to
+
+ // struct get_thread_item_info_return_values
+ // {
+ // uint64_t item_info_buffer_ptr; /* the address of the items buffer from libBacktraceRecording */
+ // uint64_t item_info_buffer_size; /* the size of the items buffer from libBacktraceRecording */
+ // };
+ //
+ // void __lldb_backtrace_recording_get_thread_item_info
+ // (struct get_thread_item_info_return_values *return_buffer,
+ // int debug,
+ // void *page_to_free,
+ // uint64_t page_to_free_size)
+
+ // Where the return_buffer argument points to a 24 byte region of memory already allocated by lldb in
+ // the inferior process.
+
+ CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ Value return_buffer_ptr_value;
+ return_buffer_ptr_value.SetValueType (Value::eValueTypeScalar);
+ return_buffer_ptr_value.SetCompilerType (clang_void_ptr_type);
+
+ CompilerType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt);
+ Value debug_value;
+ debug_value.SetValueType (Value::eValueTypeScalar);
+ debug_value.SetCompilerType (clang_int_type);
+
+ CompilerType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong);
+ Value thread_id_value;
+ thread_id_value.SetValueType (Value::eValueTypeScalar);
+ thread_id_value.SetCompilerType (clang_uint64_type);
+
+ Value page_to_free_value;
+ page_to_free_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_value.SetCompilerType (clang_void_ptr_type);
+
+ Value page_to_free_size_value;
+ page_to_free_size_value.SetValueType (Value::eValueTypeScalar);
+ page_to_free_size_value.SetCompilerType (clang_uint64_type);
+
+
+ Mutex::Locker locker(m_get_thread_item_info_retbuffer_mutex);
+ if (m_get_thread_item_info_return_buffer_addr == LLDB_INVALID_ADDRESS)
+ {
+ addr_t bufaddr = process_sp->AllocateMemory (32, ePermissionsReadable | ePermissionsWritable, error);
+ if (!error.Success() || bufaddr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("Failed to allocate memory for return buffer for get current queues func call");
+ return return_value;
+ }
+ m_get_thread_item_info_return_buffer_addr = bufaddr;
+ }
+
+ ValueList argument_values;
+
+ return_buffer_ptr_value.GetScalar() = m_get_thread_item_info_return_buffer_addr;
+ argument_values.PushValue (return_buffer_ptr_value);
+
+ debug_value.GetScalar() = 0;
+ argument_values.PushValue (debug_value);
+
+ thread_id_value.GetScalar() = thread_id;
+ argument_values.PushValue (thread_id_value);
+
+ if (page_to_free != LLDB_INVALID_ADDRESS)
+ page_to_free_value.GetScalar() = page_to_free;
+ else
+ page_to_free_value.GetScalar() = 0;
+ argument_values.PushValue (page_to_free_value);
+
+ page_to_free_size_value.GetScalar() = page_to_free_size;
+ argument_values.PushValue (page_to_free_size_value);
+
+ addr_t args_addr = SetupGetThreadItemInfoFunction (thread, argument_values);
+
+ StreamString errors;
+ ExecutionContext exe_ctx;
+ EvaluateExpressionOptions options;
+ FunctionCaller *get_thread_item_info_caller = nullptr;
+
+ options.SetUnwindOnError (true);
+ options.SetIgnoreBreakpoints (true);
+ options.SetStopOthers (true);
+ options.SetTimeoutUsec(500000);
+ options.SetTryAllThreads (false);
+ thread.CalculateExecutionContext (exe_ctx);
+
+ if (!m_get_thread_item_info_impl_code)
+ {
+ error.SetErrorString ("Unable to compile function to call __introspection_dispatch_thread_get_item_info");
+ return return_value;
+ }
+
+ get_thread_item_info_caller = m_get_thread_item_info_impl_code->GetFunctionCaller();
+
+ if (!get_thread_item_info_caller)
+ {
+ error.SetErrorString ("Unable to compile function caller for __introspection_dispatch_thread_get_item_info");
+ return return_value;
+ }
+
+ ExpressionResults func_call_ret;
+ Value results;
+ func_call_ret = get_thread_item_info_caller->ExecuteFunction (exe_ctx, &args_addr, options, errors, results);
+ if (func_call_ret != eExpressionCompleted || !error.Success())
+ {
+ if (log)
+ log->Printf ("Unable to call __introspection_dispatch_thread_get_item_info(), got ExpressionResults %d, error contains %s", func_call_ret, error.AsCString(""));
+ error.SetErrorString ("Unable to call __introspection_dispatch_thread_get_item_info() for list of queues");
+ return return_value;
+ }
+
+ return_value.item_buffer_ptr = m_process->ReadUnsignedIntegerFromMemory (m_get_thread_item_info_return_buffer_addr, 8, LLDB_INVALID_ADDRESS, error);
+ if (!error.Success() || return_value.item_buffer_ptr == LLDB_INVALID_ADDRESS)
+ {
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ return_value.item_buffer_size = m_process->ReadUnsignedIntegerFromMemory (m_get_thread_item_info_return_buffer_addr + 8, 8, 0, error);
+
+ if (!error.Success())
+ {
+ return_value.item_buffer_ptr = LLDB_INVALID_ADDRESS;
+ return return_value;
+ }
+
+ if (log)
+ log->Printf ("AppleGetThreadItemInfoHandler called __introspection_dispatch_thread_get_item_info (page_to_free == 0x%" PRIx64 ", size = %" PRId64 "), returned page is at 0x%" PRIx64 ", size %" PRId64, page_to_free, page_to_free_size, return_value.item_buffer_ptr, return_value.item_buffer_size);
+
+ return return_value;
+}
diff --git a/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h b/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h
new file mode 100644
index 000000000000..c1798fb515b4
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h
@@ -0,0 +1,113 @@
+//===-- AppleGetThreadItemInfoHandler.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_AppleGetThreadItemInfoHandler_h_
+#define lldb_AppleGetThreadItemInfoHandler_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/CompilerType.h"
+
+// This class will insert a UtilityFunction into the inferior process for
+// calling libBacktraceRecording's __introspection_dispatch_thread_get_item_info()
+// function. The function in the inferior will return a struct by value
+// with these members:
+//
+// struct get_thread_item_info_return_values
+// {
+// introspection_dispatch_item_info_ref *item_buffer;
+// uint64_t item_buffer_size;
+// };
+//
+// The item_buffer pointer is an address in the inferior program's address
+// space (item_buffer_size in size) which must be mach_vm_deallocate'd by
+// lldb.
+//
+// The AppleGetThreadItemInfoHandler object should persist so that the UtilityFunction
+// can be reused multiple times.
+
+namespace lldb_private
+{
+
+class AppleGetThreadItemInfoHandler {
+public:
+
+ AppleGetThreadItemInfoHandler (lldb_private::Process *process);
+
+ ~AppleGetThreadItemInfoHandler();
+
+ struct GetThreadItemInfoReturnInfo
+ {
+ lldb::addr_t item_buffer_ptr; /* the address of the item buffer from libBacktraceRecording */
+ lldb::addr_t item_buffer_size; /* the size of the item buffer from libBacktraceRecording */
+
+ GetThreadItemInfoReturnInfo() :
+ item_buffer_ptr(LLDB_INVALID_ADDRESS),
+ item_buffer_size(0)
+ {}
+ };
+
+ //----------------------------------------------------------
+ /// Get the information about a work item by calling
+ /// __introspection_dispatch_thread_get_item_info. If there's a page of
+ /// memory that needs to be freed, pass in the address and size and it will
+ /// be freed before getting the list of queues.
+ ///
+ /// @param [in] thread_id
+ /// The thread to get the extended backtrace for.
+ ///
+ /// @param [in] page_to_free
+ /// An address of an inferior process vm page that needs to be deallocated,
+ /// LLDB_INVALID_ADDRESS if this is not needed.
+ ///
+ /// @param [in] page_to_free_size
+ /// The size of the vm page that needs to be deallocated if an address was
+ /// passed in to page_to_free.
+ ///
+ /// @param [out] error
+ /// This object will be updated with the error status / error string from any failures encountered.
+ ///
+ /// @returns
+ /// The result of the inferior function call execution. If there was a failure of any kind while getting
+ /// the information, the item_buffer_ptr value will be LLDB_INVALID_ADDRESS.
+ //----------------------------------------------------------
+ GetThreadItemInfoReturnInfo
+ GetThreadItemInfo (Thread &thread, lldb::tid_t thread_id, lldb::addr_t page_to_free, uint64_t page_to_free_size, lldb_private::Error &error);
+
+
+ void
+ Detach ();
+
+private:
+
+ lldb::addr_t
+ SetupGetThreadItemInfoFunction (Thread &thread, ValueList &get_thread_item_info_arglist);
+
+ static const char *g_get_thread_item_info_function_name;
+ static const char *g_get_thread_item_info_function_code;
+
+ lldb_private::Process *m_process;
+ std::unique_ptr<UtilityFunction> m_get_thread_item_info_impl_code;
+ Mutex m_get_thread_item_info_function_mutex;
+
+ lldb::addr_t m_get_thread_item_info_return_buffer_addr;
+ Mutex m_get_thread_item_info_retbuffer_mutex;
+
+};
+
+} // using namespace lldb_private
+
+#endif // lldb_AppleGetThreadItemInfoHandler_h_
diff --git a/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt b/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt
new file mode 100644
index 000000000000..d1580cce20d6
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_lldb_library(lldbPluginSystemRuntimeMacOSX
+ AppleGetItemInfoHandler.cpp
+ AppleGetPendingItemsHandler.cpp
+ AppleGetQueuesHandler.cpp
+ AppleGetThreadItemInfoHandler.cpp
+ SystemRuntimeMacOSX.cpp
+ )
diff --git a/source/Plugins/SystemRuntime/MacOSX/Makefile b/source/Plugins/SystemRuntime/MacOSX/Makefile
new file mode 100644
index 000000000000..eebfb52073d5
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/SystemRuntime/MacOSX ----*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginSystemRuntimeMacOSX
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
new file mode 100644
index 000000000000..b11a06760325
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
@@ -0,0 +1,1010 @@
+//===-- SystemRuntimeMacOSX.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/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "Plugins/Process/Utility/HistoryThread.h"
+#include "lldb/Target/Queue.h"
+#include "lldb/Target/QueueList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/ProcessStructReader.h"
+
+#include "SystemRuntimeMacOSX.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Create an instance of this class. This function is filled into
+// the plugin info class that gets handed out by the plugin factory and
+// allows the lldb to instantiate an instance of this class.
+//----------------------------------------------------------------------
+SystemRuntime *
+SystemRuntimeMacOSX::CreateInstance (Process* process)
+{
+ bool create = false;
+ if (!create)
+ {
+ create = true;
+ Module* exe_module = process->GetTarget().GetExecutableModulePointer();
+ if (exe_module)
+ {
+ ObjectFile *object_file = exe_module->GetObjectFile();
+ if (object_file)
+ {
+ create = (object_file->GetStrata() == ObjectFile::eStrataUser);
+ }
+ }
+
+ if (create)
+ {
+ const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
+ switch (triple_ref.getOS())
+ {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
+ case llvm::Triple::TvOS:
+ case llvm::Triple::WatchOS:
+ create = triple_ref.getVendor() == llvm::Triple::Apple;
+ break;
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+
+ if (create)
+ return new SystemRuntimeMacOSX (process);
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+SystemRuntimeMacOSX::SystemRuntimeMacOSX (Process* process) :
+ SystemRuntime(process),
+ m_break_id(LLDB_INVALID_BREAK_ID),
+ m_mutex(Mutex::eMutexTypeRecursive),
+ m_get_queues_handler(process),
+ m_get_pending_items_handler(process),
+ m_get_item_info_handler(process),
+ m_get_thread_item_info_handler(process),
+ m_page_to_free(LLDB_INVALID_ADDRESS),
+ m_page_to_free_size(0),
+ m_lib_backtrace_recording_info(),
+ m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS),
+ m_libdispatch_offsets(),
+ m_libpthread_layout_offsets_addr (LLDB_INVALID_ADDRESS),
+ m_libpthread_offsets(),
+ m_dispatch_tsd_indexes_addr (LLDB_INVALID_ADDRESS),
+ m_libdispatch_tsd_indexes(),
+ m_dispatch_voucher_offsets_addr (LLDB_INVALID_ADDRESS),
+ m_libdispatch_voucher_offsets()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SystemRuntimeMacOSX::~SystemRuntimeMacOSX()
+{
+ Clear (true);
+}
+
+void
+SystemRuntimeMacOSX::Detach ()
+{
+ m_get_queues_handler.Detach();
+ m_get_pending_items_handler.Detach();
+ m_get_item_info_handler.Detach();
+ m_get_thread_item_info_handler.Detach();
+}
+
+//----------------------------------------------------------------------
+// Clear out the state of this class.
+//----------------------------------------------------------------------
+void
+SystemRuntimeMacOSX::Clear (bool clear_process)
+{
+ Mutex::Locker locker(m_mutex);
+
+ if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id))
+ m_process->ClearBreakpointSiteByID(m_break_id);
+
+ if (clear_process)
+ m_process = NULL;
+ m_break_id = LLDB_INVALID_BREAK_ID;
+}
+
+
+std::string
+SystemRuntimeMacOSX::GetQueueNameFromThreadQAddress (addr_t dispatch_qaddr)
+{
+ std::string dispatch_queue_name;
+ if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0)
+ return "";
+
+ ReadLibdispatchOffsets ();
+ if (m_libdispatch_offsets.IsValid ())
+ {
+ // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
+ // deref it to get the address of the dispatch_queue_t structure for this thread's
+ // queue.
+ Error error;
+ addr_t dispatch_queue_addr = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
+ if (error.Success())
+ {
+ if (m_libdispatch_offsets.dqo_version >= 4)
+ {
+ // libdispatch versions 4+, pointer to dispatch name is in the
+ // queue structure.
+ addr_t pointer_to_label_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_label;
+ addr_t label_addr = m_process->ReadPointerFromMemory (pointer_to_label_address, error);
+ if (error.Success())
+ {
+ m_process->ReadCStringFromMemory (label_addr, dispatch_queue_name, error);
+ }
+ }
+ else
+ {
+ // libdispatch versions 1-3, dispatch name is a fixed width char array
+ // in the queue structure.
+ addr_t label_addr = dispatch_queue_addr + m_libdispatch_offsets.dqo_label;
+ dispatch_queue_name.resize (m_libdispatch_offsets.dqo_label_size, '\0');
+ size_t bytes_read = m_process->ReadMemory (label_addr, &dispatch_queue_name[0], m_libdispatch_offsets.dqo_label_size, error);
+ if (bytes_read < m_libdispatch_offsets.dqo_label_size)
+ dispatch_queue_name.erase (bytes_read);
+ }
+ }
+ }
+ return dispatch_queue_name;
+}
+
+lldb::addr_t
+SystemRuntimeMacOSX::GetLibdispatchQueueAddressFromThreadQAddress (addr_t dispatch_qaddr)
+{
+ addr_t libdispatch_queue_t_address = LLDB_INVALID_ADDRESS;
+ Error error;
+ libdispatch_queue_t_address = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
+ if (!error.Success())
+ {
+ libdispatch_queue_t_address = LLDB_INVALID_ADDRESS;
+ }
+ return libdispatch_queue_t_address;
+}
+
+lldb::QueueKind
+SystemRuntimeMacOSX::GetQueueKind (addr_t dispatch_queue_addr)
+{
+ if (dispatch_queue_addr == LLDB_INVALID_ADDRESS || dispatch_queue_addr == 0)
+ return eQueueKindUnknown;
+
+ QueueKind kind = eQueueKindUnknown;
+ ReadLibdispatchOffsets ();
+ if (m_libdispatch_offsets.IsValid () && m_libdispatch_offsets.dqo_version >= 4)
+ {
+ Error error;
+ uint64_t width = m_process->ReadUnsignedIntegerFromMemory (dispatch_queue_addr + m_libdispatch_offsets.dqo_width, m_libdispatch_offsets.dqo_width_size, 0, error);
+ if (error.Success())
+ {
+ if (width == 1)
+ {
+ kind = eQueueKindSerial;
+ }
+ if (width > 1)
+ {
+ kind = eQueueKindConcurrent;
+ }
+ }
+ }
+ return kind;
+}
+
+void
+SystemRuntimeMacOSX::AddThreadExtendedInfoPacketHints (lldb_private::StructuredData::ObjectSP dict_sp)
+{
+ StructuredData::Dictionary *dict = dict_sp->GetAsDictionary();
+ if (dict)
+ {
+ ReadLibpthreadOffsets();
+ if (m_libpthread_offsets.IsValid())
+ {
+ dict->AddIntegerItem ("plo_pthread_tsd_base_offset", m_libpthread_offsets.plo_pthread_tsd_base_offset);
+ dict->AddIntegerItem ("plo_pthread_tsd_base_address_offset", m_libpthread_offsets.plo_pthread_tsd_base_address_offset);
+ dict->AddIntegerItem ("plo_pthread_tsd_entry_size", m_libpthread_offsets.plo_pthread_tsd_entry_size);
+ }
+
+ ReadLibdispatchTSDIndexes ();
+ if (m_libdispatch_tsd_indexes.IsValid())
+ {
+ dict->AddIntegerItem ("dti_queue_index", m_libdispatch_tsd_indexes.dti_queue_index);
+ dict->AddIntegerItem ("dti_voucher_index", m_libdispatch_tsd_indexes.dti_voucher_index);
+ dict->AddIntegerItem ("dti_qos_class_index", m_libdispatch_tsd_indexes.dti_qos_class_index);
+ }
+ }
+}
+
+bool
+SystemRuntimeMacOSX::SafeToCallFunctionsOnThisThread (ThreadSP thread_sp)
+{
+ if (thread_sp && thread_sp->GetStackFrameCount() > 0 && thread_sp->GetFrameWithConcreteFrameIndex(0))
+ {
+ const SymbolContext sym_ctx (thread_sp->GetFrameWithConcreteFrameIndex(0)->GetSymbolContext (eSymbolContextSymbol));
+ static ConstString g_select_symbol ("__select");
+ if (sym_ctx.GetFunctionName() == g_select_symbol)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+lldb::queue_id_t
+SystemRuntimeMacOSX::GetQueueIDFromThreadQAddress (lldb::addr_t dispatch_qaddr)
+{
+ queue_id_t queue_id = LLDB_INVALID_QUEUE_ID;
+
+ if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0)
+ return queue_id;
+
+ ReadLibdispatchOffsets ();
+ if (m_libdispatch_offsets.IsValid ())
+ {
+ // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
+ // deref it to get the address of the dispatch_queue_t structure for this thread's
+ // queue.
+ Error error;
+ uint64_t dispatch_queue_addr = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
+ if (error.Success())
+ {
+ addr_t serialnum_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_serialnum;
+ queue_id_t serialnum = m_process->ReadUnsignedIntegerFromMemory (serialnum_address, m_libdispatch_offsets.dqo_serialnum_size, LLDB_INVALID_QUEUE_ID, error);
+ if (error.Success())
+ {
+ queue_id = serialnum;
+ }
+ }
+ }
+
+ return queue_id;
+}
+
+
+void
+SystemRuntimeMacOSX::ReadLibdispatchOffsetsAddress ()
+{
+ if (m_dispatch_queue_offsets_addr != LLDB_INVALID_ADDRESS)
+ return;
+
+ static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets");
+ const Symbol *dispatch_queue_offsets_symbol = NULL;
+
+ // libdispatch symbols were in libSystem.B.dylib up through Mac OS X 10.6 ("Snow Leopard")
+ ModuleSpec libSystem_module_spec (FileSpec("libSystem.B.dylib", false));
+ ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule (libSystem_module_spec));
+ if (module_sp)
+ dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
+
+ // libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") and later
+ if (dispatch_queue_offsets_symbol == NULL)
+ {
+ ModuleSpec libdispatch_module_spec (FileSpec("libdispatch.dylib", false));
+ module_sp = m_process->GetTarget().GetImages().FindFirstModule (libdispatch_module_spec);
+ if (module_sp)
+ dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
+ }
+ if (dispatch_queue_offsets_symbol)
+ m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetLoadAddress(&m_process->GetTarget());
+}
+
+void
+SystemRuntimeMacOSX::ReadLibdispatchOffsets ()
+{
+ if (m_libdispatch_offsets.IsValid())
+ return;
+
+ ReadLibdispatchOffsetsAddress ();
+
+ uint8_t memory_buffer[sizeof (struct LibdispatchOffsets)];
+ DataExtractor data (memory_buffer,
+ sizeof(memory_buffer),
+ m_process->GetByteOrder(),
+ m_process->GetAddressByteSize());
+
+ Error error;
+ if (m_process->ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(memory_buffer), error) == sizeof(memory_buffer))
+ {
+ lldb::offset_t data_offset = 0;
+
+ // The struct LibdispatchOffsets is a series of uint16_t's - extract them all
+ // in one big go.
+ data.GetU16 (&data_offset, &m_libdispatch_offsets.dqo_version, sizeof (struct LibdispatchOffsets) / sizeof (uint16_t));
+ }
+}
+
+void
+SystemRuntimeMacOSX::ReadLibpthreadOffsetsAddress ()
+{
+ if (m_libpthread_layout_offsets_addr != LLDB_INVALID_ADDRESS)
+ return;
+
+ static ConstString g_libpthread_layout_offsets_symbol_name ("pthread_layout_offsets");
+ const Symbol *libpthread_layout_offsets_symbol = NULL;
+
+ ModuleSpec libpthread_module_spec (FileSpec("libsystem_pthread.dylib", false));
+ ModuleSP module_sp (m_process->GetTarget().GetImages().FindFirstModule (libpthread_module_spec));
+ if (module_sp)
+ {
+ libpthread_layout_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType
+ (g_libpthread_layout_offsets_symbol_name, eSymbolTypeData);
+ if (libpthread_layout_offsets_symbol)
+ {
+ m_libpthread_layout_offsets_addr = libpthread_layout_offsets_symbol->GetLoadAddress(&m_process->GetTarget());
+ }
+ }
+}
+
+void
+SystemRuntimeMacOSX::ReadLibpthreadOffsets ()
+{
+ if (m_libpthread_offsets.IsValid())
+ return;
+
+ ReadLibpthreadOffsetsAddress ();
+
+ if (m_libpthread_layout_offsets_addr != LLDB_INVALID_ADDRESS)
+ {
+ uint8_t memory_buffer[sizeof (struct LibpthreadOffsets)];
+ DataExtractor data (memory_buffer,
+ sizeof(memory_buffer),
+ m_process->GetByteOrder(),
+ m_process->GetAddressByteSize());
+ Error error;
+ if (m_process->ReadMemory (m_libpthread_layout_offsets_addr, memory_buffer, sizeof(memory_buffer), error) == sizeof(memory_buffer))
+ {
+ lldb::offset_t data_offset = 0;
+
+ // The struct LibpthreadOffsets is a series of uint16_t's - extract them all
+ // in one big go.
+ data.GetU16 (&data_offset, &m_libpthread_offsets.plo_version, sizeof (struct LibpthreadOffsets) / sizeof (uint16_t));
+ }
+ }
+}
+
+void
+SystemRuntimeMacOSX::ReadLibdispatchTSDIndexesAddress ()
+{
+ if (m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS)
+ return;
+
+ static ConstString g_libdispatch_tsd_indexes_symbol_name ("dispatch_tsd_indexes");
+ const Symbol *libdispatch_tsd_indexes_symbol = NULL;
+
+ ModuleSpec libpthread_module_spec (FileSpec("libdispatch.dylib", false));
+ ModuleSP module_sp (m_process->GetTarget().GetImages().FindFirstModule (libpthread_module_spec));
+ if (module_sp)
+ {
+ libdispatch_tsd_indexes_symbol = module_sp->FindFirstSymbolWithNameAndType
+ (g_libdispatch_tsd_indexes_symbol_name, eSymbolTypeData);
+ if (libdispatch_tsd_indexes_symbol)
+ {
+ m_dispatch_tsd_indexes_addr = libdispatch_tsd_indexes_symbol->GetLoadAddress(&m_process->GetTarget());
+ }
+ }
+}
+
+void
+SystemRuntimeMacOSX::ReadLibdispatchTSDIndexes ()
+{
+ if (m_libdispatch_tsd_indexes.IsValid())
+ return;
+
+ ReadLibdispatchTSDIndexesAddress ();
+
+ if (m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS)
+ {
+
+ // We don't need to check the version number right now, it will be at least 2, but
+ // keep this code around to fetch just the version # for the future where we need
+ // to fetch alternate versions of the struct.
+# if 0
+ uint16_t dti_version = 2;
+ Address dti_struct_addr;
+ if (m_process->GetTarget().ResolveLoadAddress (m_dispatch_tsd_indexes_addr, dti_struct_addr))
+ {
+ Error error;
+ uint16_t version = m_process->GetTarget().ReadUnsignedIntegerFromMemory (dti_struct_addr, false, 2, UINT16_MAX, error);
+ if (error.Success() && dti_version != UINT16_MAX)
+ {
+ dti_version = version;
+ }
+ }
+#endif
+
+ ClangASTContext *ast_ctx = m_process->GetTarget().GetScratchClangASTContext();
+ if (ast_ctx->getASTContext() && m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS)
+ {
+ CompilerType uint16 = ast_ctx->GetBuiltinTypeForEncodingAndBitSize (eEncodingUint, 16);
+ CompilerType dispatch_tsd_indexes_s = ast_ctx->CreateRecordType(nullptr, lldb::eAccessPublic, "__lldb_dispatch_tsd_indexes_s", clang::TTK_Struct, lldb::eLanguageTypeC);
+
+ ClangASTContext::StartTagDeclarationDefinition(dispatch_tsd_indexes_s);
+ ClangASTContext::AddFieldToRecordType (dispatch_tsd_indexes_s, "dti_version", uint16, lldb::eAccessPublic, 0);
+ ClangASTContext::AddFieldToRecordType (dispatch_tsd_indexes_s, "dti_queue_index", uint16, lldb::eAccessPublic, 0);
+ ClangASTContext::AddFieldToRecordType (dispatch_tsd_indexes_s, "dti_voucher_index", uint16, lldb::eAccessPublic, 0);
+ ClangASTContext::AddFieldToRecordType (dispatch_tsd_indexes_s, "dti_qos_class_index", uint16, lldb::eAccessPublic, 0);
+ ClangASTContext::CompleteTagDeclarationDefinition(dispatch_tsd_indexes_s);
+
+ ProcessStructReader struct_reader (m_process, m_dispatch_tsd_indexes_addr, dispatch_tsd_indexes_s);
+
+ m_libdispatch_tsd_indexes.dti_version = struct_reader.GetField<uint16_t>(ConstString("dti_version"));
+ m_libdispatch_tsd_indexes.dti_queue_index = struct_reader.GetField<uint16_t>(ConstString("dti_queue_index"));
+ m_libdispatch_tsd_indexes.dti_voucher_index = struct_reader.GetField<uint16_t>(ConstString("dti_voucher_index"));
+ m_libdispatch_tsd_indexes.dti_qos_class_index = struct_reader.GetField<uint16_t>(ConstString("dti_qos_class_index"));
+ }
+ }
+}
+
+
+ThreadSP
+SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP real_thread, ConstString type)
+{
+ ThreadSP originating_thread_sp;
+ if (BacktraceRecordingHeadersInitialized() && type == ConstString ("libdispatch"))
+ {
+ Error error;
+
+ // real_thread is either an actual, live thread (in which case we need to call into
+ // libBacktraceRecording to find its originator) or it is an extended backtrace itself,
+ // in which case we get the token from it and call into libBacktraceRecording to find
+ // the originator of that token.
+
+ if (real_thread->GetExtendedBacktraceToken() != LLDB_INVALID_ADDRESS)
+ {
+ originating_thread_sp = GetExtendedBacktraceFromItemRef (real_thread->GetExtendedBacktraceToken());
+ }
+ else
+ {
+ ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
+ AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo ret = m_get_thread_item_info_handler.GetThreadItemInfo (*cur_thread_sp.get(), real_thread->GetID(), m_page_to_free, m_page_to_free_size, error);
+ m_page_to_free = LLDB_INVALID_ADDRESS;
+ m_page_to_free_size = 0;
+ if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
+ {
+ DataBufferHeap data (ret.item_buffer_size, 0);
+ if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
+ ItemInfo item = ExtractItemInfoFromBuffer (extractor);
+ bool stop_id_is_valid = true;
+ if (item.stop_id == 0)
+ stop_id_is_valid = false;
+ originating_thread_sp.reset (new HistoryThread (*m_process,
+ item.enqueuing_thread_id,
+ item.enqueuing_callstack,
+ item.stop_id,
+ stop_id_is_valid));
+ originating_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this);
+ originating_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str());
+ originating_thread_sp->SetQueueID (item.enqueuing_queue_serialnum);
+// originating_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
+ }
+ m_page_to_free = ret.item_buffer_ptr;
+ m_page_to_free_size = ret.item_buffer_size;
+ }
+ }
+ }
+ return originating_thread_sp;
+}
+
+ThreadSP
+SystemRuntimeMacOSX::GetExtendedBacktraceFromItemRef (lldb::addr_t item_ref)
+{
+ ThreadSP return_thread_sp;
+
+ AppleGetItemInfoHandler::GetItemInfoReturnInfo ret;
+ ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
+ Error error;
+ ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error);
+ m_page_to_free = LLDB_INVALID_ADDRESS;
+ m_page_to_free_size = 0;
+ if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
+ {
+ DataBufferHeap data (ret.item_buffer_size, 0);
+ if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
+ ItemInfo item = ExtractItemInfoFromBuffer (extractor);
+ bool stop_id_is_valid = true;
+ if (item.stop_id == 0)
+ stop_id_is_valid = false;
+ return_thread_sp.reset (new HistoryThread (*m_process,
+ item.enqueuing_thread_id,
+ item.enqueuing_callstack,
+ item.stop_id,
+ stop_id_is_valid));
+ return_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this);
+ return_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str());
+ return_thread_sp->SetQueueID (item.enqueuing_queue_serialnum);
+// return_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
+
+ m_page_to_free = ret.item_buffer_ptr;
+ m_page_to_free_size = ret.item_buffer_size;
+ }
+ }
+ return return_thread_sp;
+}
+
+ThreadSP
+SystemRuntimeMacOSX::GetExtendedBacktraceForQueueItem (QueueItemSP queue_item_sp, ConstString type)
+{
+ ThreadSP extended_thread_sp;
+ if (type != ConstString("libdispatch"))
+ return extended_thread_sp;
+
+ bool stop_id_is_valid = true;
+ if (queue_item_sp->GetStopID() == 0)
+ stop_id_is_valid = false;
+
+ extended_thread_sp.reset (new HistoryThread (*m_process,
+ queue_item_sp->GetEnqueueingThreadID(),
+ queue_item_sp->GetEnqueueingBacktrace(),
+ queue_item_sp->GetStopID(),
+ stop_id_is_valid));
+ extended_thread_sp->SetExtendedBacktraceToken (queue_item_sp->GetItemThatEnqueuedThis());
+ extended_thread_sp->SetQueueName (queue_item_sp->GetQueueLabel().c_str());
+ extended_thread_sp->SetQueueID (queue_item_sp->GetEnqueueingQueueID());
+// extended_thread_sp->SetThreadName (queue_item_sp->GetThreadLabel().c_str());
+
+ return extended_thread_sp;
+}
+
+/* Returns true if we were able to get the version / offset information
+ * out of libBacktraceRecording. false means we were unable to retrieve
+ * this; the queue_info_version field will be 0.
+ */
+
+bool
+SystemRuntimeMacOSX::BacktraceRecordingHeadersInitialized ()
+{
+ if (m_lib_backtrace_recording_info.queue_info_version != 0)
+ return true;
+
+ addr_t queue_info_version_address = LLDB_INVALID_ADDRESS;
+ addr_t queue_info_data_offset_address = LLDB_INVALID_ADDRESS;
+ addr_t item_info_version_address = LLDB_INVALID_ADDRESS;
+ addr_t item_info_data_offset_address = LLDB_INVALID_ADDRESS;
+ Target &target = m_process->GetTarget();
+
+
+ static ConstString introspection_dispatch_queue_info_version ("__introspection_dispatch_queue_info_version");
+ SymbolContextList sc_list;
+ if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_version, eSymbolTypeData, sc_list) > 0)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ AddressRange addr_range;
+ sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
+ queue_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
+ }
+ sc_list.Clear();
+
+ static ConstString introspection_dispatch_queue_info_data_offset ("__introspection_dispatch_queue_info_data_offset");
+ if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_data_offset, eSymbolTypeData, sc_list) > 0)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ AddressRange addr_range;
+ sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
+ queue_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
+ }
+ sc_list.Clear();
+
+ static ConstString introspection_dispatch_item_info_version ("__introspection_dispatch_item_info_version");
+ if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_version, eSymbolTypeData, sc_list) > 0)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ AddressRange addr_range;
+ sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
+ item_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
+ }
+ sc_list.Clear();
+
+ static ConstString introspection_dispatch_item_info_data_offset ("__introspection_dispatch_item_info_data_offset");
+ if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_data_offset, eSymbolTypeData, sc_list) > 0)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ AddressRange addr_range;
+ sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
+ item_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
+ }
+
+ if (queue_info_version_address != LLDB_INVALID_ADDRESS
+ && queue_info_data_offset_address != LLDB_INVALID_ADDRESS
+ && item_info_version_address != LLDB_INVALID_ADDRESS
+ && item_info_data_offset_address != LLDB_INVALID_ADDRESS)
+ {
+ Error error;
+ m_lib_backtrace_recording_info.queue_info_version = m_process->ReadUnsignedIntegerFromMemory (queue_info_version_address, 2, 0, error);
+ if (error.Success())
+ {
+ m_lib_backtrace_recording_info.queue_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (queue_info_data_offset_address, 2, 0, error);
+ if (error.Success())
+ {
+ m_lib_backtrace_recording_info.item_info_version = m_process->ReadUnsignedIntegerFromMemory (item_info_version_address, 2, 0, error);
+ if (error.Success())
+ {
+ m_lib_backtrace_recording_info.item_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (item_info_data_offset_address, 2, 0, error);
+ if (!error.Success())
+ {
+ m_lib_backtrace_recording_info.queue_info_version = 0;
+ }
+ }
+ else
+ {
+ m_lib_backtrace_recording_info.queue_info_version = 0;
+ }
+ }
+ else
+ {
+ m_lib_backtrace_recording_info.queue_info_version = 0;
+ }
+ }
+ }
+
+ return m_lib_backtrace_recording_info.queue_info_version != 0;
+}
+
+const std::vector<ConstString> &
+SystemRuntimeMacOSX::GetExtendedBacktraceTypes ()
+{
+ if (m_types.size () == 0)
+ {
+ m_types.push_back(ConstString("libdispatch"));
+ // We could have pthread as another type in the future if we have a way of
+ // gathering that information & it's useful to distinguish between them.
+ }
+ return m_types;
+}
+
+void
+SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list)
+{
+ if (BacktraceRecordingHeadersInitialized())
+ {
+ AppleGetQueuesHandler::GetQueuesReturnInfo queue_info_pointer;
+ ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
+ if (cur_thread_sp)
+ {
+ Error error;
+ queue_info_pointer = m_get_queues_handler.GetCurrentQueues (*cur_thread_sp.get(), m_page_to_free, m_page_to_free_size, error);
+ m_page_to_free = LLDB_INVALID_ADDRESS;
+ m_page_to_free_size = 0;
+ if (error.Success())
+ {
+
+ if (queue_info_pointer.count > 0
+ && queue_info_pointer.queues_buffer_size > 0
+ && queue_info_pointer.queues_buffer_ptr != 0
+ && queue_info_pointer.queues_buffer_ptr != LLDB_INVALID_ADDRESS)
+ {
+ PopulateQueuesUsingLibBTR (queue_info_pointer.queues_buffer_ptr, queue_info_pointer.queues_buffer_size, queue_info_pointer.count, queue_list);
+ }
+ }
+ }
+ }
+
+ // We either didn't have libBacktraceRecording (and need to create the queues list based on threads)
+ // or we did get the queues list from libBacktraceRecording but some special queues may not be
+ // included in its information. This is needed because libBacktraceRecording
+ // will only list queues with pending or running items by default - but the magic com.apple.main-thread
+ // queue on thread 1 is always around.
+
+ for (ThreadSP thread_sp : m_process->Threads())
+ {
+ if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID)
+ {
+ if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL)
+ {
+ QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName()));
+ queue_sp->SetKind (GetQueueKind (thread_sp->GetQueueLibdispatchQueueAddress()));
+ queue_sp->SetLibdispatchQueueAddress (thread_sp->GetQueueLibdispatchQueueAddress());
+ queue_list.AddQueue (queue_sp);
+ }
+ }
+ }
+}
+
+// Returns either an array of introspection_dispatch_item_info_ref's for the pending items on
+// a queue or an array introspection_dispatch_item_info_ref's and code addresses for the
+// pending items on a queue. The information about each of these pending items then needs to
+// be fetched individually by passing the ref to libBacktraceRecording.
+
+SystemRuntimeMacOSX::PendingItemsForQueue
+SystemRuntimeMacOSX::GetPendingItemRefsForQueue (lldb::addr_t queue)
+{
+ PendingItemsForQueue pending_item_refs;
+ AppleGetPendingItemsHandler::GetPendingItemsReturnInfo pending_items_pointer;
+ ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
+ if (cur_thread_sp)
+ {
+ Error error;
+ pending_items_pointer = m_get_pending_items_handler.GetPendingItems (*cur_thread_sp.get(), queue, m_page_to_free, m_page_to_free_size, error);
+ m_page_to_free = LLDB_INVALID_ADDRESS;
+ m_page_to_free_size = 0;
+ if (error.Success())
+ {
+ if (pending_items_pointer.count > 0
+ && pending_items_pointer.items_buffer_size > 0
+ && pending_items_pointer.items_buffer_ptr != 0
+ && pending_items_pointer.items_buffer_ptr != LLDB_INVALID_ADDRESS)
+ {
+ DataBufferHeap data (pending_items_pointer.items_buffer_size, 0);
+ if (m_process->ReadMemory (pending_items_pointer.items_buffer_ptr, data.GetBytes(), pending_items_pointer.items_buffer_size, error))
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
+
+ // We either have an array of
+ // void* item_ref
+ // (old style) or we have a structure returned which looks like
+ //
+ // struct introspection_dispatch_pending_item_info_s {
+ // void *item_ref;
+ // void *function_or_block;
+ // };
+ //
+ // struct introspection_dispatch_pending_items_array_s {
+ // uint32_t version;
+ // uint32_t size_of_item_info;
+ // introspection_dispatch_pending_item_info_s items[];
+ // }
+
+ offset_t offset = 0;
+ int i = 0;
+ uint32_t version = extractor.GetU32(&offset);
+ if (version == 1)
+ {
+ pending_item_refs.new_style = true;
+ uint32_t item_size = extractor.GetU32(&offset);
+ uint32_t start_of_array_offset = offset;
+ while (offset < pending_items_pointer.items_buffer_size &&
+ static_cast<size_t>(i) < pending_items_pointer.count)
+ {
+ offset = start_of_array_offset + (i * item_size);
+ ItemRefAndCodeAddress item;
+ item.item_ref = extractor.GetPointer (&offset);
+ item.code_address = extractor.GetPointer (&offset);
+ pending_item_refs.item_refs_and_code_addresses.push_back (item);
+ i++;
+ }
+ }
+ else
+ {
+ offset = 0;
+ pending_item_refs.new_style = false;
+ while (offset < pending_items_pointer.items_buffer_size &&
+ static_cast<size_t>(i) < pending_items_pointer.count)
+ {
+ ItemRefAndCodeAddress item;
+ item.item_ref = extractor.GetPointer (&offset);
+ item.code_address = LLDB_INVALID_ADDRESS;
+ pending_item_refs.item_refs_and_code_addresses.push_back (item);
+ i++;
+ }
+ }
+ }
+ m_page_to_free = pending_items_pointer.items_buffer_ptr;
+ m_page_to_free_size = pending_items_pointer.items_buffer_size;
+ }
+ }
+ }
+ return pending_item_refs;
+}
+
+
+
+void
+SystemRuntimeMacOSX::PopulatePendingItemsForQueue (Queue *queue)
+{
+ if (BacktraceRecordingHeadersInitialized())
+ {
+ PendingItemsForQueue pending_item_refs = GetPendingItemRefsForQueue (queue->GetLibdispatchQueueAddress());
+ for (ItemRefAndCodeAddress pending_item : pending_item_refs.item_refs_and_code_addresses)
+ {
+ Address addr;
+ m_process->GetTarget().ResolveLoadAddress (pending_item.code_address, addr);
+ QueueItemSP queue_item_sp (new QueueItem (queue->shared_from_this(), m_process->shared_from_this(), pending_item.item_ref, addr));
+ queue->PushPendingQueueItem (queue_item_sp);
+ }
+ }
+}
+
+void
+SystemRuntimeMacOSX::CompleteQueueItem (QueueItem *queue_item, addr_t item_ref)
+{
+ AppleGetItemInfoHandler::GetItemInfoReturnInfo ret;
+
+ ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
+ Error error;
+ ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error);
+ m_page_to_free = LLDB_INVALID_ADDRESS;
+ m_page_to_free_size = 0;
+ if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
+ {
+ DataBufferHeap data (ret.item_buffer_size, 0);
+ if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
+ ItemInfo item = ExtractItemInfoFromBuffer (extractor);
+ queue_item->SetItemThatEnqueuedThis (item.item_that_enqueued_this);
+ queue_item->SetEnqueueingThreadID (item.enqueuing_thread_id);
+ queue_item->SetEnqueueingQueueID (item.enqueuing_queue_serialnum);
+ queue_item->SetStopID (item.stop_id);
+ queue_item->SetEnqueueingBacktrace (item.enqueuing_callstack);
+ queue_item->SetThreadLabel (item.enqueuing_thread_label);
+ queue_item->SetQueueLabel (item.enqueuing_queue_label);
+ queue_item->SetTargetQueueLabel (item.target_queue_label);
+ }
+ m_page_to_free = ret.item_buffer_ptr;
+ m_page_to_free_size = ret.item_buffer_size;
+ }
+}
+
+void
+SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR (lldb::addr_t queues_buffer, uint64_t queues_buffer_size,
+ uint64_t count, lldb_private::QueueList &queue_list)
+{
+ Error error;
+ DataBufferHeap data (queues_buffer_size, 0);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
+ if (m_process->ReadMemory (queues_buffer, data.GetBytes(), queues_buffer_size, error) == queues_buffer_size && error.Success())
+ {
+ // We've read the information out of inferior memory; free it on the next call we make
+ m_page_to_free = queues_buffer;
+ m_page_to_free_size = queues_buffer_size;
+
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
+ offset_t offset = 0;
+ uint64_t queues_read = 0;
+
+ // The information about the queues is stored in this format (v1):
+ // typedef struct introspection_dispatch_queue_info_s {
+ // uint32_t offset_to_next;
+ // dispatch_queue_t queue;
+ // uint64_t serialnum; // queue's serialnum in the process, as provided by libdispatch
+ // uint32_t running_work_items_count;
+ // uint32_t pending_work_items_count;
+ //
+ // char data[]; // Starting here, we have variable-length data:
+ // // char queue_label[];
+ // } introspection_dispatch_queue_info_s;
+
+ while (queues_read < count && offset < queues_buffer_size)
+ {
+ offset_t start_of_this_item = offset;
+
+ uint32_t offset_to_next = extractor.GetU32 (&offset);
+
+ offset += 4; // Skip over the 4 bytes of reserved space
+ addr_t queue = extractor.GetPointer (&offset);
+ uint64_t serialnum = extractor.GetU64 (&offset);
+ uint32_t running_work_items_count = extractor.GetU32 (&offset);
+ uint32_t pending_work_items_count = extractor.GetU32 (&offset);
+
+ // Read the first field of the variable length data
+ offset = start_of_this_item + m_lib_backtrace_recording_info.queue_info_data_offset;
+ const char *queue_label = extractor.GetCStr (&offset);
+ if (queue_label == NULL)
+ queue_label = "";
+
+ offset_t start_of_next_item = start_of_this_item + offset_to_next;
+ offset = start_of_next_item;
+
+ if (log)
+ log->Printf ("SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR added queue with dispatch_queue_t 0x%" PRIx64 ", serial number 0x%" PRIx64 ", running items %d, pending items %d, name '%s'", queue, serialnum, running_work_items_count, pending_work_items_count, queue_label);
+
+ QueueSP queue_sp (new Queue (m_process->shared_from_this(), serialnum, queue_label));
+ queue_sp->SetNumRunningWorkItems (running_work_items_count);
+ queue_sp->SetNumPendingWorkItems (pending_work_items_count);
+ queue_sp->SetLibdispatchQueueAddress (queue);
+ queue_sp->SetKind (GetQueueKind (queue));
+ queue_list.AddQueue (queue_sp);
+ queues_read++;
+ }
+ }
+}
+
+SystemRuntimeMacOSX::ItemInfo
+SystemRuntimeMacOSX::ExtractItemInfoFromBuffer (lldb_private::DataExtractor &extractor)
+{
+ ItemInfo item;
+
+ offset_t offset = 0;
+
+ item.item_that_enqueued_this = extractor.GetPointer (&offset);
+ item.function_or_block = extractor.GetPointer (&offset);
+ item.enqueuing_thread_id = extractor.GetU64 (&offset);
+ item.enqueuing_queue_serialnum = extractor.GetU64 (&offset);
+ item.target_queue_serialnum = extractor.GetU64 (&offset);
+ item.enqueuing_callstack_frame_count = extractor.GetU32 (&offset);
+ item.stop_id = extractor.GetU32 (&offset);
+
+ offset = m_lib_backtrace_recording_info.item_info_data_offset;
+
+ for (uint32_t i = 0; i < item.enqueuing_callstack_frame_count; i++)
+ {
+ item.enqueuing_callstack.push_back (extractor.GetPointer (&offset));
+ }
+ item.enqueuing_thread_label = extractor.GetCStr (&offset);
+ item.enqueuing_queue_label = extractor.GetCStr (&offset);
+ item.target_queue_label = extractor.GetCStr (&offset);
+
+ return item;
+}
+
+void
+SystemRuntimeMacOSX::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SystemRuntimeMacOSX::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+SystemRuntimeMacOSX::GetPluginNameStatic()
+{
+ static ConstString g_name("systemruntime-macosx");
+ return g_name;
+}
+
+const char *
+SystemRuntimeMacOSX::GetPluginDescriptionStatic()
+{
+ return "System runtime plugin for Mac OS X native libraries.";
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+SystemRuntimeMacOSX::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SystemRuntimeMacOSX::GetPluginVersion()
+{
+ return 1;
+}
diff --git a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h
new file mode 100644
index 000000000000..5976bed57cf6
--- /dev/null
+++ b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h
@@ -0,0 +1,336 @@
+//===-- SystemRuntimeMacOSX.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_SystemRuntimeMacOSX_h_
+#define liblldb_SystemRuntimeMacOSX_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+#include <string>
+
+// Other libraries and framework include
+// Project includes
+#include "lldb/Target/SystemRuntime.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/QueueItem.h"
+
+#include "AppleGetItemInfoHandler.h"
+#include "AppleGetQueuesHandler.h"
+#include "AppleGetPendingItemsHandler.h"
+#include "AppleGetThreadItemInfoHandler.h"
+
+class SystemRuntimeMacOSX : public lldb_private::SystemRuntime
+{
+public:
+ SystemRuntimeMacOSX(lldb_private::Process *process);
+
+ ~SystemRuntimeMacOSX() override;
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SystemRuntime *
+ CreateInstance (lldb_private::Process *process);
+
+ //------------------------------------------------------------------
+ // instance methods
+ //------------------------------------------------------------------
+
+ void
+ Clear(bool clear_process);
+
+ void
+ Detach() override;
+
+ const std::vector<lldb_private::ConstString> &
+ GetExtendedBacktraceTypes() override;
+
+ lldb::ThreadSP
+ GetExtendedBacktraceThread(lldb::ThreadSP thread, lldb_private::ConstString type) override;
+
+ lldb::ThreadSP
+ GetExtendedBacktraceForQueueItem(lldb::QueueItemSP queue_item_sp,
+ lldb_private::ConstString type) override;
+
+ lldb::ThreadSP
+ GetExtendedBacktraceFromItemRef (lldb::addr_t item_ref);
+
+ void
+ PopulateQueueList(lldb_private::QueueList &queue_list) override;
+
+ void
+ PopulateQueuesUsingLibBTR (lldb::addr_t queues_buffer, uint64_t queues_buffer_size, uint64_t count, lldb_private::QueueList &queue_list);
+
+ void
+ PopulatePendingQueuesUsingLibBTR (lldb::addr_t items_buffer, uint64_t items_buffer_size, uint64_t count, lldb_private::Queue *queue);
+
+ std::string
+ GetQueueNameFromThreadQAddress(lldb::addr_t dispatch_qaddr) override;
+
+ lldb::queue_id_t
+ GetQueueIDFromThreadQAddress(lldb::addr_t dispatch_qaddr) override;
+
+ lldb::addr_t
+ GetLibdispatchQueueAddressFromThreadQAddress(lldb::addr_t dispatch_qaddr) override;
+
+ void
+ PopulatePendingItemsForQueue(lldb_private::Queue *queue) override;
+
+ void
+ CompleteQueueItem(lldb_private::QueueItem *queue_item, lldb::addr_t item_ref) override;
+
+ virtual lldb::QueueKind
+ GetQueueKind (lldb::addr_t dispatch_queue_addr);
+
+ void
+ AddThreadExtendedInfoPacketHints(lldb_private::StructuredData::ObjectSP dict) override;
+
+ bool
+ SafeToCallFunctionsOnThisThread(lldb::ThreadSP thread_sp) override;
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ lldb_private::ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+protected:
+ lldb::user_id_t m_break_id;
+ mutable lldb_private::Mutex m_mutex;
+
+private:
+ struct libBacktraceRecording_info {
+ uint16_t queue_info_version;
+ uint16_t queue_info_data_offset;
+ uint16_t item_info_version;
+ uint16_t item_info_data_offset;
+
+ libBacktraceRecording_info () :
+ queue_info_version(0),
+ queue_info_data_offset(0),
+ item_info_version(0),
+ item_info_data_offset(0) {}
+ };
+
+ // A structure which reflects the data recorded in the
+ // libBacktraceRecording introspection_dispatch_item_info_s.
+ struct ItemInfo {
+ lldb::addr_t item_that_enqueued_this;
+ lldb::addr_t function_or_block;
+ uint64_t enqueuing_thread_id;
+ uint64_t enqueuing_queue_serialnum;
+ uint64_t target_queue_serialnum;
+ uint32_t enqueuing_callstack_frame_count;
+ uint32_t stop_id;
+ std::vector<lldb::addr_t> enqueuing_callstack;
+ std::string enqueuing_thread_label;
+ std::string enqueuing_queue_label;
+ std::string target_queue_label;
+ };
+
+ // The offsets of different fields of the dispatch_queue_t structure in
+ // a thread/queue process.
+ // Based on libdispatch src/queue_private.h, struct dispatch_queue_offsets_s
+ // With dqo_version 1-3, the dqo_label field is a per-queue value and cannot be cached.
+ // With dqo_version 4 (Mac OS X 10.9 / iOS 7), dqo_label is a constant value that can be cached.
+ struct LibdispatchOffsets
+ {
+ uint16_t dqo_version;
+ uint16_t dqo_label;
+ uint16_t dqo_label_size;
+ uint16_t dqo_flags;
+ uint16_t dqo_flags_size;
+ uint16_t dqo_serialnum;
+ uint16_t dqo_serialnum_size;
+ uint16_t dqo_width;
+ uint16_t dqo_width_size;
+ uint16_t dqo_running;
+ uint16_t dqo_running_size;
+
+ uint16_t dqo_suspend_cnt; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+ uint16_t dqo_suspend_cnt_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+ uint16_t dqo_target_queue; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+ uint16_t dqo_target_queue_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+ uint16_t dqo_priority; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+ uint16_t dqo_priority_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+
+ LibdispatchOffsets ()
+ {
+ dqo_version = UINT16_MAX;
+ dqo_flags = UINT16_MAX;
+ dqo_serialnum = UINT16_MAX;
+ dqo_label = UINT16_MAX;
+ dqo_width = UINT16_MAX;
+ dqo_running = UINT16_MAX;
+ dqo_suspend_cnt = UINT16_MAX;
+ dqo_target_queue = UINT16_MAX;
+ dqo_target_queue = UINT16_MAX;
+ dqo_priority = UINT16_MAX;
+ }
+
+ bool
+ IsValid ()
+ {
+ return dqo_version != UINT16_MAX;
+ }
+
+ bool
+ LabelIsValid ()
+ {
+ return dqo_label != UINT16_MAX;
+ }
+ };
+
+ struct LibdispatchVoucherOffsets
+ {
+ uint16_t vo_version;
+ uint16_t vo_activity_ids_count;
+ uint16_t vo_activity_ids_count_size;
+ uint16_t vo_activity_ids_array;
+ uint16_t vo_activity_ids_array_entry_size;
+
+ LibdispatchVoucherOffsets () :
+ vo_version (UINT16_MAX),
+ vo_activity_ids_count (UINT16_MAX),
+ vo_activity_ids_count_size (UINT16_MAX),
+ vo_activity_ids_array (UINT16_MAX),
+ vo_activity_ids_array_entry_size (UINT16_MAX)
+ { }
+
+ bool IsValid () { return vo_version != UINT16_MAX; }
+ };
+
+ struct LibdispatchTSDIndexes
+ {
+ uint16_t dti_version;
+ uint64_t dti_queue_index;
+ uint64_t dti_voucher_index;
+ uint64_t dti_qos_class_index;
+
+ LibdispatchTSDIndexes () :
+ dti_version (UINT16_MAX),
+ dti_queue_index (UINT64_MAX),
+ dti_voucher_index (UINT64_MAX),
+ dti_qos_class_index (UINT64_MAX)
+ { }
+
+ bool IsValid () { return dti_version != UINT16_MAX; }
+ };
+
+ struct LibpthreadOffsets
+ {
+ uint16_t plo_version;
+ uint16_t plo_pthread_tsd_base_offset;
+ uint16_t plo_pthread_tsd_base_address_offset;
+ uint16_t plo_pthread_tsd_entry_size;
+
+ LibpthreadOffsets () :
+ plo_version (UINT16_MAX),
+ plo_pthread_tsd_base_offset (UINT16_MAX),
+ plo_pthread_tsd_base_address_offset (UINT16_MAX),
+ plo_pthread_tsd_entry_size (UINT16_MAX)
+ {
+ }
+
+ bool IsValid ()
+ {
+ return plo_version != UINT16_MAX;
+ }
+ };
+
+ // The libBacktraceRecording function __introspection_dispatch_queue_get_pending_items has
+ // two forms. It can either return a simple array of item_refs (void *) size or it can return
+ // a header with uint32_t version, a uint32_t size of item, and then an array of item_refs (void*)
+ // and code addresses (void*) for all the pending blocks.
+
+ struct ItemRefAndCodeAddress {
+ lldb::addr_t item_ref;
+ lldb::addr_t code_address;
+ };
+
+ struct PendingItemsForQueue {
+ bool new_style; // new-style means both item_refs and code_addresses avail
+ // old-style means only item_refs is filled in
+ std::vector<ItemRefAndCodeAddress> item_refs_and_code_addresses;
+ };
+
+ bool
+ BacktraceRecordingHeadersInitialized ();
+
+ void
+ ReadLibdispatchOffsetsAddress();
+
+ void
+ ReadLibdispatchOffsets ();
+
+ void
+ ReadLibpthreadOffsetsAddress();
+
+ void
+ ReadLibpthreadOffsets ();
+
+ void
+ ReadLibdispatchTSDIndexesAddress ();
+
+ void
+ ReadLibdispatchTSDIndexes ();
+
+ PendingItemsForQueue
+ GetPendingItemRefsForQueue (lldb::addr_t queue);
+
+ ItemInfo
+ ExtractItemInfoFromBuffer (lldb_private::DataExtractor &extractor);
+
+ lldb_private::AppleGetQueuesHandler m_get_queues_handler;
+ lldb_private::AppleGetPendingItemsHandler m_get_pending_items_handler;
+ lldb_private::AppleGetItemInfoHandler m_get_item_info_handler;
+ lldb_private::AppleGetThreadItemInfoHandler m_get_thread_item_info_handler;
+
+ lldb::addr_t m_page_to_free;
+ uint64_t m_page_to_free_size;
+ libBacktraceRecording_info m_lib_backtrace_recording_info;
+
+ lldb::addr_t m_dispatch_queue_offsets_addr;
+ struct LibdispatchOffsets m_libdispatch_offsets;
+
+ lldb::addr_t m_libpthread_layout_offsets_addr;
+ struct LibpthreadOffsets m_libpthread_offsets;
+
+ lldb::addr_t m_dispatch_tsd_indexes_addr;
+ struct LibdispatchTSDIndexes m_libdispatch_tsd_indexes;
+
+ lldb::addr_t m_dispatch_voucher_offsets_addr;
+ struct LibdispatchVoucherOffsets m_libdispatch_voucher_offsets;
+
+ DISALLOW_COPY_AND_ASSIGN (SystemRuntimeMacOSX);
+};
+
+#endif // liblldb_SystemRuntimeMacOSX_h_
diff --git a/source/Plugins/UnwindAssembly/CMakeLists.txt b/source/Plugins/UnwindAssembly/CMakeLists.txt
new file mode 100644
index 000000000000..1723a0604580
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(InstEmulation)
+add_subdirectory(x86)
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/CMakeLists.txt b/source/Plugins/UnwindAssembly/InstEmulation/CMakeLists.txt
new file mode 100644
index 000000000000..21673160bf40
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/InstEmulation/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginUnwindAssemblyInstEmulation
+ UnwindAssemblyInstEmulation.cpp
+ )
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/Makefile b/source/Plugins/UnwindAssembly/InstEmulation/Makefile
new file mode 100644
index 000000000000..e006235864f1
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/InstEmulation/Makefile
@@ -0,0 +1,14 @@
+##==- source/Plugins/UnwindAssembly/InstEmulation/Makefile -*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginUnwindAssemblyInstEmulation
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/UnwindAssembly/x86/CMakeLists.txt b/source/Plugins/UnwindAssembly/x86/CMakeLists.txt
new file mode 100644
index 000000000000..6ae63891bcc3
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/x86/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_library(lldbPluginUnwindAssemblyX86
+ UnwindAssembly-x86.cpp
+ )
diff --git a/source/Plugins/UnwindAssembly/x86/Makefile b/source/Plugins/UnwindAssembly/x86/Makefile
new file mode 100644
index 000000000000..24419c044f04
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/x86/Makefile
@@ -0,0 +1,14 @@
+##==-- source/Plugins/UnwindAssembly/x86/Makefile ----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginUnwindAssemblyX86
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Symbol/CMakeLists.txt b/source/Symbol/CMakeLists.txt
new file mode 100644
index 000000000000..6372fffde1f1
--- /dev/null
+++ b/source/Symbol/CMakeLists.txt
@@ -0,0 +1,36 @@
+add_lldb_library(lldbSymbol
+ ArmUnwindInfo.cpp
+ Block.cpp
+ ClangASTContext.cpp
+ ClangASTImporter.cpp
+ ClangExternalASTSourceCallbacks.cpp
+ ClangExternalASTSourceCommon.cpp
+ CompilerDecl.cpp
+ CompilerDeclContext.cpp
+ CompilerType.cpp
+ CompileUnit.cpp
+ CompactUnwindInfo.cpp
+ DebugMacros.cpp
+ Declaration.cpp
+ DWARFCallFrameInfo.cpp
+ Function.cpp
+ FuncUnwinders.cpp
+ GoASTContext.cpp
+ LineEntry.cpp
+ LineTable.cpp
+ ObjectFile.cpp
+ Symbol.cpp
+ SymbolContext.cpp
+ SymbolFile.cpp
+ SymbolVendor.cpp
+ Symtab.cpp
+ Type.cpp
+ TypeList.cpp
+ TypeMap.cpp
+ TypeSystem.cpp
+ UnwindPlan.cpp
+ UnwindTable.cpp
+ Variable.cpp
+ VariableList.cpp
+ VerifyDecl.cpp
+ )
diff --git a/source/Symbol/Makefile b/source/Symbol/Makefile
new file mode 100644
index 000000000000..ae0cef0e242a
--- /dev/null
+++ b/source/Symbol/Makefile
@@ -0,0 +1,14 @@
+##===- source/Symbol/Makefile ------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbSymbol
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Target/CMakeLists.txt b/source/Target/CMakeLists.txt
new file mode 100644
index 000000000000..f1c2a7e98007
--- /dev/null
+++ b/source/Target/CMakeLists.txt
@@ -0,0 +1,59 @@
+include_directories(../Plugins/Process/Utility)
+
+add_lldb_library(lldbTarget
+ ABI.cpp
+ CPPLanguageRuntime.cpp
+ ExecutionContext.cpp
+ FileAction.cpp
+ JITLoader.cpp
+ JITLoaderList.cpp
+ InstrumentationRuntime.cpp
+ InstrumentationRuntimeStopInfo.cpp
+ Language.cpp
+ LanguageRuntime.cpp
+ Memory.cpp
+ MemoryHistory.cpp
+ ObjCLanguageRuntime.cpp
+ OperatingSystem.cpp
+ PathMappingList.cpp
+ Platform.cpp
+ Process.cpp
+ ProcessInfo.cpp
+ ProcessLaunchInfo.cpp
+ Queue.cpp
+ QueueItem.cpp
+ QueueList.cpp
+ RegisterContext.cpp
+ SectionLoadHistory.cpp
+ SectionLoadList.cpp
+ StackFrame.cpp
+ StackFrameList.cpp
+ StackID.cpp
+ StopInfo.cpp
+ SystemRuntime.cpp
+ Target.cpp
+ TargetList.cpp
+ Thread.cpp
+ ThreadCollection.cpp
+ ThreadList.cpp
+ ThreadPlan.cpp
+ ThreadPlanBase.cpp
+ ThreadPlanCallFunction.cpp
+ ThreadPlanCallFunctionUsingABI.cpp
+ ThreadPlanCallUserExpression.cpp
+ ThreadPlanPython.cpp
+ ThreadPlanRunToAddress.cpp
+ ThreadPlanShouldStopHere.cpp
+ ThreadPlanStepInRange.cpp
+ ThreadPlanStepInstruction.cpp
+ ThreadPlanStepOut.cpp
+ ThreadPlanStepOverBreakpoint.cpp
+ ThreadPlanStepOverRange.cpp
+ ThreadPlanStepRange.cpp
+ ThreadPlanStepThrough.cpp
+ ThreadPlanStepUntil.cpp
+ ThreadPlanTracer.cpp
+ ThreadSpec.cpp
+ UnixSignals.cpp
+ UnwindAssembly.cpp
+ )
diff --git a/source/Target/Makefile b/source/Target/Makefile
new file mode 100644
index 000000000000..0d4be5449ad3
--- /dev/null
+++ b/source/Target/Makefile
@@ -0,0 +1,14 @@
+##===- source/Target/Makefile ------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbTarget
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index 6bc9f2b0c9d8..311c695860fe 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -3980,7 +3980,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
{
Vote stop_vote = m_thread_list.ShouldReportStop (event_ptr);
if (log)
- log->Printf ("Process::ShouldBroadcastEvent: should_stop: %i state: %s was_restarted: %i stop_vote: %d.",
+ log->Printf ("Process::ShouldBroadcastEvent: should_resume: %i state: %s was_restarted: %i stop_vote: %d.",
should_resume, StateAsCString(state),
was_restarted, stop_vote);
diff --git a/source/Utility/CMakeLists.txt b/source/Utility/CMakeLists.txt
new file mode 100644
index 000000000000..aa4ad0301352
--- /dev/null
+++ b/source/Utility/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_lldb_library(lldbUtility
+ ARM_DWARF_Registers.cpp
+ ARM64_DWARF_Registers.cpp
+ ConvertEnum.cpp
+ JSON.cpp
+ KQueue.cpp
+ LLDBAssert.cpp
+ ModuleCache.cpp
+ NameMatches.cpp
+ PseudoTerminal.cpp
+ Range.cpp
+ RegisterNumber.cpp
+ SharingPtr.cpp
+ StringExtractor.cpp
+ StringExtractorGDBRemote.cpp
+ StringLexer.cpp
+ TaskPool.cpp
+ TimeSpecTimeout.cpp
+ UriParser.cpp
+ )
diff --git a/source/Utility/Makefile b/source/Utility/Makefile
new file mode 100644
index 000000000000..13bcd8376c2d
--- /dev/null
+++ b/source/Utility/Makefile
@@ -0,0 +1,15 @@
+##===- source/Utility/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../..
+LIBRARYNAME := lldbUtility
+BUILD_ARCHIVE = 1
+NO_PEDANTIC = 1
+
+include $(LLDB_LEVEL)/Makefile