aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/Process
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Process')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp1088
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h136
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.cpp29
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h42
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp202
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.h68
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp302
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h86
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp239
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h75
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp290
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.h75
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp657
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h97
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp345
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h91
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp335
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h54
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.cpp110
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.h41
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.cpp83
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.h41
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.cpp88
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.h41
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp86
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h50
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp1119
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h130
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp34
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h44
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp645
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h94
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp329
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h86
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.cpp31
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.h20
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp189
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h65
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp34
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h39
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/ARMDefines.h191
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/ARMUtils.h377
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.cpp98
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h84
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp139
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h27
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp181
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h30
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryThread.cpp85
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryThread.h92
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp73
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryUnwind.h46
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp190
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h35
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/InstructionUtils.h116
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h293
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp205
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h27
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp143
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.h27
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp356
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h63
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp210
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h31
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp470
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h89
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.cpp276
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h54
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp42
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h40
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp99
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.h27
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp1745
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h264
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp1041
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h231
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp963
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h208
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp1056
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h213
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp120
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h65
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp83
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp179
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h30
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp233
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h52
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp145
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h30
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp121
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h67
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp125
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h29
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp69
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.h32
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86.h30
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp184
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h34
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp74
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h39
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp60
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h35
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp63
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h36
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp139
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h75
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp96
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.h25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp178
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h33
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp77
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp104
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h30
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp98
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h62
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp119
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h86
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.cpp82
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.h63
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp138
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h78
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp164
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h195
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp183
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h73
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.cpp82
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.h63
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp163
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h72
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp540
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h185
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp216
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h102
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.cpp89
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.h27
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.cpp152
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.h28
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h374
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h123
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_s390x.h90
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp58
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h395
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp217
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h86
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoAndSetInterface.h36
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h49
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp193
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h72
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp561
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h186
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.cpp158
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h69
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp63
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h31
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.cpp142
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h66
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h800
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h793
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h573
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h310
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_loongarch64.h171
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h305
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h223
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h228
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h329
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h474
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv64.h186
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_s390x.h124
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h486
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h471
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base_shared.cpp321
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base_shared.h142
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp862
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.h76
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp98
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.h107
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h199
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h264
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-loongarch-register-enums.h178
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h103
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h136
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-ppc64le-register-enums.h207
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-riscv-register-enums.h193
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-s390x-register-enums.h90
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h517
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp1097
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h187
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextLinuxCore_x86_64.cpp237
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextLinuxCore_x86_64.h28
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp74
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h53
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp396
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h89
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp91
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h55
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp111
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h60
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp133
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.h48
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.cpp82
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.h60
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp96
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h55
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp99
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h49
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.cpp39
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h158
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp440
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h178
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp404
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h175
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp1320
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h249
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp4353
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h658
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp95
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h76
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp168
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h86
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp1388
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h154
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp4321
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h342
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp606
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h149
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteErrno.def39
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp777
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h141
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.cpp101
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.h26
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp5876
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h497
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp47
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h45
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td24
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp368
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h126
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp711
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h113
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp79
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h107
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/NtStructures.h42
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp929
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h123
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp550
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h98
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp833
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h83
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp96
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h135
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp110
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h180
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp118
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.h45
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp540
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.h136
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp370
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.h80
261 files changed, 67313 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
new file mode 100644
index 000000000000..064bddd37052
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
@@ -0,0 +1,1088 @@
+//===-- NativeProcessFreeBSD.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessFreeBSD.h"
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <machine/elf.h>
+// clang-format on
+
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/State.h"
+#include "llvm/Support/Errno.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+using namespace llvm;
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static Status EnsureFDFlags(int fd, int flags) {
+ Status 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;
+}
+
+static Status CanTrace() {
+ int proc_debug, ret;
+ size_t len = sizeof(proc_debug);
+ ret = ::sysctlbyname("security.bsd.unprivileged_proc_debug", &proc_debug,
+ &len, nullptr, 0);
+ if (ret != 0)
+ return Status("sysctlbyname() security.bsd.unprivileged_proc_debug failed");
+
+ if (proc_debug < 1)
+ return Status(
+ "process debug disabled by security.bsd.unprivileged_proc_debug oid");
+
+ return {};
+}
+
+// Public Static Methods
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessFreeBSD::Manager::Launch(ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate) {
+ Log *log = GetLog(POSIXLog::Process);
+ Status status;
+
+ ::pid_t pid = ProcessLauncherPosixFork()
+ .LaunchProcess(launch_info, status)
+ .GetProcessId();
+ LLDB_LOG(log, "pid = {0:x}", pid);
+ if (status.Fail()) {
+ LLDB_LOG(log, "failed to launch process: {0}", status);
+ auto error = CanTrace();
+ if (error.Fail())
+ return error.ToError();
+ return status.ToError();
+ }
+
+ // Wait for the child process to trap on its call to execve.
+ int wstatus;
+ ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
+ assert(wpid == pid);
+ UNUSED_IF_ASSERT_DISABLED(wpid);
+ if (!WIFSTOPPED(wstatus)) {
+ LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
+ WaitStatus::Decode(wstatus));
+ return llvm::make_error<StringError>("Could not sync with inferior process",
+ llvm::inconvertibleErrorCode());
+ }
+ LLDB_LOG(log, "inferior started, now in stopped state");
+
+ ProcessInstanceInfo Info;
+ if (!Host::GetProcessInfo(pid, Info)) {
+ return llvm::make_error<StringError>("Cannot get process architecture",
+ llvm::inconvertibleErrorCode());
+ }
+
+ // Set the architecture to the exe architecture.
+ LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
+ Info.GetArchitecture().GetArchitectureName());
+
+ std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD(
+ pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
+ Info.GetArchitecture(), m_mainloop));
+
+ status = process_up->SetupTrace();
+ if (status.Fail())
+ return status.ToError();
+
+ for (const auto &thread : process_up->m_threads)
+ static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+ process_up->SetState(StateType::eStateStopped, false);
+
+ return std::move(process_up);
+}
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessFreeBSD::Manager::Attach(
+ lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid = {0:x}", pid);
+
+ // Retrieve the architecture for the running process.
+ ProcessInstanceInfo Info;
+ if (!Host::GetProcessInfo(pid, Info)) {
+ return llvm::make_error<StringError>("Cannot get process architecture",
+ llvm::inconvertibleErrorCode());
+ }
+
+ std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD(
+ pid, -1, native_delegate, Info.GetArchitecture(), m_mainloop));
+
+ Status status = process_up->Attach();
+ if (!status.Success())
+ return status.ToError();
+
+ return std::move(process_up);
+}
+
+NativeProcessFreeBSD::Extension
+NativeProcessFreeBSD::Manager::GetSupportedExtensions() const {
+ return
+#if defined(PT_COREDUMP)
+ Extension::savecore |
+#endif
+ Extension::multiprocess | Extension::fork | Extension::vfork |
+ Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |
+ Extension::siginfo_read;
+}
+
+// Public Instance Methods
+
+NativeProcessFreeBSD::NativeProcessFreeBSD(::pid_t pid, int terminal_fd,
+ NativeDelegate &delegate,
+ const ArchSpec &arch,
+ MainLoop &mainloop)
+ : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),
+ m_main_loop(mainloop) {
+ if (m_terminal_fd != -1) {
+ Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
+ assert(status.Success());
+ }
+
+ Status status;
+ m_sigchld_handle = mainloop.RegisterSignal(
+ SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
+ assert(m_sigchld_handle && status.Success());
+}
+
+// Handles all waitpid events from the inferior process.
+void NativeProcessFreeBSD::MonitorCallback(lldb::pid_t pid, int signal) {
+ switch (signal) {
+ case SIGTRAP:
+ return MonitorSIGTRAP(pid);
+ case SIGSTOP:
+ return MonitorSIGSTOP(pid);
+ default:
+ return MonitorSignal(pid, signal);
+ }
+}
+
+void NativeProcessFreeBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
+ Log *log = GetLog(POSIXLog::Process);
+
+ LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
+
+ /* Stop Tracking All Threads attached to Process */
+ m_threads.clear();
+
+ SetExitStatus(status, true);
+
+ // Notify delegate that our process has exited.
+ SetState(StateType::eStateExited, true);
+}
+
+void NativeProcessFreeBSD::MonitorSIGSTOP(lldb::pid_t pid) {
+ /* Stop all Threads attached to Process */
+ for (const auto &thread : m_threads) {
+ static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP,
+ nullptr);
+ }
+ SetState(StateType::eStateStopped, true);
+}
+
+void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
+ Log *log = GetLog(POSIXLog::Process);
+ struct ptrace_lwpinfo info;
+
+ const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+ return;
+ }
+ assert(info.pl_event == PL_EVENT_SIGNAL);
+
+ LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, flags = {2:x}", pid,
+ info.pl_lwpid, info.pl_flags);
+ NativeThreadFreeBSD *thread = nullptr;
+
+ if (info.pl_flags & (PL_FLAG_BORN | PL_FLAG_EXITED)) {
+ if (info.pl_flags & PL_FLAG_BORN) {
+ LLDB_LOG(log, "monitoring new thread, tid = {0}", info.pl_lwpid);
+ NativeThreadFreeBSD &t = AddThread(info.pl_lwpid);
+
+ // Technically, the FreeBSD kernel copies the debug registers to new
+ // threads. However, there is a non-negligible delay between acquiring
+ // the DR values and reporting the new thread during which the user may
+ // establish a new watchpoint. In order to ensure that watchpoints
+ // established during this period are propagated to new threads,
+ // explicitly copy the DR value at the time the new thread is reported.
+ //
+ // See also: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=250954
+
+ llvm::Error error = t.CopyWatchpointsFrom(
+ static_cast<NativeThreadFreeBSD &>(*GetCurrentThread()));
+ if (error) {
+ LLDB_LOG_ERROR(log, std::move(error),
+ "failed to copy watchpoints to new thread {1}: {0}",
+ info.pl_lwpid);
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+ } else /*if (info.pl_flags & PL_FLAG_EXITED)*/ {
+ LLDB_LOG(log, "thread exited, tid = {0}", info.pl_lwpid);
+ RemoveThread(info.pl_lwpid);
+ }
+
+ Status error =
+ PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
+ if (error.Fail())
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+
+ if (info.pl_flags & PL_FLAG_EXEC) {
+ Status error = ReinitializeThreads();
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+
+ // Let our delegate know we have just exec'd.
+ NotifyDidExec();
+
+ for (const auto &thread : m_threads)
+ static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedByExec();
+ SetCurrentThreadID(m_threads.front()->GetID());
+ SetState(StateType::eStateStopped, true);
+ return;
+ }
+
+ if (info.pl_lwpid > 0) {
+ for (const auto &t : m_threads) {
+ if (t->GetID() == static_cast<lldb::tid_t>(info.pl_lwpid))
+ thread = static_cast<NativeThreadFreeBSD *>(t.get());
+ static_cast<NativeThreadFreeBSD *>(t.get())->SetStoppedWithNoReason();
+ }
+ if (!thread)
+ LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
+ info.pl_lwpid);
+ }
+
+ if (info.pl_flags & PL_FLAG_FORKED) {
+ assert(thread);
+ MonitorClone(info.pl_child_pid, info.pl_flags & PL_FLAG_VFORKED, *thread);
+ return;
+ }
+
+ if (info.pl_flags & PL_FLAG_VFORK_DONE) {
+ assert(thread);
+ if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) {
+ thread->SetStoppedByVForkDone();
+ SetState(StateType::eStateStopped, true);
+ } else {
+ Status error =
+ PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
+ if (error.Fail())
+ SetState(StateType::eStateInvalid);
+ }
+ return;
+ }
+
+ if (info.pl_flags & PL_FLAG_SI) {
+ assert(info.pl_siginfo.si_signo == SIGTRAP);
+ LLDB_LOG(log, "SIGTRAP siginfo: si_code = {0}, pid = {1}",
+ info.pl_siginfo.si_code, info.pl_siginfo.si_pid);
+
+ switch (info.pl_siginfo.si_code) {
+ case TRAP_BRKPT:
+ LLDB_LOG(log, "SIGTRAP/TRAP_BRKPT: si_addr: {0}",
+ info.pl_siginfo.si_addr);
+
+ if (thread) {
+ auto thread_info =
+ m_threads_stepping_with_breakpoint.find(thread->GetID());
+ if (thread_info != m_threads_stepping_with_breakpoint.end()) {
+ thread->SetStoppedByTrace();
+ Status brkpt_error = RemoveBreakpoint(thread_info->second);
+ if (brkpt_error.Fail())
+ LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",
+ thread_info->first, brkpt_error);
+ m_threads_stepping_with_breakpoint.erase(thread_info);
+ } else
+ thread->SetStoppedByBreakpoint();
+ FixupBreakpointPCAsNeeded(*thread);
+ SetCurrentThreadID(thread->GetID());
+ }
+ SetState(StateType::eStateStopped, true);
+ return;
+ case TRAP_TRACE:
+ LLDB_LOG(log, "SIGTRAP/TRAP_TRACE: si_addr: {0}",
+ info.pl_siginfo.si_addr);
+
+ if (thread) {
+ auto &regctx = static_cast<NativeRegisterContextFreeBSD &>(
+ thread->GetRegisterContext());
+ uint32_t wp_index = LLDB_INVALID_INDEX32;
+ Status error = regctx.GetWatchpointHitIndex(
+ wp_index, reinterpret_cast<uintptr_t>(info.pl_siginfo.si_addr));
+ if (error.Fail())
+ LLDB_LOG(log,
+ "received error while checking for watchpoint hits, pid = "
+ "{0}, LWP = {1}, error = {2}",
+ pid, info.pl_lwpid, error);
+ if (wp_index != LLDB_INVALID_INDEX32) {
+ regctx.ClearWatchpointHit(wp_index);
+ thread->SetStoppedByWatchpoint(wp_index);
+ SetCurrentThreadID(thread->GetID());
+ SetState(StateType::eStateStopped, true);
+ break;
+ }
+
+ thread->SetStoppedByTrace();
+ SetCurrentThreadID(thread->GetID());
+ }
+
+ SetState(StateType::eStateStopped, true);
+ return;
+ }
+ }
+
+ // Either user-generated SIGTRAP or an unknown event that would
+ // otherwise leave the debugger hanging.
+ LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler");
+ MonitorSignal(pid, SIGTRAP);
+}
+
+void NativeProcessFreeBSD::MonitorSignal(lldb::pid_t pid, int signal) {
+ Log *log = GetLog(POSIXLog::Process);
+ struct ptrace_lwpinfo info;
+
+ const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+ return;
+ }
+ assert(info.pl_event == PL_EVENT_SIGNAL);
+ // TODO: do we need to handle !PL_FLAG_SI?
+ assert(info.pl_flags & PL_FLAG_SI);
+ assert(info.pl_siginfo.si_signo == signal);
+
+ for (const auto &abs_thread : m_threads) {
+ NativeThreadFreeBSD &thread =
+ static_cast<NativeThreadFreeBSD &>(*abs_thread);
+ assert(info.pl_lwpid >= 0);
+ if (info.pl_lwpid == 0 ||
+ static_cast<lldb::tid_t>(info.pl_lwpid) == thread.GetID()) {
+ thread.SetStoppedBySignal(info.pl_siginfo.si_signo, &info.pl_siginfo);
+ SetCurrentThreadID(thread.GetID());
+ } else
+ thread.SetStoppedWithNoReason();
+ }
+ SetState(StateType::eStateStopped, true);
+}
+
+Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
+ int data, int *result) {
+ Log *log = GetLog(POSIXLog::Ptrace);
+ Status error;
+ int ret;
+
+ errno = 0;
+ ret =
+ ptrace(req, static_cast<::pid_t>(pid), static_cast<caddr_t>(addr), data);
+
+ if (ret == -1) {
+ error = CanTrace();
+ if (error.Success())
+ error.SetErrorToErrno();
+ }
+
+ if (result)
+ *result = ret;
+
+ LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
+
+ if (error.Fail())
+ LLDB_LOG(log, "ptrace() failed: {0}", error);
+
+ return error;
+}
+
+llvm::Expected<llvm::ArrayRef<uint8_t>>
+NativeProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
+ static const uint8_t g_arm_opcode[] = {0xfe, 0xde, 0xff, 0xe7};
+ static const uint8_t g_thumb_opcode[] = {0x01, 0xde};
+
+ switch (GetArchitecture().GetMachine()) {
+ case llvm::Triple::arm:
+ switch (size_hint) {
+ case 2:
+ return llvm::ArrayRef(g_thumb_opcode);
+ case 4:
+ return llvm::ArrayRef(g_arm_opcode);
+ default:
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Unrecognised trap opcode size hint!");
+ }
+ default:
+ return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);
+ }
+}
+
+Status NativeProcessFreeBSD::Resume(const ResumeActionList &resume_actions) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ Status ret;
+
+ int signal = 0;
+ for (const auto &abs_thread : m_threads) {
+ assert(abs_thread && "thread list should not contain NULL threads");
+ NativeThreadFreeBSD &thread =
+ static_cast<NativeThreadFreeBSD &>(*abs_thread);
+
+ const ResumeAction *action =
+ resume_actions.GetActionForThread(thread.GetID(), true);
+ // we need to explicit issue suspend requests, so it is simpler to map it
+ // into proper action
+ ResumeAction suspend_action{thread.GetID(), eStateSuspended,
+ LLDB_INVALID_SIGNAL_NUMBER};
+
+ if (action == nullptr) {
+ LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
+ thread.GetID());
+ action = &suspend_action;
+ }
+
+ LLDB_LOG(
+ log,
+ "processing resume action state {0} signal {1} for pid {2} tid {3}",
+ action->state, action->signal, GetID(), thread.GetID());
+
+ switch (action->state) {
+ case eStateRunning:
+ ret = thread.Resume();
+ break;
+ case eStateStepping:
+ ret = thread.SingleStep();
+ break;
+ case eStateSuspended:
+ case eStateStopped:
+ if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
+ return Status("Passing signal to suspended thread unsupported");
+
+ ret = thread.Suspend();
+ break;
+
+ default:
+ return Status(
+ "NativeProcessFreeBSD::%s (): unexpected state %s specified "
+ "for pid %" PRIu64 ", tid %" PRIu64,
+ __FUNCTION__, StateAsCString(action->state), GetID(), thread.GetID());
+ }
+
+ if (!ret.Success())
+ return ret;
+ if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
+ signal = action->signal;
+ }
+
+ ret =
+ PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);
+ if (ret.Success())
+ SetState(eStateRunning, true);
+ return ret;
+}
+
+Status NativeProcessFreeBSD::Halt() {
+ Status error;
+
+ // Do not try to stop a process that's already stopped, this may cause
+ // the SIGSTOP to get queued and stop the process again once resumed.
+ if (StateIsStoppedState(m_state, false))
+ return error;
+ if (kill(GetID(), SIGSTOP) != 0)
+ error.SetErrorToErrno();
+ return error;
+}
+
+Status NativeProcessFreeBSD::Detach() {
+ Status error;
+
+ // Stop monitoring the inferior.
+ m_sigchld_handle.reset();
+
+ // Tell ptrace to detach from the process.
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ return error;
+
+ return PtraceWrapper(PT_DETACH, GetID());
+}
+
+Status NativeProcessFreeBSD::Signal(int signo) {
+ Status error;
+
+ if (kill(GetID(), signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Status NativeProcessFreeBSD::Interrupt() { return Halt(); }
+
+Status NativeProcessFreeBSD::Kill() {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ Status 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.
+ LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", 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;
+ }
+
+ return PtraceWrapper(PT_KILL, m_pid);
+}
+
+Status NativeProcessFreeBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+
+ if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
+ // We're done.
+ return Status("unsupported");
+ }
+
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail()) {
+ return error;
+ }
+
+ 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->first;
+ // Sanity check assumption that memory map entries are ascending.
+ assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
+ "descending memory map entries detected, unexpected");
+ prev_base_address = proc_entry_info.GetRange().GetRangeBase();
+ UNUSED_IF_ASSERT_DISABLED(prev_base_address);
+ // 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);
+ range_info.SetMapped(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);
+ range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
+ range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
+ return error;
+}
+
+Status NativeProcessFreeBSD::PopulateMemoryRegionCache() {
+ Log *log = GetLog(POSIXLog::Process);
+ // 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()) {
+ LLDB_LOG(log, "reusing {0} cached memory region entries",
+ m_mem_region_cache.size());
+ return Status();
+ }
+
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, static_cast<int>(m_pid)};
+ int ret;
+ size_t len;
+
+ ret = ::sysctl(mib, 4, nullptr, &len, nullptr, 0);
+ if (ret != 0) {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ return Status("sysctl() for KERN_PROC_VMMAP failed");
+ }
+
+ std::unique_ptr<WritableMemoryBuffer> buf =
+ llvm::WritableMemoryBuffer::getNewMemBuffer(len);
+ ret = ::sysctl(mib, 4, buf->getBufferStart(), &len, nullptr, 0);
+ if (ret != 0) {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ return Status("sysctl() for KERN_PROC_VMMAP failed");
+ }
+
+ char *bp = buf->getBufferStart();
+ char *end = bp + len;
+ while (bp < end) {
+ auto *kv = reinterpret_cast<struct kinfo_vmentry *>(bp);
+ if (kv->kve_structsize == 0)
+ break;
+ bp += kv->kve_structsize;
+
+ MemoryRegionInfo info;
+ info.Clear();
+ info.GetRange().SetRangeBase(kv->kve_start);
+ info.GetRange().SetRangeEnd(kv->kve_end);
+ info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
+
+ if (kv->kve_protection & VM_PROT_READ)
+ info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (kv->kve_protection & VM_PROT_WRITE)
+ info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (kv->kve_protection & VM_PROT_EXECUTE)
+ info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (kv->kve_path[0])
+ info.SetName(kv->kve_path);
+
+ m_mem_region_cache.emplace_back(info,
+ FileSpec(info.GetName().GetCString()));
+ }
+
+ if (m_mem_region_cache.empty()) {
+ // No entries after attempting to read them. This shouldn't happen. Assume
+ // we don't support map entries.
+ LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "
+ "for memory region metadata retrieval");
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ return Status("not supported");
+ }
+ LLDB_LOG(log, "read {0} memory region entries from process {1}",
+ m_mem_region_cache.size(), GetID());
+ // We support memory retrieval, remember that.
+ m_supports_mem_region = LazyBool::eLazyBoolYes;
+
+ return Status();
+}
+
+size_t NativeProcessFreeBSD::UpdateThreads() { return m_threads.size(); }
+
+Status NativeProcessFreeBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) {
+ if (hardware)
+ return SetHardwareBreakpoint(addr, size);
+ return SetSoftwareBreakpoint(addr, size);
+}
+
+Status NativeProcessFreeBSD::GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) {
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail()) {
+ auto status = CanTrace();
+ if (status.Fail())
+ return status;
+ return error;
+ }
+
+ FileSpec module_file_spec(module_path);
+ FileSystem::Instance().Resolve(module_file_spec);
+
+ file_spec.Clear();
+ for (const auto &it : m_mem_region_cache) {
+ if (it.second.GetFilename() == module_file_spec.GetFilename()) {
+ file_spec = it.second;
+ return Status();
+ }
+ }
+ return Status("Module file (%s) not found in process' memory map!",
+ module_file_spec.GetFilename().AsCString());
+}
+
+Status
+NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) {
+ load_addr = LLDB_INVALID_ADDRESS;
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail()) {
+ auto status = CanTrace();
+ if (status.Fail())
+ return status;
+ return error;
+ }
+
+ FileSpec file(file_name);
+ for (const auto &it : m_mem_region_cache) {
+ if (it.second == file) {
+ load_addr = it.first.GetRange().GetRangeBase();
+ return Status();
+ }
+ }
+ return Status("No load address found for file %s.", file_name.str().c_str());
+}
+
+void NativeProcessFreeBSD::SigchldHandler() {
+ Log *log = GetLog(POSIXLog::Process);
+ int status;
+ ::pid_t wait_pid =
+ llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WNOHANG);
+
+ if (wait_pid == 0)
+ return;
+
+ if (wait_pid == -1) {
+ Status error(errno, eErrorTypePOSIX);
+ LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
+ return;
+ }
+
+ WaitStatus wait_status = WaitStatus::Decode(status);
+ bool exited = wait_status.type == WaitStatus::Exit ||
+ (wait_status.type == WaitStatus::Signal &&
+ wait_pid == static_cast<::pid_t>(GetID()));
+
+ LLDB_LOG(log,
+ "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
+ GetID(), wait_pid, status, exited);
+
+ if (exited)
+ MonitorExited(wait_pid, wait_status);
+ else {
+ assert(wait_status.type == WaitStatus::Stop);
+ MonitorCallback(wait_pid, wait_status.status);
+ }
+}
+
+bool NativeProcessFreeBSD::HasThreadNoLock(lldb::tid_t thread_id) {
+ for (const auto &thread : m_threads) {
+ assert(thread && "thread list should not contain NULL threads");
+ if (thread->GetID() == thread_id) {
+ // We have this thread.
+ return true;
+ }
+ }
+
+ // We don't have this thread.
+ return false;
+}
+
+NativeThreadFreeBSD &NativeProcessFreeBSD::AddThread(lldb::tid_t thread_id) {
+ Log *log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
+
+ assert(thread_id > 0);
+ 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);
+
+ m_threads.push_back(std::make_unique<NativeThreadFreeBSD>(*this, thread_id));
+ return static_cast<NativeThreadFreeBSD &>(*m_threads.back());
+}
+
+void NativeProcessFreeBSD::RemoveThread(lldb::tid_t thread_id) {
+ Log *log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);
+
+ assert(thread_id > 0);
+ assert(HasThreadNoLock(thread_id) &&
+ "attempted to remove a thread that does not exist");
+
+ for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
+ if ((*it)->GetID() == thread_id) {
+ m_threads.erase(it);
+ break;
+ }
+ }
+
+ if (GetCurrentThreadID() == thread_id)
+ SetCurrentThreadID(m_threads.front()->GetID());
+}
+
+Status NativeProcessFreeBSD::Attach() {
+ // Attach to the requested process.
+ // An attach will cause the thread to stop with a SIGSTOP.
+ Status status = PtraceWrapper(PT_ATTACH, m_pid);
+ if (status.Fail())
+ return status;
+
+ int wstatus;
+ // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this
+ // point we should have a thread stopped if waitpid succeeds.
+ if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr, 0)) <
+ 0)
+ return Status(errno, eErrorTypePOSIX);
+
+ // Initialize threads and tracing status
+ // NB: this needs to be called before we set thread state
+ status = SetupTrace();
+ if (status.Fail())
+ return status;
+
+ for (const auto &thread : m_threads)
+ static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+
+ // Let our process instance know the thread has stopped.
+ SetCurrentThreadID(m_threads.front()->GetID());
+ SetState(StateType::eStateStopped, false);
+ return Status();
+}
+
+Status NativeProcessFreeBSD::ReadMemory(lldb::addr_t addr, void *buf,
+ size_t size, size_t &bytes_read) {
+ unsigned char *dst = static_cast<unsigned char *>(buf);
+ struct ptrace_io_desc io;
+
+ Log *log = GetLog(POSIXLog::Memory);
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_read = 0;
+ io.piod_op = PIOD_READ_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_offs = (void *)(addr + bytes_read);
+ io.piod_addr = dst + bytes_read;
+
+ Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail() || io.piod_len == 0)
+ return error;
+
+ bytes_read += io.piod_len;
+ io.piod_len = size - bytes_read;
+ } while (bytes_read < size);
+
+ return Status();
+}
+
+Status NativeProcessFreeBSD::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);
+ Status error;
+ struct ptrace_io_desc io;
+
+ Log *log = GetLog(POSIXLog::Memory);
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_written = 0;
+ io.piod_op = PIOD_WRITE_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_addr =
+ const_cast<void *>(static_cast<const void *>(src + bytes_written));
+ io.piod_offs = (void *)(addr + bytes_written);
+
+ Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail() || io.piod_len == 0)
+ return error;
+
+ bytes_written += io.piod_len;
+ io.piod_len = size - bytes_written;
+ } while (bytes_written < size);
+
+ return error;
+}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+NativeProcessFreeBSD::GetAuxvData() const {
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV, static_cast<int>(GetID())};
+ size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo);
+ std::unique_ptr<WritableMemoryBuffer> buf =
+ llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
+
+ if (::sysctl(mib, 4, buf->getBufferStart(), &auxv_size, nullptr, 0) != 0)
+ return std::error_code(errno, std::generic_category());
+
+ return buf;
+}
+
+Status NativeProcessFreeBSD::SetupTrace() {
+ // Enable event reporting
+ int events;
+ Status status =
+ PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
+ if (status.Fail())
+ return status;
+ events |= PTRACE_LWP | PTRACE_FORK | PTRACE_VFORK;
+ status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
+ if (status.Fail())
+ return status;
+
+ return ReinitializeThreads();
+}
+
+Status NativeProcessFreeBSD::ReinitializeThreads() {
+ // Clear old threads
+ m_threads.clear();
+
+ int num_lwps;
+ Status error = PtraceWrapper(PT_GETNUMLWPS, GetID(), nullptr, 0, &num_lwps);
+ if (error.Fail())
+ return error;
+
+ std::vector<lwpid_t> lwp_ids;
+ lwp_ids.resize(num_lwps);
+ error = PtraceWrapper(PT_GETLWPLIST, GetID(), lwp_ids.data(),
+ lwp_ids.size() * sizeof(lwpid_t), &num_lwps);
+ if (error.Fail())
+ return error;
+
+ // Reinitialize from scratch threads and register them in process
+ for (lwpid_t lwp : lwp_ids)
+ AddThread(lwp);
+
+ return error;
+}
+
+bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const {
+ return !m_arch.IsMIPS();
+}
+
+void NativeProcessFreeBSD::MonitorClone(::pid_t child_pid, bool is_vfork,
+ NativeThreadFreeBSD &parent_thread) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "fork, child_pid={0}", child_pid);
+
+ int status;
+ ::pid_t wait_pid =
+ llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);
+ if (wait_pid != child_pid) {
+ LLDB_LOG(log,
+ "waiting for pid {0} failed. Assuming the pid has "
+ "disappeared in the meantime",
+ child_pid);
+ return;
+ }
+ if (WIFEXITED(status)) {
+ LLDB_LOG(log,
+ "waiting for pid {0} returned an 'exited' event. Not "
+ "tracking it.",
+ child_pid);
+ return;
+ }
+
+ struct ptrace_lwpinfo info;
+ const auto siginfo_err = PtraceWrapper(PT_LWPINFO, child_pid, &info, sizeof(info));
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+ return;
+ }
+ assert(info.pl_event == PL_EVENT_SIGNAL);
+ lldb::tid_t child_tid = info.pl_lwpid;
+
+ std::unique_ptr<NativeProcessFreeBSD> child_process{
+ new NativeProcessFreeBSD(static_cast<::pid_t>(child_pid), m_terminal_fd,
+ m_delegate, m_arch, m_main_loop)};
+ if (!is_vfork)
+ child_process->m_software_breakpoints = m_software_breakpoints;
+
+ Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork;
+ if ((m_enabled_extensions & expected_ext) == expected_ext) {
+ child_process->SetupTrace();
+ for (const auto &thread : child_process->m_threads)
+ static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+ child_process->SetState(StateType::eStateStopped, false);
+
+ m_delegate.NewSubprocess(this, std::move(child_process));
+ if (is_vfork)
+ parent_thread.SetStoppedByVFork(child_pid, child_tid);
+ else
+ parent_thread.SetStoppedByFork(child_pid, child_tid);
+ SetState(StateType::eStateStopped, true);
+ } else {
+ child_process->Detach();
+ Status pt_error =
+ PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0);
+ if (pt_error.Fail()) {
+ LLDB_LOG_ERROR(log, pt_error.ToError(),
+ "unable to resume parent process {1}: {0}", GetID());
+ SetState(StateType::eStateInvalid);
+ }
+ }
+}
+
+llvm::Expected<std::string>
+NativeProcessFreeBSD::SaveCore(llvm::StringRef path_hint) {
+#if defined(PT_COREDUMP)
+ using namespace llvm::sys::fs;
+
+ llvm::SmallString<128> path{path_hint};
+ Status error;
+ struct ptrace_coredump pc = {};
+
+ // Try with the suggested path first. If there is no suggested path or it
+ // failed to open, use a temporary file.
+ if (path.empty() ||
+ openFile(path, pc.pc_fd, CD_CreateNew, FA_Write, OF_None)) {
+ if (std::error_code errc =
+ createTemporaryFile("lldb", "core", pc.pc_fd, path))
+ return llvm::createStringError(errc, "Unable to create a temporary file");
+ }
+ error = PtraceWrapper(PT_COREDUMP, GetID(), &pc, sizeof(pc));
+
+ std::error_code close_err = closeFile(pc.pc_fd);
+ if (error.Fail())
+ return error.ToError();
+ if (close_err)
+ return llvm::createStringError(
+ close_err, "Unable to close the core dump after writing");
+ return path.str().str();
+#else // !defined(PT_COREDUMP)
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "PT_COREDUMP not supported in the FreeBSD version used to build LLDB");
+#endif
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h
new file mode 100644
index 000000000000..b638367ebbaa
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h
@@ -0,0 +1,136 @@
+//===-- NativeProcessFreeBSD.h -------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeProcessFreeBSD_H_
+#define liblldb_NativeProcessFreeBSD_H_
+
+#include "Plugins/Process/POSIX/NativeProcessELF.h"
+#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"
+
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/FileSpec.h"
+
+#include "NativeThreadFreeBSD.h"
+
+namespace lldb_private {
+namespace process_freebsd {
+/// \class NativeProcessFreeBSD
+/// 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 NativeProcessFreeBSD : public NativeProcessELF,
+ private NativeProcessSoftwareSingleStep {
+public:
+ class Manager : public NativeProcessProtocol::Manager {
+ public:
+ using NativeProcessProtocol::Manager::Manager;
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Launch(ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate) override;
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override;
+
+ Extension GetSupportedExtensions() const override;
+ };
+
+ // NativeProcessProtocol Interface
+ Status Resume(const ResumeActionList &resume_actions) override;
+
+ Status Halt() override;
+
+ Status Detach() override;
+
+ Status Signal(int signo) override;
+
+ Status Interrupt() override;
+
+ Status Kill() override;
+
+ Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
+
+ Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) override;
+
+ Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+ size_t &bytes_written) override;
+
+ size_t UpdateThreads() override;
+
+ const ArchSpec &GetArchitecture() const override { return m_arch; }
+
+ Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) override;
+
+ // The two following methods are probably not necessary and probably
+ // will never be called. Nevertheless, we implement them right now
+ // to reduce the differences between different platforms and reduce
+ // the risk of the lack of implementation actually breaking something,
+ // at least for the time being.
+ Status GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) override;
+ Status GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) override;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ GetAuxvData() const override;
+
+ // Interface used by NativeRegisterContext-derived classes.
+ static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
+ int data = 0, int *result = nullptr);
+
+ bool SupportHardwareSingleStepping() const;
+
+ llvm::Expected<std::string> SaveCore(llvm::StringRef path_hint) override;
+
+protected:
+ llvm::Expected<llvm::ArrayRef<uint8_t>>
+ GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;
+
+private:
+ MainLoop::SignalHandleUP m_sigchld_handle;
+ ArchSpec m_arch;
+ MainLoop& m_main_loop;
+ LazyBool m_supports_mem_region = eLazyBoolCalculate;
+ std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
+
+ // Private Instance Methods
+ NativeProcessFreeBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
+ const ArchSpec &arch, MainLoop &mainloop);
+
+ bool HasThreadNoLock(lldb::tid_t thread_id);
+
+ NativeThreadFreeBSD &AddThread(lldb::tid_t thread_id);
+ void RemoveThread(lldb::tid_t thread_id);
+
+ void MonitorCallback(lldb::pid_t pid, int signal);
+ void MonitorExited(lldb::pid_t pid, WaitStatus status);
+ void MonitorSIGSTOP(lldb::pid_t pid);
+ void MonitorSIGTRAP(lldb::pid_t pid);
+ void MonitorSignal(lldb::pid_t pid, int signal);
+ void MonitorClone(::pid_t child_pid, bool is_vfork,
+ NativeThreadFreeBSD &parent_thread);
+
+ Status PopulateMemoryRegionCache();
+ void SigchldHandler();
+
+ Status Attach();
+ Status SetupTrace();
+ Status ReinitializeThreads();
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeProcessFreeBSD_H_
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.cpp
new file mode 100644
index 000000000000..3d744f773a26
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.cpp
@@ -0,0 +1,29 @@
+//===-- NativeRegisterContextFreeBSD.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextFreeBSD.h"
+
+#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+// clang-format on
+
+NativeProcessFreeBSD &NativeRegisterContextFreeBSD::GetProcess() {
+ return static_cast<NativeProcessFreeBSD &>(m_thread.GetProcess());
+}
+
+::pid_t NativeRegisterContextFreeBSD::GetProcessPid() {
+ return GetProcess().GetID();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h
new file mode 100644
index 000000000000..b7f659ef24de
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h
@@ -0,0 +1,42 @@
+//===-- NativeRegisterContextFreeBSD.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextFreeBSD_h
+#define lldb_NativeRegisterContextFreeBSD_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+class NativeThreadFreeBSD;
+
+class NativeRegisterContextFreeBSD
+ : public virtual NativeRegisterContextRegisterInfo {
+public:
+ // This function is implemented in the NativeRegisterContextFreeBSD_*
+ // subclasses to create a new instance of the host specific
+ // NativeRegisterContextFreeBSD. The implementations can't collide as only one
+ // NativeRegisterContextFreeBSD_* variant should be compiled into the final
+ // executable.
+ static NativeRegisterContextFreeBSD *
+ CreateHostNativeRegisterContextFreeBSD(const ArchSpec &target_arch,
+ NativeThreadFreeBSD &native_thread);
+ virtual llvm::Error
+ CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) = 0;
+
+protected:
+ virtual NativeProcessFreeBSD &GetProcess();
+ virtual ::pid_t GetProcessPid();
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_h
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp
new file mode 100644
index 000000000000..f19085600d6c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp
@@ -0,0 +1,202 @@
+//===-- NativeRegisterContextFreeBSD_arm.cpp ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__arm__)
+
+#include "NativeRegisterContextFreeBSD_arm.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+// clang-format on
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+NativeRegisterContextFreeBSD *
+NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+ const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
+ return new NativeRegisterContextFreeBSD_arm(target_arch, native_thread);
+}
+
+NativeRegisterContextFreeBSD_arm::NativeRegisterContextFreeBSD_arm(
+ const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
+ : NativeRegisterContextRegisterInfo(
+ native_thread, new RegisterInfoPOSIX_arm(target_arch)) {}
+
+RegisterInfoPOSIX_arm &
+NativeRegisterContextFreeBSD_arm::GetRegisterInfo() const {
+ return static_cast<RegisterInfoPOSIX_arm &>(*m_register_info_interface_up);
+}
+
+uint32_t NativeRegisterContextFreeBSD_arm::GetRegisterSetCount() const {
+ return GetRegisterInfo().GetRegisterSetCount();
+}
+
+const RegisterSet *
+NativeRegisterContextFreeBSD_arm::GetRegisterSet(uint32_t set_index) const {
+ return GetRegisterInfo().GetRegisterSet(set_index);
+}
+
+uint32_t NativeRegisterContextFreeBSD_arm::GetUserRegisterCount() const {
+ uint32_t count = 0;
+ for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
+ count += GetRegisterSet(set_index)->num_registers;
+ return count;
+}
+
+Status NativeRegisterContextFreeBSD_arm::ReadRegisterSet(uint32_t set) {
+ switch (set) {
+ case RegisterInfoPOSIX_arm::GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
+ m_reg_data.data());
+ case RegisterInfoPOSIX_arm::FPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(
+ PT_GETVFPREGS, m_thread.GetID(),
+ m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR));
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_arm::ReadRegisterSet");
+}
+
+Status NativeRegisterContextFreeBSD_arm::WriteRegisterSet(uint32_t set) {
+ switch (set) {
+ case RegisterInfoPOSIX_arm::GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
+ m_reg_data.data());
+ case RegisterInfoPOSIX_arm::FPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(
+ PT_SETVFPREGS, m_thread.GetID(),
+ m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR));
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_arm::WriteRegisterSet");
+}
+
+Status
+NativeRegisterContextFreeBSD_arm::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status 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)
+ return Status("no lldb regnum for %s", reg_info && reg_info->name
+ ? reg_info->name
+ : "<unknown register>");
+
+ uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+ reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
+ reg_info->byte_size, endian::InlHostByteOrder());
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_arm::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+ Status error;
+
+ if (!reg_info)
+ return Status("reg_info NULL");
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (reg == LLDB_INVALID_REGNUM)
+ return Status("no lldb regnum for %s", reg_info && reg_info->name
+ ? reg_info->name
+ : "<unknown register>");
+
+ uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+ ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
+ reg_info->byte_size);
+
+ return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextFreeBSD_arm::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ Status error;
+
+ error = ReadRegisterSet(RegisterInfoPOSIX_arm::GPRegSet);
+ if (error.Fail())
+ return error;
+
+ error = ReadRegisterSet(RegisterInfoPOSIX_arm::FPRegSet);
+ if (error.Fail())
+ return error;
+
+ data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, m_reg_data.data(), m_reg_data.size());
+
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_arm::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_arm::%s invalid data_sp provided",
+ __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize() != m_reg_data.size()) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_arm::%s data_sp contained mismatched "
+ "data size, expected %" PRIu64 ", actual %" PRIu64,
+ __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
+ return error;
+ }
+
+ const uint8_t *src = data_sp->GetBytes();
+ if (src == nullptr) {
+ error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm::%s "
+ "DataBuffer::GetBytes() returned a null "
+ "pointer",
+ __FUNCTION__);
+ return error;
+ }
+ ::memcpy(m_reg_data.data(), src, m_reg_data.size());
+
+ error = WriteRegisterSet(RegisterInfoPOSIX_arm::GPRegSet);
+ if (error.Fail())
+ return error;
+
+ return WriteRegisterSet(RegisterInfoPOSIX_arm::FPRegSet);
+}
+
+llvm::Error NativeRegisterContextFreeBSD_arm::CopyHardwareWatchpointsFrom(
+ NativeRegisterContextFreeBSD &source) {
+ return llvm::Error::success();
+}
+
+#endif // defined (__arm__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.h
new file mode 100644
index 000000000000..b9537e6952f6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.h
@@ -0,0 +1,68 @@
+//===-- NativeRegisterContextFreeBSD_arm.h ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__arm__)
+
+#ifndef lldb_NativeRegisterContextFreeBSD_arm_h
+#define lldb_NativeRegisterContextFreeBSD_arm_h
+
+// clang-format off
+#include <sys/types.h>
+#include <machine/reg.h>
+#include <machine/vfp.h>
+// clang-format on
+
+#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
+
+#include <array>
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD_arm : public NativeRegisterContextFreeBSD {
+public:
+ NativeRegisterContextFreeBSD_arm(const ArchSpec &target_arch,
+ NativeThreadFreeBSD &native_thread);
+
+ uint32_t GetRegisterSetCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+
+ const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+ Status ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ llvm::Error
+ CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
+
+private:
+ std::array<uint8_t, sizeof(reg) + sizeof(vfp_state)> m_reg_data;
+
+ Status ReadRegisterSet(uint32_t set);
+ Status WriteRegisterSet(uint32_t set);
+
+ RegisterInfoPOSIX_arm &GetRegisterInfo() const;
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_arm_h
+
+#endif // defined (__arm__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
new file mode 100644
index 000000000000..28ea8b7ac118
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
@@ -0,0 +1,302 @@
+//===-- NativeRegisterContextFreeBSD_arm64.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__aarch64__)
+
+#include "NativeRegisterContextFreeBSD_arm64.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+// clang-format on
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+// A NativeRegisterContext is constructed per thread, but all threads' registers
+// will contain the same fields. Therefore this mutex prevents each instance
+// competing with the other, and subsequent instances from having to detect the
+// fields all over again.
+static std::mutex g_register_flags_detector_mutex;
+static Arm64RegisterFlagsDetector g_register_flags_detector;
+
+NativeRegisterContextFreeBSD *
+NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+ const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
+ std::lock_guard<std::mutex> lock(g_register_flags_detector_mutex);
+ if (!g_register_flags_detector.HasDetected()) {
+ NativeProcessFreeBSD &process = native_thread.GetProcess();
+ g_register_flags_detector.DetectFields(
+ process.GetAuxValue(AuxVector::AUXV_FREEBSD_AT_HWCAP).value_or(0),
+ process.GetAuxValue(AuxVector::AUXV_AT_HWCAP2).value_or(0));
+ }
+
+ return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread);
+}
+
+NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64(
+ const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
+ : NativeRegisterContextRegisterInfo(
+ native_thread, new RegisterInfoPOSIX_arm64(target_arch, 0))
+#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
+ ,
+ m_read_dbreg(false)
+#endif
+{
+ g_register_flags_detector.UpdateRegisterInfo(
+ GetRegisterInfoInterface().GetRegisterInfo(),
+ GetRegisterInfoInterface().GetRegisterCount());
+
+ ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
+ ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
+}
+
+RegisterInfoPOSIX_arm64 &
+NativeRegisterContextFreeBSD_arm64::GetRegisterInfo() const {
+ return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up);
+}
+
+uint32_t NativeRegisterContextFreeBSD_arm64::GetRegisterSetCount() const {
+ return GetRegisterInfo().GetRegisterSetCount();
+}
+
+const RegisterSet *
+NativeRegisterContextFreeBSD_arm64::GetRegisterSet(uint32_t set_index) const {
+ return GetRegisterInfo().GetRegisterSet(set_index);
+}
+
+uint32_t NativeRegisterContextFreeBSD_arm64::GetUserRegisterCount() const {
+ uint32_t count = 0;
+ for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
+ count += GetRegisterSet(set_index)->num_registers;
+ return count;
+}
+
+Status NativeRegisterContextFreeBSD_arm64::ReadRegisterSet(uint32_t set) {
+ switch (set) {
+ case RegisterInfoPOSIX_arm64::GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
+ m_reg_data.data());
+ case RegisterInfoPOSIX_arm64::FPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(
+ PT_GETFPREGS, m_thread.GetID(),
+ m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR));
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_arm64::ReadRegisterSet");
+}
+
+Status NativeRegisterContextFreeBSD_arm64::WriteRegisterSet(uint32_t set) {
+ switch (set) {
+ case RegisterInfoPOSIX_arm64::GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
+ m_reg_data.data());
+ case RegisterInfoPOSIX_arm64::FPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(
+ PT_SETFPREGS, m_thread.GetID(),
+ m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR));
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_arm64::WriteRegisterSet");
+}
+
+Status
+NativeRegisterContextFreeBSD_arm64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status 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)
+ return Status("no lldb regnum for %s", reg_info && reg_info->name
+ ? reg_info->name
+ : "<unknown register>");
+
+ uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+ reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
+ reg_info->byte_size, endian::InlHostByteOrder());
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_arm64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+ Status error;
+
+ if (!reg_info)
+ return Status("reg_info NULL");
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (reg == LLDB_INVALID_REGNUM)
+ return Status("no lldb regnum for %s", reg_info && reg_info->name
+ ? reg_info->name
+ : "<unknown register>");
+
+ uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+ ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
+ reg_info->byte_size);
+
+ return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextFreeBSD_arm64::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ Status error;
+
+ error = ReadRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet);
+ if (error.Fail())
+ return error;
+
+ error = ReadRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet);
+ if (error.Fail())
+ return error;
+
+ data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, m_reg_data.data(), m_reg_data.size());
+
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_arm64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_arm64::%s invalid data_sp provided",
+ __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize() != m_reg_data.size()) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_arm64::%s data_sp contained mismatched "
+ "data size, expected %" PRIu64 ", actual %" PRIu64,
+ __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
+ return error;
+ }
+
+ const uint8_t *src = data_sp->GetBytes();
+ if (src == nullptr) {
+ error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm64::%s "
+ "DataBuffer::GetBytes() returned a null "
+ "pointer",
+ __FUNCTION__);
+ return error;
+ }
+ ::memcpy(m_reg_data.data(), src, m_reg_data.size());
+
+ error = WriteRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet);
+ if (error.Fail())
+ return error;
+
+ return WriteRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet);
+}
+
+llvm::Error NativeRegisterContextFreeBSD_arm64::CopyHardwareWatchpointsFrom(
+ NativeRegisterContextFreeBSD &source) {
+#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
+ auto &r_source = static_cast<NativeRegisterContextFreeBSD_arm64 &>(source);
+ llvm::Error error = r_source.ReadHardwareDebugInfo();
+ if (error)
+ return error;
+
+ m_dbreg = r_source.m_dbreg;
+ m_hbp_regs = r_source.m_hbp_regs;
+ m_hwp_regs = r_source.m_hwp_regs;
+ m_max_hbp_supported = r_source.m_max_hbp_supported;
+ m_max_hwp_supported = r_source.m_max_hwp_supported;
+ m_read_dbreg = true;
+
+ // on FreeBSD this writes both breakpoints and watchpoints
+ return WriteHardwareDebugRegs(eDREGTypeWATCH);
+#else
+ return llvm::Error::success();
+#endif
+}
+
+llvm::Error NativeRegisterContextFreeBSD_arm64::ReadHardwareDebugInfo() {
+#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
+ Log *log = GetLog(POSIXLog::Registers);
+
+ // we're fully stateful, so no need to reread control registers ever
+ if (m_read_dbreg)
+ return llvm::Error::success();
+
+ Status res = NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS,
+ m_thread.GetID(), &m_dbreg);
+ if (res.Fail())
+ return res.ToError();
+
+ LLDB_LOG(log, "m_dbreg read: debug_ver={0}, nbkpts={1}, nwtpts={2}",
+ m_dbreg.db_debug_ver, m_dbreg.db_nbkpts, m_dbreg.db_nwtpts);
+ m_max_hbp_supported = m_dbreg.db_nbkpts;
+ m_max_hwp_supported = m_dbreg.db_nwtpts;
+ assert(m_max_hbp_supported <= m_hbp_regs.size());
+ assert(m_max_hwp_supported <= m_hwp_regs.size());
+
+ m_read_dbreg = true;
+ return llvm::Error::success();
+#else
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Hardware breakpoints/watchpoints require FreeBSD 14.0");
+#endif
+}
+
+llvm::Error
+NativeRegisterContextFreeBSD_arm64::WriteHardwareDebugRegs(DREGType) {
+#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
+ assert(m_read_dbreg && "dbregs must be read before writing them back");
+
+ // copy data from m_*_regs to m_dbreg before writing it back
+ for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
+ m_dbreg.db_breakregs[i].dbr_addr = m_hbp_regs[i].address;
+ m_dbreg.db_breakregs[i].dbr_ctrl = m_hbp_regs[i].control;
+ }
+ for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
+ m_dbreg.db_watchregs[i].dbw_addr = m_hwp_regs[i].address;
+ m_dbreg.db_watchregs[i].dbw_ctrl = m_hwp_regs[i].control;
+ }
+
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(),
+ &m_dbreg)
+ .ToError();
+#else
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Hardware breakpoints/watchpoints require FreeBSD 14.0");
+#endif
+}
+
+#endif // defined (__aarch64__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h
new file mode 100644
index 000000000000..ba876006c6c5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h
@@ -0,0 +1,86 @@
+//===-- NativeRegisterContextFreeBSD_arm64.h --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__aarch64__)
+
+#ifndef lldb_NativeRegisterContextFreeBSD_arm64_h
+#define lldb_NativeRegisterContextFreeBSD_arm64_h
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/param.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+
+#include <array>
+
+#if __FreeBSD_version >= 1300139
+# define LLDB_HAS_FREEBSD_WATCHPOINT 1
+#endif
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD_arm64
+ : public NativeRegisterContextFreeBSD,
+ public NativeRegisterContextDBReg_arm64 {
+public:
+ NativeRegisterContextFreeBSD_arm64(const ArchSpec &target_arch,
+ NativeThreadFreeBSD &native_thread);
+
+ uint32_t GetRegisterSetCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+
+ const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+ Status ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ llvm::Error
+ CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
+
+private:
+ // Due to alignment, FreeBSD reg/fpreg are a few bytes larger than
+ // LLDB's GPR/FPU structs. However, all fields have matching offsets
+ // and sizes, so we do not have to worry about these (and we have
+ // a unittest to assert that).
+ std::array<uint8_t, sizeof(reg) + sizeof(fpreg)> m_reg_data;
+#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
+ dbreg m_dbreg;
+ bool m_read_dbreg;
+#endif
+
+ Status ReadRegisterSet(uint32_t set);
+ Status WriteRegisterSet(uint32_t set);
+
+ llvm::Error ReadHardwareDebugInfo() override;
+ llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
+
+ RegisterInfoPOSIX_arm64 &GetRegisterInfo() const;
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_arm64_h
+
+#endif // defined (__aarch64__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp
new file mode 100644
index 000000000000..090d0f3802c3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp
@@ -0,0 +1,239 @@
+//===-- NativeRegisterContextFreeBSD_mips64.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__mips64__)
+
+#include "NativeRegisterContextFreeBSD_mips64.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
+#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h"
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+// clang-format on
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+NativeRegisterContextFreeBSD *
+NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+ const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
+ return new NativeRegisterContextFreeBSD_mips64(target_arch, native_thread);
+}
+
+NativeRegisterContextFreeBSD_mips64::NativeRegisterContextFreeBSD_mips64(
+ const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
+ : NativeRegisterContextRegisterInfo(
+ native_thread, new RegisterContextFreeBSD_mips64(target_arch)) {}
+
+RegisterContextFreeBSD_mips64 &
+NativeRegisterContextFreeBSD_mips64::GetRegisterInfo() const {
+ return static_cast<RegisterContextFreeBSD_mips64 &>(
+ *m_register_info_interface_up);
+}
+
+uint32_t NativeRegisterContextFreeBSD_mips64::GetRegisterSetCount() const {
+ return GetRegisterInfo().GetRegisterSetCount();
+}
+
+const RegisterSet *
+NativeRegisterContextFreeBSD_mips64::GetRegisterSet(uint32_t set_index) const {
+ return GetRegisterInfo().GetRegisterSet(set_index);
+}
+
+uint32_t NativeRegisterContextFreeBSD_mips64::GetUserRegisterCount() const {
+ uint32_t count = 0;
+ for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
+ count += GetRegisterSet(set_index)->num_registers;
+ return count;
+}
+
+std::optional<NativeRegisterContextFreeBSD_mips64::RegSetKind>
+NativeRegisterContextFreeBSD_mips64::GetSetForNativeRegNum(
+ uint32_t reg_num) const {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::mips64:
+ if (reg_num >= k_first_gpr_mips64 && reg_num <= k_last_gpr_mips64)
+ return GPRegSet;
+ if (reg_num >= k_first_fpr_mips64 && reg_num <= k_last_fpr_mips64)
+ return FPRegSet;
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ llvm_unreachable("Register does not belong to any register set");
+}
+
+Status NativeRegisterContextFreeBSD_mips64::ReadRegisterSet(RegSetKind set) {
+ switch (set) {
+ case GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
+ m_reg_data.data());
+ case FPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(
+ PT_GETFPREGS, m_thread.GetID(),
+ m_reg_data.data() + GetRegisterInfo().GetGPRSize());
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_mips64::ReadRegisterSet");
+}
+
+Status NativeRegisterContextFreeBSD_mips64::WriteRegisterSet(RegSetKind set) {
+ switch (set) {
+ case GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
+ m_reg_data.data());
+ case FPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(
+ PT_SETFPREGS, m_thread.GetID(),
+ m_reg_data.data() + GetRegisterInfo().GetGPRSize());
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_mips64::WriteRegisterSet");
+}
+
+Status
+NativeRegisterContextFreeBSD_mips64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status 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)
+ return Status("no lldb regnum for %s", reg_info && reg_info->name
+ ? reg_info->name
+ : "<unknown register>");
+
+ std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ RegSetKind set = *opt_set;
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+ reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
+ reg_info->byte_size, endian::InlHostByteOrder());
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_mips64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+ Status error;
+
+ if (!reg_info)
+ return Status("reg_info NULL");
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (reg == LLDB_INVALID_REGNUM)
+ return Status("no lldb regnum for %s", reg_info && reg_info->name
+ ? reg_info->name
+ : "<unknown register>");
+
+ std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ RegSetKind set = *opt_set;
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+ ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
+ reg_info->byte_size);
+
+ return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextFreeBSD_mips64::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ Status error;
+
+ error = ReadRegisterSet(GPRegSet);
+ if (error.Fail())
+ return error;
+
+ error = ReadRegisterSet(FPRegSet);
+ if (error.Fail())
+ return error;
+
+ data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, m_reg_data.data(), m_reg_data.size());
+
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_mips64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_mips64::%s invalid data_sp provided",
+ __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize() != m_reg_data.size()) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_mips64::%s data_sp contained mismatched "
+ "data size, expected %" PRIu64 ", actual %" PRIu64,
+ __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
+ return error;
+ }
+
+ const uint8_t *src = data_sp->GetBytes();
+ if (src == nullptr) {
+ error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_mips64::%s "
+ "DataBuffer::GetBytes() returned a null "
+ "pointer",
+ __FUNCTION__);
+ return error;
+ }
+ ::memcpy(m_reg_data.data(), src, m_reg_data.size());
+
+ error = WriteRegisterSet(GPRegSet);
+ if (error.Fail())
+ return error;
+
+ return WriteRegisterSet(FPRegSet);
+}
+
+llvm::Error NativeRegisterContextFreeBSD_mips64::CopyHardwareWatchpointsFrom(
+ NativeRegisterContextFreeBSD &source) {
+ return llvm::Error::success();
+}
+
+#endif // defined (__mips64__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h
new file mode 100644
index 000000000000..286b4fd8d8b9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h
@@ -0,0 +1,75 @@
+//===-- NativeRegisterContextFreeBSD_mips64.h -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__mips64__)
+
+#ifndef lldb_NativeRegisterContextFreeBSD_mips64_h
+#define lldb_NativeRegisterContextFreeBSD_mips64_h
+
+// clang-format off
+#include <sys/types.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
+
+#include <array>
+#include <optional>
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD_mips64
+ : public NativeRegisterContextFreeBSD {
+public:
+ NativeRegisterContextFreeBSD_mips64(const ArchSpec &target_arch,
+ NativeThreadFreeBSD &native_thread);
+
+ uint32_t GetRegisterSetCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+
+ const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+ Status ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ llvm::Error
+ CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
+
+private:
+ enum RegSetKind {
+ GPRegSet,
+ FPRegSet,
+ };
+ std::array<uint8_t, sizeof(reg) + sizeof(fpreg)> m_reg_data;
+
+ std::optional<RegSetKind> GetSetForNativeRegNum(uint32_t reg_num) const;
+
+ Status ReadRegisterSet(RegSetKind set);
+ Status WriteRegisterSet(RegSetKind set);
+
+ RegisterContextFreeBSD_mips64 &GetRegisterInfo() const;
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_mips64_h
+
+#endif // defined (__mips64__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp
new file mode 100644
index 000000000000..fd5eb1ee2a1c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp
@@ -0,0 +1,290 @@
+//===-- NativeRegisterContextFreeBSD_powerpc.cpp --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__powerpc__)
+
+#include "NativeRegisterContextFreeBSD_powerpc.h"
+
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
+// for register enum definitions
+#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+// clang-format on
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+static const uint32_t g_gpr_regnums[] = {
+ gpr_r0_powerpc, gpr_r1_powerpc, gpr_r2_powerpc, gpr_r3_powerpc,
+ gpr_r4_powerpc, gpr_r5_powerpc, gpr_r6_powerpc, gpr_r7_powerpc,
+ gpr_r8_powerpc, gpr_r9_powerpc, gpr_r10_powerpc, gpr_r11_powerpc,
+ gpr_r12_powerpc, gpr_r13_powerpc, gpr_r14_powerpc, gpr_r15_powerpc,
+ gpr_r16_powerpc, gpr_r17_powerpc, gpr_r18_powerpc, gpr_r19_powerpc,
+ gpr_r20_powerpc, gpr_r21_powerpc, gpr_r22_powerpc, gpr_r23_powerpc,
+ gpr_r24_powerpc, gpr_r25_powerpc, gpr_r26_powerpc, gpr_r27_powerpc,
+ gpr_r28_powerpc, gpr_r29_powerpc, gpr_r30_powerpc, gpr_r31_powerpc,
+ gpr_lr_powerpc, gpr_cr_powerpc, gpr_xer_powerpc, gpr_ctr_powerpc,
+ gpr_pc_powerpc,
+};
+
+static const uint32_t g_fpr_regnums[] = {
+ fpr_f0_powerpc, fpr_f1_powerpc, fpr_f2_powerpc, fpr_f3_powerpc,
+ fpr_f4_powerpc, fpr_f5_powerpc, fpr_f6_powerpc, fpr_f7_powerpc,
+ fpr_f8_powerpc, fpr_f9_powerpc, fpr_f10_powerpc, fpr_f11_powerpc,
+ fpr_f12_powerpc, fpr_f13_powerpc, fpr_f14_powerpc, fpr_f15_powerpc,
+ fpr_f16_powerpc, fpr_f17_powerpc, fpr_f18_powerpc, fpr_f19_powerpc,
+ fpr_f20_powerpc, fpr_f21_powerpc, fpr_f22_powerpc, fpr_f23_powerpc,
+ fpr_f24_powerpc, fpr_f25_powerpc, fpr_f26_powerpc, fpr_f27_powerpc,
+ fpr_f28_powerpc, fpr_f29_powerpc, fpr_f30_powerpc, fpr_f31_powerpc,
+ fpr_fpscr_powerpc,
+};
+
+// Number of register sets provided by this context.
+enum { k_num_register_sets = 2 };
+
+static const RegisterSet g_reg_sets_powerpc[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_powerpc,
+ g_gpr_regnums},
+ {"Floating Point Registers", "fpr", k_num_fpr_registers_powerpc,
+ g_fpr_regnums},
+};
+
+NativeRegisterContextFreeBSD *
+NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+ const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
+ return new NativeRegisterContextFreeBSD_powerpc(target_arch, native_thread);
+}
+
+static RegisterInfoInterface *
+CreateRegisterInfoInterface(const ArchSpec &target_arch) {
+ if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) {
+ return new RegisterContextFreeBSD_powerpc32(target_arch);
+ } else {
+ assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
+ "Register setting path assumes this is a 64-bit host");
+ return new RegisterContextFreeBSD_powerpc64(target_arch);
+ }
+}
+
+NativeRegisterContextFreeBSD_powerpc::NativeRegisterContextFreeBSD_powerpc(
+ const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
+ : NativeRegisterContextRegisterInfo(
+ native_thread, CreateRegisterInfoInterface(target_arch)) {}
+
+RegisterContextFreeBSD_powerpc &
+NativeRegisterContextFreeBSD_powerpc::GetRegisterInfo() const {
+ return static_cast<RegisterContextFreeBSD_powerpc &>(
+ *m_register_info_interface_up);
+}
+
+uint32_t NativeRegisterContextFreeBSD_powerpc::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
+const RegisterSet *
+NativeRegisterContextFreeBSD_powerpc::GetRegisterSet(uint32_t set_index) const {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::ppc:
+ return &g_reg_sets_powerpc[set_index];
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+}
+
+std::optional<NativeRegisterContextFreeBSD_powerpc::RegSetKind>
+NativeRegisterContextFreeBSD_powerpc::GetSetForNativeRegNum(
+ uint32_t reg_num) const {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::ppc:
+ if (reg_num >= k_first_gpr_powerpc && reg_num <= k_last_gpr_powerpc)
+ return GPRegSet;
+ if (reg_num >= k_first_fpr && reg_num <= k_last_fpr)
+ return FPRegSet;
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ llvm_unreachable("Register does not belong to any register set");
+}
+
+uint32_t NativeRegisterContextFreeBSD_powerpc::GetUserRegisterCount() const {
+ uint32_t count = 0;
+ for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
+ count += GetRegisterSet(set_index)->num_registers;
+ return count;
+}
+
+Status NativeRegisterContextFreeBSD_powerpc::ReadRegisterSet(RegSetKind set) {
+ switch (set) {
+ case GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
+ m_reg_data.data());
+ case FPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(),
+ m_reg_data.data() + sizeof(reg));
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_powerpc::ReadRegisterSet");
+}
+
+Status NativeRegisterContextFreeBSD_powerpc::WriteRegisterSet(RegSetKind set) {
+ switch (set) {
+ case GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
+ m_reg_data.data());
+ case FPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(),
+ m_reg_data.data() + sizeof(reg));
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_powerpc::WriteRegisterSet");
+}
+
+Status
+NativeRegisterContextFreeBSD_powerpc::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status 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)
+ return Status("no lldb regnum for %s", reg_info && reg_info->name
+ ? reg_info->name
+ : "<unknown register>");
+
+ std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ RegSetKind set = *opt_set;
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+ reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
+ reg_info->byte_size, endian::InlHostByteOrder());
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_powerpc::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+ Status error;
+
+ if (!reg_info)
+ return Status("reg_info NULL");
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (reg == LLDB_INVALID_REGNUM)
+ return Status("no lldb regnum for %s", reg_info && reg_info->name
+ ? reg_info->name
+ : "<unknown register>");
+
+ std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ RegSetKind set = *opt_set;
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+ ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
+ reg_info->byte_size);
+
+ return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextFreeBSD_powerpc::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ Status error;
+
+ error = ReadRegisterSet(GPRegSet);
+ if (error.Fail())
+ return error;
+
+ error = ReadRegisterSet(FPRegSet);
+ if (error.Fail())
+ return error;
+
+ data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, m_reg_data.data(), m_reg_data.size());
+
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_powerpc::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_powerpc::%s invalid data_sp provided",
+ __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize() != m_reg_data.size()) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_powerpc::%s data_sp contained mismatched "
+ "data size, expected %zu, actual %" PRIu64,
+ __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
+ return error;
+ }
+
+ const uint8_t *src = data_sp->GetBytes();
+ if (src == nullptr) {
+ error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_powerpc::%s "
+ "DataBuffer::GetBytes() returned a null "
+ "pointer",
+ __FUNCTION__);
+ return error;
+ }
+ ::memcpy(m_reg_data.data(), src, m_reg_data.size());
+
+ error = WriteRegisterSet(GPRegSet);
+ if (error.Fail())
+ return error;
+
+ return WriteRegisterSet(FPRegSet);
+}
+
+llvm::Error NativeRegisterContextFreeBSD_powerpc::CopyHardwareWatchpointsFrom(
+ NativeRegisterContextFreeBSD &source) {
+ return llvm::Error::success();
+}
+
+#endif // defined (__powerpc__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.h
new file mode 100644
index 000000000000..420db822acc0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.h
@@ -0,0 +1,75 @@
+//===-- NativeRegisterContextFreeBSD_powerpc.h ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__powerpc__)
+
+#ifndef lldb_NativeRegisterContextFreeBSD_powerpc_h
+#define lldb_NativeRegisterContextFreeBSD_powerpc_h
+
+// clang-format off
+#include <sys/types.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
+
+#include <array>
+#include <optional>
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD_powerpc
+ : public NativeRegisterContextFreeBSD {
+public:
+ NativeRegisterContextFreeBSD_powerpc(const ArchSpec &target_arch,
+ NativeThreadFreeBSD &native_thread);
+
+ uint32_t GetRegisterSetCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+
+ const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+ Status ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ llvm::Error
+ CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
+
+private:
+ enum RegSetKind {
+ GPRegSet,
+ FPRegSet,
+ };
+ std::array<uint8_t, sizeof(reg) + sizeof(fpreg)> m_reg_data;
+
+ std::optional<RegSetKind> GetSetForNativeRegNum(uint32_t reg_num) const;
+
+ Status ReadRegisterSet(RegSetKind set);
+ Status WriteRegisterSet(RegSetKind set);
+
+ RegisterContextFreeBSD_powerpc &GetRegisterInfo() const;
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_powerpc_h
+
+#endif // defined (__powerpc__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp
new file mode 100644
index 000000000000..5eed2d02b0a8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp
@@ -0,0 +1,657 @@
+//===-- NativeRegisterContextFreeBSD_x86_64.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include "NativeRegisterContextFreeBSD_x86_64.h"
+
+// clang-format off
+#include <x86/fpu.h>
+#include <x86/specialreg.h>
+#include <cpuid.h>
+// clang-format on
+
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+#include "NativeProcessFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+#include <optional>
+
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+// 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_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64,
+ lldb_fdp_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");
+
+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");
+
+static const uint32_t g_mpx_regnums_x86_64[] = {
+ // Note: we currently do not provide them but this is needed to avoid
+ // unnamed groups in SBFrame::GetRegisterContext().
+ lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64,
+ lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) -
+ 1 ==
+ k_num_mpx_registers_x86_64,
+ "g_mpx_regnums_x86_64 has wrong number of register infos");
+
+// x86 debug registers.
+static const uint32_t g_dbr_regnums_x86_64[] = {
+ lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64,
+ lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) -
+ 1 ==
+ k_num_dbr_registers_x86_64,
+ "g_dbr_regnums_x86_64 has wrong number of register infos");
+
+// x86 32-bit general purpose registers.
+static 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.
+static 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");
+
+static 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");
+
+static const uint32_t g_mpx_regnums_i386[] = {
+ // Note: we currently do not provide them but this is needed to avoid
+ // unnamed groups in SBFrame::GetRegisterContext().
+ lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386,
+ lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) -
+ 1 ==
+ k_num_mpx_registers_i386,
+ "g_mpx_regnums_i386 has wrong number of register infos");
+
+// x86 debug registers.
+static const uint32_t g_dbr_regnums_i386[] = {
+ lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386,
+ lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) -
+ 1 ==
+ k_num_dbr_registers_i386,
+ "g_dbr_regnums_i386 has wrong number of register infos");
+
+// Number of register sets provided by this context.
+enum { k_num_register_sets = 5 };
+
+// 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},
+ {"Debug Registers", "dbr", k_num_dbr_registers_i386, g_dbr_regnums_i386},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386,
+ g_avx_regnums_i386},
+ {"Memory Protection Extensions", "mpx", k_num_mpx_registers_i386,
+ g_mpx_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},
+ {"Debug Registers", "dbr", k_num_dbr_registers_x86_64,
+ g_dbr_regnums_x86_64},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64,
+ g_avx_regnums_x86_64},
+ {"Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64,
+ g_mpx_regnums_x86_64},
+};
+
+#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
+
+NativeRegisterContextFreeBSD *
+NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+ const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
+ return new NativeRegisterContextFreeBSD_x86_64(target_arch, native_thread);
+}
+
+// NativeRegisterContextFreeBSD_x86_64 members.
+
+static RegisterInfoInterface *
+CreateRegisterInfoInterface(const ArchSpec &target_arch) {
+ if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) {
+ // 32-bit hosts run with a RegisterContextFreeBSD_i386 context.
+ return new RegisterContextFreeBSD_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 RegisterContextFreeBSD_x86_64(target_arch);
+ }
+}
+
+NativeRegisterContextFreeBSD_x86_64::NativeRegisterContextFreeBSD_x86_64(
+ const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
+ : NativeRegisterContextRegisterInfo(
+ native_thread, CreateRegisterInfoInterface(target_arch)),
+ NativeRegisterContextDBReg_x86(native_thread), m_regset_offsets({0}) {
+ assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize());
+ std::array<uint32_t, MaxRegSet + 1> first_regnos;
+
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ first_regnos[FPRegSet] = lldb_fctrl_i386;
+ first_regnos[DBRegSet] = lldb_dr0_i386;
+ break;
+ case llvm::Triple::x86_64:
+ first_regnos[FPRegSet] = lldb_fctrl_x86_64;
+ first_regnos[DBRegSet] = lldb_dr0_x86_64;
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ for (int i : {FPRegSet, DBRegSet})
+ m_regset_offsets[i] = GetRegisterInfoInterface()
+ .GetRegisterInfo()[first_regnos[i]]
+ .byte_offset;
+}
+
+uint32_t NativeRegisterContextFreeBSD_x86_64::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
+const RegisterSet *
+NativeRegisterContextFreeBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
+ 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:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+}
+
+std::optional<NativeRegisterContextFreeBSD_x86_64::RegSetKind>
+NativeRegisterContextFreeBSD_x86_64::GetSetForNativeRegNum(
+ uint32_t reg_num) const {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386)
+ return GPRegSet;
+ if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386)
+ return FPRegSet;
+ if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386)
+ return YMMRegSet;
+ if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386)
+ return std::nullopt; // MPXR
+ if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386)
+ return std::nullopt; // MPXC
+ if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386)
+ return DBRegSet; // DBR
+ break;
+ case llvm::Triple::x86_64:
+ if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64)
+ return GPRegSet;
+ if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64)
+ return FPRegSet;
+ if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64)
+ return YMMRegSet;
+ if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64)
+ return std::nullopt; // MPXR
+ if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64)
+ return std::nullopt; // MPXC
+ if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64)
+ return DBRegSet; // DBR
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ llvm_unreachable("Register does not belong to any register set");
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet(RegSetKind set) {
+ switch (set) {
+ case GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
+ m_gpr.data());
+ case FPRegSet:
+#if defined(__x86_64__)
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(),
+ m_fpr.data());
+#else
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETXMMREGS, m_thread.GetID(),
+ m_fpr.data());
+#endif
+ case DBRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, m_thread.GetID(),
+ m_dbr.data());
+ case YMMRegSet:
+ case MPXRegSet: {
+ struct ptrace_xstate_info info;
+ Status ret = NativeProcessFreeBSD::PtraceWrapper(
+ PT_GETXSTATE_INFO, GetProcessPid(), &info, sizeof(info));
+ if (!ret.Success())
+ return ret;
+
+ assert(info.xsave_mask & XFEATURE_ENABLED_X87);
+ assert(info.xsave_mask & XFEATURE_ENABLED_SSE);
+
+ m_xsave_offsets[YMMRegSet] = LLDB_INVALID_XSAVE_OFFSET;
+ if (info.xsave_mask & XFEATURE_ENABLED_YMM_HI128) {
+ uint32_t eax, ecx, edx;
+ __get_cpuid_count(0x0D, 2, &eax, &m_xsave_offsets[YMMRegSet], &ecx, &edx);
+ }
+
+ m_xsave.resize(info.xsave_len);
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETXSTATE, GetProcessPid(),
+ m_xsave.data(), m_xsave.size());
+ }
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet");
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet(RegSetKind set) {
+ switch (set) {
+ case GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
+ m_gpr.data());
+ case FPRegSet:
+#if defined(__x86_64__)
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(),
+ m_fpr.data());
+#else
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETXMMREGS, m_thread.GetID(),
+ m_fpr.data());
+#endif
+ case DBRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(),
+ m_dbr.data());
+ case YMMRegSet:
+ case MPXRegSet:
+ // ReadRegisterSet() must always be called before WriteRegisterSet().
+ assert(m_xsave.size() > 0);
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETXSTATE, GetProcessPid(),
+ m_xsave.data(), m_xsave.size());
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet");
+}
+
+Status
+NativeRegisterContextFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ 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;
+ }
+
+ std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ RegSetKind set = opt_set.value();
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ switch (set) {
+ case GPRegSet:
+ case FPRegSet:
+ case DBRegSet: {
+ void *data = GetOffsetRegSetData(set, reg_info->byte_offset);
+ FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_fpr.data());
+ if (data == &fpr->ftag) // ftag
+ reg_value.SetUInt16(
+ AbridgedToFullTagWord(fpr->ftag, fpr->fstat, fpr->stmm));
+ else
+ reg_value.SetBytes(data, reg_info->byte_size, endian::InlHostByteOrder());
+ break;
+ }
+ case YMMRegSet: {
+ std::optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
+ if (!ymm_reg) {
+ error.SetErrorStringWithFormat(
+ "register \"%s\" not supported by CPU/kernel", reg_info->name);
+ } else {
+ YMMReg ymm = XStateToYMM(ymm_reg->xmm, ymm_reg->ymm_hi);
+ reg_value.SetBytes(ymm.bytes, reg_info->byte_size,
+ endian::InlHostByteOrder());
+ }
+ break;
+ }
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
+
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+
+ Status error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ 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;
+ }
+
+ std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ RegSetKind set = opt_set.value();
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ switch (set) {
+ case GPRegSet:
+ case FPRegSet:
+ case DBRegSet: {
+ void *data = GetOffsetRegSetData(set, reg_info->byte_offset);
+ FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_fpr.data());
+ if (data == &fpr->ftag) // ftag
+ fpr->ftag = FullToAbridgedTagWord(reg_value.GetAsUInt16());
+ else
+ ::memcpy(data, reg_value.GetBytes(), reg_value.GetByteSize());
+ break;
+ }
+ case YMMRegSet: {
+ std::optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
+ if (!ymm_reg) {
+ error.SetErrorStringWithFormat(
+ "register \"%s\" not supported by CPU/kernel", reg_info->name);
+ } else {
+ YMMReg ymm;
+ ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+ YMMToXState(ymm, ymm_reg->xmm, ymm_reg->ymm_hi);
+ }
+ break;
+ }
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
+
+ return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ Status error;
+
+ data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
+ error = ReadRegisterSet(GPRegSet);
+ if (error.Fail())
+ return error;
+
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, m_gpr.data(), GetRegisterInfoInterface().GetGPRSize());
+ dst += GetRegisterInfoInterface().GetGPRSize();
+
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_x86_64::%s invalid data_sp provided",
+ __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_x86_64::%s data_sp contained mismatched "
+ "data size, expected %zu, actual %" PRIu64,
+ __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
+ return error;
+ }
+
+ const uint8_t *src = data_sp->GetBytes();
+ if (src == nullptr) {
+ error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_x86_64::%s "
+ "DataBuffer::GetBytes() returned a null "
+ "pointer",
+ __FUNCTION__);
+ return error;
+ }
+ ::memcpy(m_gpr.data(), src, GetRegisterInfoInterface().GetGPRSize());
+
+ error = WriteRegisterSet(GPRegSet);
+ if (error.Fail())
+ return error;
+ src += GetRegisterInfoInterface().GetGPRSize();
+
+ return error;
+}
+
+llvm::Error NativeRegisterContextFreeBSD_x86_64::CopyHardwareWatchpointsFrom(
+ NativeRegisterContextFreeBSD &source) {
+ auto &r_source = static_cast<NativeRegisterContextFreeBSD_x86_64 &>(source);
+ // NB: This implicitly reads the whole dbreg set.
+ RegisterValue dr7;
+ Status res = r_source.ReadRegister(GetDR(7), dr7);
+ if (!res.Fail()) {
+ // copy dbregs only if any watchpoints were set
+ if ((dr7.GetAsUInt64() & 0xFF) == 0)
+ return llvm::Error::success();
+
+ m_dbr = r_source.m_dbr;
+ res = WriteRegisterSet(DBRegSet);
+ }
+ return res.ToError();
+}
+
+uint8_t *
+NativeRegisterContextFreeBSD_x86_64::GetOffsetRegSetData(RegSetKind set,
+ size_t reg_offset) {
+ uint8_t *base;
+ switch (set) {
+ case GPRegSet:
+ base = m_gpr.data();
+ break;
+ case FPRegSet:
+ base = m_fpr.data();
+ break;
+ case DBRegSet:
+ base = m_dbr.data();
+ break;
+ case YMMRegSet:
+ llvm_unreachable("GetRegSetData() is unsuitable for this regset.");
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
+ assert(reg_offset >= m_regset_offsets[set]);
+ return base + (reg_offset - m_regset_offsets[set]);
+}
+
+std::optional<NativeRegisterContextFreeBSD_x86_64::YMMSplitPtr>
+NativeRegisterContextFreeBSD_x86_64::GetYMMSplitReg(uint32_t reg) {
+ uint32_t offset = m_xsave_offsets[YMMRegSet];
+ if (offset == LLDB_INVALID_XSAVE_OFFSET)
+ return std::nullopt;
+
+ uint32_t reg_index;
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ reg_index = reg - lldb_ymm0_i386;
+ break;
+ case llvm::Triple::x86_64:
+ reg_index = reg - lldb_ymm0_x86_64;
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ auto *fpreg = reinterpret_cast<struct savexmm_ymm *>(m_xsave.data());
+ auto *ymmreg = reinterpret_cast<struct ymmacc *>(m_xsave.data() + offset);
+
+ return YMMSplitPtr{&fpreg->sv_xmm[reg_index], &ymmreg[reg_index]};
+}
+
+#endif // defined(__x86_64__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h
new file mode 100644
index 000000000000..a522d850cb37
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h
@@ -0,0 +1,97 @@
+//===-- NativeRegisterContextFreeBSD_x86_64.h -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifndef lldb_NativeRegisterContextFreeBSD_x86_64_h
+#define lldb_NativeRegisterContextFreeBSD_x86_64_h
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include <array>
+#include <optional>
+
+#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterContext_x86.h"
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+#define LLDB_INVALID_XSAVE_OFFSET UINT32_MAX
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD_x86_64
+ : public NativeRegisterContextFreeBSD,
+ public NativeRegisterContextDBReg_x86 {
+public:
+ NativeRegisterContextFreeBSD_x86_64(const ArchSpec &target_arch,
+ NativeThreadFreeBSD &native_thread);
+ uint32_t GetRegisterSetCount() const override;
+
+ const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+ Status ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ llvm::Error
+ CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
+
+private:
+ // Private member types.
+ enum RegSetKind {
+ GPRegSet,
+ FPRegSet,
+ DBRegSet,
+ YMMRegSet,
+ MPXRegSet,
+ MaxRegSet = MPXRegSet,
+ };
+
+ // Private member variables.
+ std::array<uint8_t, sizeof(struct reg)> m_gpr;
+ std::array<uint8_t, 512> m_fpr; // FXSAVE
+ std::array<uint8_t, sizeof(struct dbreg)> m_dbr;
+ std::vector<uint8_t> m_xsave;
+ std::array<uint32_t, MaxRegSet + 1> m_xsave_offsets;
+ std::array<size_t, MaxRegSet + 1> m_regset_offsets;
+
+ std::optional<RegSetKind> GetSetForNativeRegNum(uint32_t reg_num) const;
+
+ Status ReadRegisterSet(RegSetKind set);
+ Status WriteRegisterSet(RegSetKind set);
+
+ uint8_t *GetOffsetRegSetData(RegSetKind set, size_t reg_offset);
+
+ struct YMMSplitPtr {
+ void *xmm;
+ void *ymm_hi;
+ };
+ std::optional<YMMSplitPtr> GetYMMSplitReg(uint32_t reg);
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_x86_64_h
+
+#endif // defined(__x86_64__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp
new file mode 100644
index 000000000000..a0de7751c7e5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp
@@ -0,0 +1,345 @@
+//===-- NativeThreadFreeBSD.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadFreeBSD.h"
+#include "NativeRegisterContextFreeBSD.h"
+
+#include "NativeProcessFreeBSD.h"
+
+#include "Plugins/Process/POSIX/CrashReason.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/State.h"
+#include "llvm/Support/Errno.h"
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+// clang-format on
+
+#include <sstream>
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process,
+ lldb::tid_t tid)
+ : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
+ m_stop_info(),
+ m_reg_context_up(
+ NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+ process.GetArchitecture(), *this)),
+ m_stop_description() {}
+
+Status NativeThreadFreeBSD::Resume() {
+ Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());
+ if (!ret.Success())
+ return ret;
+ ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID());
+ // we can get EINVAL if the architecture in question does not support
+ // hardware single-stepping -- that's fine, we have nothing to clear
+ // then
+ if (ret.GetError() == EINVAL)
+ ret.Clear();
+ if (ret.Success())
+ SetRunning();
+ return ret;
+}
+
+Status NativeThreadFreeBSD::SingleStep() {
+ Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());
+ if (!ret.Success())
+ return ret;
+ ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, GetID());
+ if (ret.Success())
+ SetStepping();
+ return ret;
+}
+
+Status NativeThreadFreeBSD::Suspend() {
+ Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_SUSPEND, GetID());
+ if (ret.Success())
+ SetStopped();
+ return ret;
+}
+
+void NativeThreadFreeBSD::SetStoppedBySignal(uint32_t signo,
+ const siginfo_t *info) {
+ Log *log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
+
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.signo = signo;
+
+ m_stop_description.clear();
+ if (info) {
+ switch (signo) {
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ m_stop_description = GetCrashReasonString(*info);
+ break;
+ }
+ }
+}
+
+void NativeThreadFreeBSD::SetStoppedByBreakpoint() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonBreakpoint;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedByTrace() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonTrace;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedByExec() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonExec;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
+ lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
+
+ std::ostringstream ostr;
+ ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
+ ostr << wp_index;
+
+ ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
+
+ SetStopped();
+ m_stop_description = ostr.str();
+ m_stop_info.reason = StopReason::eStopReasonWatchpoint;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedByFork(lldb::pid_t child_pid,
+ lldb::tid_t child_tid) {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonFork;
+ m_stop_info.signo = SIGTRAP;
+ m_stop_info.details.fork.child_pid = child_pid;
+ m_stop_info.details.fork.child_tid = child_tid;
+}
+
+void NativeThreadFreeBSD::SetStoppedByVFork(lldb::pid_t child_pid,
+ lldb::tid_t child_tid) {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonVFork;
+ m_stop_info.signo = SIGTRAP;
+ m_stop_info.details.fork.child_pid = child_pid;
+ m_stop_info.details.fork.child_tid = child_tid;
+}
+
+void NativeThreadFreeBSD::SetStoppedByVForkDone() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonVForkDone;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedWithNoReason() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+ m_stop_info.signo = 0;
+}
+
+void NativeThreadFreeBSD::SetStopped() {
+ const StateType new_state = StateType::eStateStopped;
+ m_state = new_state;
+ m_stop_description.clear();
+}
+
+void NativeThreadFreeBSD::SetRunning() {
+ m_state = StateType::eStateRunning;
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void NativeThreadFreeBSD::SetStepping() {
+ m_state = StateType::eStateStepping;
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+std::string NativeThreadFreeBSD::GetName() {
+ Log *log = GetLog(POSIXLog::Thread);
+
+ std::vector<struct kinfo_proc> kp;
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
+ static_cast<int>(GetProcess().GetID())};
+
+ while (1) {
+ size_t len = kp.size() * sizeof(struct kinfo_proc);
+ void *ptr = len == 0 ? nullptr : kp.data();
+ int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0);
+ if (ptr == nullptr || (error != 0 && errno == ENOMEM)) {
+ kp.resize(len / sizeof(struct kinfo_proc));
+ continue;
+ }
+ if (error != 0) {
+ len = 0;
+ LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}",
+ GetID(), m_state, strerror(errno));
+ }
+ kp.resize(len / sizeof(struct kinfo_proc));
+ break;
+ }
+
+ for (auto &procinfo : kp) {
+ if (procinfo.ki_tid == static_cast<lwpid_t>(GetID()))
+ return procinfo.ki_tdname;
+ }
+
+ return "";
+}
+
+lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; }
+
+bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) {
+ Log *log = GetLog(POSIXLog::Thread);
+ description.clear();
+
+ switch (m_state) {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ case eStateUnloaded:
+ stop_info = m_stop_info;
+ description = m_stop_description;
+
+ return true;
+
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
+ StateAsCString(m_state));
+ return false;
+ }
+ llvm_unreachable("unhandled StateType!");
+}
+
+NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() {
+ assert(m_reg_context_up);
+ return *m_reg_context_up;
+}
+
+Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, bool hardware) {
+ assert(m_state == eStateStopped);
+ if (!hardware)
+ return Status("not implemented");
+ Status error = RemoveWatchpoint(addr);
+ if (error.Fail())
+ return error;
+ uint32_t wp_index =
+ GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return Status("Setting hardware watchpoint failed.");
+ m_watchpoint_index_map.insert({addr, wp_index});
+ return Status();
+}
+
+Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) {
+ auto wp = m_watchpoint_index_map.find(addr);
+ if (wp == m_watchpoint_index_map.end())
+ return Status();
+ uint32_t wp_index = wp->second;
+ m_watchpoint_index_map.erase(wp);
+ if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
+ return Status();
+ return Status("Clearing hardware watchpoint failed.");
+}
+
+Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ assert(m_state == eStateStopped);
+ Status error = RemoveHardwareBreakpoint(addr);
+ if (error.Fail())
+ return error;
+
+ uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
+
+ if (bp_index == LLDB_INVALID_INDEX32)
+ return Status("Setting hardware breakpoint failed.");
+
+ m_hw_break_index_map.insert({addr, bp_index});
+ return Status();
+}
+
+Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+ auto bp = m_hw_break_index_map.find(addr);
+ if (bp == m_hw_break_index_map.end())
+ return Status();
+
+ uint32_t bp_index = bp->second;
+ if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
+ m_hw_break_index_map.erase(bp);
+ return Status();
+ }
+
+ return Status("Clearing hardware breakpoint failed.");
+}
+
+llvm::Error
+NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) {
+ llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
+ source.GetRegisterContext());
+ if (!s) {
+ m_watchpoint_index_map = source.m_watchpoint_index_map;
+ m_hw_break_index_map = source.m_hw_break_index_map;
+ }
+ return s;
+}
+
+NativeProcessFreeBSD &NativeThreadFreeBSD::GetProcess() {
+ return static_cast<NativeProcessFreeBSD &>(m_process);
+}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+NativeThreadFreeBSD::GetSiginfo() const {
+ Log *log = GetLog(POSIXLog::Process);
+
+ struct ptrace_lwpinfo info;
+ const auto siginfo_err = NativeProcessFreeBSD::PtraceWrapper(
+ PT_LWPINFO, GetID(), &info, sizeof(info));
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+ return siginfo_err.ToError();
+ }
+
+ if (info.pl_event != PL_EVENT_SIGNAL)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Thread not signaled");
+ if (!(info.pl_flags & PL_FLAG_SI))
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No siginfo for thread");
+
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::StringRef(reinterpret_cast<const char *>(&info.pl_siginfo),
+ sizeof(info.pl_siginfo)));
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h
new file mode 100644
index 000000000000..edfb07658e19
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h
@@ -0,0 +1,91 @@
+//===-- NativeThreadFreeBSD.h --------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeThreadFreeBSD_H_
+#define liblldb_NativeThreadFreeBSD_H_
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
+
+#include <csignal>
+#include <map>
+#include <string>
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeThreadFreeBSD : public NativeThreadProtocol {
+ friend class NativeProcessFreeBSD;
+
+public:
+ NativeThreadFreeBSD(NativeProcessFreeBSD &process, lldb::tid_t tid);
+
+ // NativeThreadProtocol Interface
+ std::string GetName() override;
+
+ lldb::StateType GetState() override;
+
+ bool GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) override;
+
+ NativeRegisterContextFreeBSD &GetRegisterContext() override;
+
+ Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+ bool hardware) override;
+
+ Status RemoveWatchpoint(lldb::addr_t addr) override;
+
+ Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+ Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+
+ NativeProcessFreeBSD &GetProcess();
+
+ llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+ GetSiginfo() const override;
+
+private:
+ // Interface for friend classes
+
+ Status Resume();
+ Status SingleStep();
+ Status Suspend();
+
+ void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
+ void SetStoppedByBreakpoint();
+ void SetStoppedByTrace();
+ void SetStoppedByExec();
+ void SetStoppedByWatchpoint(uint32_t wp_index);
+ void SetStoppedByFork(lldb::pid_t child_pid, lldb::tid_t child_tid);
+ void SetStoppedByVFork(lldb::pid_t child_pid, lldb::tid_t child_tid);
+ void SetStoppedByVForkDone();
+ void SetStoppedWithNoReason();
+ void SetStopped();
+ void SetRunning();
+ void SetStepping();
+
+ llvm::Error CopyWatchpointsFrom(NativeThreadFreeBSD &source);
+
+ // Member Variables
+ lldb::StateType m_state;
+ ThreadStopInfo m_stop_info;
+ std::unique_ptr<NativeRegisterContextFreeBSD> m_reg_context_up;
+ std::string m_stop_description;
+ using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
+ WatchpointIndexMap m_watchpoint_index_map;
+ WatchpointIndexMap m_hw_break_index_map;
+};
+
+typedef std::shared_ptr<NativeThreadFreeBSD> NativeThreadFreeBSDSP;
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeThreadFreeBSD_H_
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
new file mode 100644
index 000000000000..635f99b4467d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
@@ -0,0 +1,335 @@
+//===-- ProcessFreeBSDKernel.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h"
+#include "ProcessFreeBSDKernel.h"
+#include "ThreadFreeBSDKernel.h"
+
+#if LLDB_ENABLE_FBSDVMCORE
+#include <fvc.h>
+#endif
+#if defined(__FreeBSD__)
+#include <kvm.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(ProcessFreeBSDKernel)
+
+namespace {
+
+#if LLDB_ENABLE_FBSDVMCORE
+class ProcessFreeBSDKernelFVC : public ProcessFreeBSDKernel {
+public:
+ ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, lldb::ListenerSP listener,
+ fvc_t *fvc, const FileSpec &core_file);
+
+ ~ProcessFreeBSDKernelFVC();
+
+ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ lldb_private::Status &error) override;
+
+private:
+ fvc_t *m_fvc;
+
+ const char *GetError();
+};
+#endif // LLDB_ENABLE_FBSDVMCORE
+
+#if defined(__FreeBSD__)
+class ProcessFreeBSDKernelKVM : public ProcessFreeBSDKernel {
+public:
+ ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener,
+ kvm_t *fvc, const FileSpec &core_file);
+
+ ~ProcessFreeBSDKernelKVM();
+
+ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ lldb_private::Status &error) override;
+
+private:
+ kvm_t *m_kvm;
+
+ const char *GetError();
+};
+#endif // defined(__FreeBSD__)
+
+} // namespace
+
+ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp,
+ ListenerSP listener_sp,
+ const FileSpec &core_file)
+ : PostMortemProcess(target_sp, listener_sp, core_file) {}
+
+lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp,
+ ListenerSP listener_sp,
+ const FileSpec *crash_file,
+ bool can_connect) {
+ ModuleSP executable = target_sp->GetExecutableModule();
+ if (crash_file && !can_connect && executable) {
+#if LLDB_ENABLE_FBSDVMCORE
+ fvc_t *fvc =
+ fvc_open(executable->GetFileSpec().GetPath().c_str(),
+ crash_file->GetPath().c_str(), nullptr, nullptr, nullptr);
+ if (fvc)
+ return std::make_shared<ProcessFreeBSDKernelFVC>(target_sp, listener_sp,
+ fvc, *crash_file);
+#endif
+
+#if defined(__FreeBSD__)
+ kvm_t *kvm =
+ kvm_open2(executable->GetFileSpec().GetPath().c_str(),
+ crash_file->GetPath().c_str(), O_RDONLY, nullptr, nullptr);
+ if (kvm)
+ return std::make_shared<ProcessFreeBSDKernelKVM>(target_sp, listener_sp,
+ kvm, *crash_file);
+#endif
+ }
+ return nullptr;
+}
+
+void ProcessFreeBSDKernel::Initialize() {
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+ });
+}
+
+void ProcessFreeBSDKernel::Terminate() {
+ PluginManager::UnregisterPlugin(ProcessFreeBSDKernel::CreateInstance);
+}
+
+Status ProcessFreeBSDKernel::DoDestroy() { return Status(); }
+
+bool ProcessFreeBSDKernel::CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) {
+ return true;
+}
+
+void ProcessFreeBSDKernel::RefreshStateAfterStop() {}
+
+bool ProcessFreeBSDKernel::DoUpdateThreadList(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 set our one
+ // and only core thread state up.
+
+ // We cannot construct a thread without a register context as that crashes
+ // LLDB but we can construct a process without threads to provide minimal
+ // memory reading support.
+ switch (GetTarget().GetArchitecture().GetMachine()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ break;
+ default:
+ return false;
+ }
+
+ Status error;
+
+ // struct field offsets are written as symbols so that we don't have
+ // to figure them out ourselves
+ int32_t offset_p_list = ReadSignedIntegerFromMemory(
+ FindSymbol("proc_off_p_list"), 4, -1, error);
+ int32_t offset_p_pid =
+ ReadSignedIntegerFromMemory(FindSymbol("proc_off_p_pid"), 4, -1, error);
+ int32_t offset_p_threads = ReadSignedIntegerFromMemory(
+ FindSymbol("proc_off_p_threads"), 4, -1, error);
+ int32_t offset_p_comm = ReadSignedIntegerFromMemory(
+ FindSymbol("proc_off_p_comm"), 4, -1, error);
+
+ int32_t offset_td_tid = ReadSignedIntegerFromMemory(
+ FindSymbol("thread_off_td_tid"), 4, -1, error);
+ int32_t offset_td_plist = ReadSignedIntegerFromMemory(
+ FindSymbol("thread_off_td_plist"), 4, -1, error);
+ int32_t offset_td_pcb = ReadSignedIntegerFromMemory(
+ FindSymbol("thread_off_td_pcb"), 4, -1, error);
+ int32_t offset_td_oncpu = ReadSignedIntegerFromMemory(
+ FindSymbol("thread_off_td_oncpu"), 4, -1, error);
+ int32_t offset_td_name = ReadSignedIntegerFromMemory(
+ FindSymbol("thread_off_td_name"), 4, -1, error);
+
+ // fail if we were not able to read any of the offsets
+ if (offset_p_list == -1 || offset_p_pid == -1 || offset_p_threads == -1 ||
+ offset_p_comm == -1 || offset_td_tid == -1 || offset_td_plist == -1 ||
+ offset_td_pcb == -1 || offset_td_oncpu == -1 || offset_td_name == -1)
+ return false;
+
+ // dumptid contains the thread-id of the crashing thread
+ // dumppcb contains its PCB
+ int32_t dumptid =
+ ReadSignedIntegerFromMemory(FindSymbol("dumptid"), 4, -1, error);
+ lldb::addr_t dumppcb = FindSymbol("dumppcb");
+
+ // stoppcbs is an array of PCBs on all CPUs
+ // each element is of size pcb_size
+ int32_t pcbsize =
+ ReadSignedIntegerFromMemory(FindSymbol("pcb_size"), 4, -1, error);
+ lldb::addr_t stoppcbs = FindSymbol("stoppcbs");
+ // In later FreeBSD versions stoppcbs is a pointer to the array.
+ int32_t osreldate =
+ ReadSignedIntegerFromMemory(FindSymbol("osreldate"), 4, -1, error);
+ if (stoppcbs != LLDB_INVALID_ADDRESS && osreldate >= 1400089)
+ stoppcbs = ReadPointerFromMemory(stoppcbs, error);
+
+ // from FreeBSD sys/param.h
+ constexpr size_t fbsd_maxcomlen = 19;
+
+ // iterate through a linked list of all processes
+ // allproc is a pointer to the first list element, p_list field
+ // (found at offset_p_list) specifies the next element
+ for (lldb::addr_t proc =
+ ReadPointerFromMemory(FindSymbol("allproc"), error);
+ proc != 0 && proc != LLDB_INVALID_ADDRESS;
+ proc = ReadPointerFromMemory(proc + offset_p_list, error)) {
+ int32_t pid =
+ ReadSignedIntegerFromMemory(proc + offset_p_pid, 4, -1, error);
+ // process' command-line string
+ char comm[fbsd_maxcomlen + 1];
+ ReadCStringFromMemory(proc + offset_p_comm, comm, sizeof(comm), error);
+
+ // iterate through a linked list of all process' threads
+ // the initial thread is found in process' p_threads, subsequent
+ // elements are linked via td_plist field
+ for (lldb::addr_t td =
+ ReadPointerFromMemory(proc + offset_p_threads, error);
+ td != 0; td = ReadPointerFromMemory(td + offset_td_plist, error)) {
+ int32_t tid =
+ ReadSignedIntegerFromMemory(td + offset_td_tid, 4, -1, error);
+ lldb::addr_t pcb_addr =
+ ReadPointerFromMemory(td + offset_td_pcb, error);
+ // whether process was on CPU (-1 if not, otherwise CPU number)
+ int32_t oncpu =
+ ReadSignedIntegerFromMemory(td + offset_td_oncpu, 4, -2, error);
+ // thread name
+ char thread_name[fbsd_maxcomlen + 1];
+ ReadCStringFromMemory(td + offset_td_name, thread_name,
+ sizeof(thread_name), error);
+
+ // if we failed to read TID, ignore this thread
+ if (tid == -1)
+ continue;
+
+ std::string thread_desc = llvm::formatv("(pid {0}) {1}", pid, comm);
+ if (*thread_name && strcmp(thread_name, comm)) {
+ thread_desc += '/';
+ thread_desc += thread_name;
+ }
+
+ // roughly:
+ // 1. if the thread crashed, its PCB is going to be at "dumppcb"
+ // 2. if the thread was on CPU, its PCB is going to be on the CPU
+ // 3. otherwise, its PCB is in the thread struct
+ if (tid == dumptid) {
+ // NB: dumppcb can be LLDB_INVALID_ADDRESS if reading it failed
+ pcb_addr = dumppcb;
+ thread_desc += " (crashed)";
+ } else if (oncpu != -1) {
+ // if we managed to read stoppcbs and pcb_size, use them to find
+ // the correct PCB
+ if (stoppcbs != LLDB_INVALID_ADDRESS && pcbsize > 0)
+ pcb_addr = stoppcbs + oncpu * pcbsize;
+ else
+ pcb_addr = LLDB_INVALID_ADDRESS;
+ thread_desc += llvm::formatv(" (on CPU {0})", oncpu);
+ }
+
+ ThreadSP thread_sp{
+ new ThreadFreeBSDKernel(*this, tid, pcb_addr, thread_desc)};
+ 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;
+}
+
+Status ProcessFreeBSDKernel::DoLoadCore() {
+ // The core is already loaded by CreateInstance().
+ return Status();
+}
+
+DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() {
+ if (m_dyld_up.get() == nullptr)
+ m_dyld_up.reset(DynamicLoader::FindPlugin(
+ this, DynamicLoaderFreeBSDKernel::GetPluginNameStatic()));
+ return m_dyld_up.get();
+}
+
+lldb::addr_t ProcessFreeBSDKernel::FindSymbol(const char *name) {
+ ModuleSP mod_sp = GetTarget().GetExecutableModule();
+ const Symbol *sym = mod_sp->FindFirstSymbolWithNameAndType(ConstString(name));
+ return sym ? sym->GetLoadAddress(&GetTarget()) : LLDB_INVALID_ADDRESS;
+}
+
+#if LLDB_ENABLE_FBSDVMCORE
+
+ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp,
+ ListenerSP listener_sp,
+ fvc_t *fvc,
+ const FileSpec &core_file)
+ : ProcessFreeBSDKernel(target_sp, listener_sp, crash_file), m_fvc(fvc) {}
+
+ProcessFreeBSDKernelFVC::~ProcessFreeBSDKernelFVC() {
+ if (m_fvc)
+ fvc_close(m_fvc);
+}
+
+size_t ProcessFreeBSDKernelFVC::DoReadMemory(lldb::addr_t addr, void *buf,
+ size_t size, Status &error) {
+ ssize_t rd = 0;
+ rd = fvc_read(m_fvc, addr, buf, size);
+ if (rd < 0 || static_cast<size_t>(rd) != size) {
+ error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
+ return rd > 0 ? rd : 0;
+ }
+ return rd;
+}
+
+const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); }
+
+#endif // LLDB_ENABLE_FBSDVMCORE
+
+#if defined(__FreeBSD__)
+
+ProcessFreeBSDKernelKVM::ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp,
+ ListenerSP listener_sp,
+ kvm_t *fvc,
+ const FileSpec &core_file)
+ : ProcessFreeBSDKernel(target_sp, listener_sp, core_file), m_kvm(fvc) {}
+
+ProcessFreeBSDKernelKVM::~ProcessFreeBSDKernelKVM() {
+ if (m_kvm)
+ kvm_close(m_kvm);
+}
+
+size_t ProcessFreeBSDKernelKVM::DoReadMemory(lldb::addr_t addr, void *buf,
+ size_t size, Status &error) {
+ ssize_t rd = 0;
+ rd = kvm_read2(m_kvm, addr, buf, size);
+ if (rd < 0 || static_cast<size_t>(rd) != size) {
+ error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
+ return rd > 0 ? rd : 0;
+ }
+ return rd;
+}
+
+const char *ProcessFreeBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); }
+
+#endif // defined(__FreeBSD__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
new file mode 100644
index 000000000000..06c9d062441e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
@@ -0,0 +1,54 @@
+//===-- ProcessFreeBSDKernel.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H
+
+#include "lldb/Target/PostMortemProcess.h"
+
+class ProcessFreeBSDKernel : public lldb_private::PostMortemProcess {
+public:
+ ProcessFreeBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener,
+ const lldb_private::FileSpec &core_file);
+
+ static lldb::ProcessSP
+ CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener,
+ const lldb_private::FileSpec *crash_file_path,
+ bool can_connect);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "freebsd-kernel"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic() {
+ return "FreeBSD kernel vmcore debugging plug-in.";
+ }
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ lldb_private::Status DoDestroy() override;
+
+ bool CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) override;
+
+ void RefreshStateAfterStop() override;
+
+ lldb_private::Status DoLoadCore() override;
+
+ lldb_private::DynamicLoader *GetDynamicLoader() override;
+
+protected:
+ bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) override;
+
+ lldb::addr_t FindSymbol(const char* name);
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.cpp
new file mode 100644
index 000000000000..11843ddc82d9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.cpp
@@ -0,0 +1,110 @@
+//===-- RegisterContextFreeBSDKernel_arm64.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSDKernel_arm64.h"
+#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextFreeBSDKernel_arm64::RegisterContextFreeBSDKernel_arm64(
+ Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info_up,
+ lldb::addr_t pcb_addr)
+ : RegisterContextPOSIX_arm64(thread, std::move(register_info_up)),
+ m_pcb_addr(pcb_addr) {}
+
+bool RegisterContextFreeBSDKernel_arm64::ReadGPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_arm64::ReadFPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_arm64::WriteGPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextFreeBSDKernel_arm64::WriteFPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextFreeBSDKernel_arm64::ReadRegister(
+ const RegisterInfo *reg_info, RegisterValue &value) {
+ if (m_pcb_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ struct {
+ llvm::support::ulittle64_t x[30];
+ llvm::support::ulittle64_t lr;
+ llvm::support::ulittle64_t _reserved;
+ llvm::support::ulittle64_t sp;
+ } pcb;
+
+ Status error;
+ size_t rd =
+ m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
+ if (rd != sizeof(pcb))
+ return false;
+
+ uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ switch (reg) {
+ case gpr_x0_arm64:
+ case gpr_x1_arm64:
+ case gpr_x2_arm64:
+ case gpr_x3_arm64:
+ case gpr_x4_arm64:
+ case gpr_x5_arm64:
+ case gpr_x6_arm64:
+ case gpr_x7_arm64:
+ case gpr_x8_arm64:
+ case gpr_x9_arm64:
+ case gpr_x10_arm64:
+ case gpr_x11_arm64:
+ case gpr_x12_arm64:
+ case gpr_x13_arm64:
+ case gpr_x14_arm64:
+ case gpr_x15_arm64:
+ case gpr_x16_arm64:
+ case gpr_x17_arm64:
+ case gpr_x18_arm64:
+ case gpr_x19_arm64:
+ case gpr_x20_arm64:
+ case gpr_x21_arm64:
+ case gpr_x22_arm64:
+ case gpr_x23_arm64:
+ case gpr_x24_arm64:
+ case gpr_x25_arm64:
+ case gpr_x26_arm64:
+ case gpr_x27_arm64:
+ case gpr_x28_arm64:
+ case gpr_fp_arm64:
+ static_assert(gpr_fp_arm64 - gpr_x0_arm64 == 29,
+ "nonconsecutive arm64 register numbers");
+ value = pcb.x[reg - gpr_x0_arm64];
+ break;
+ case gpr_sp_arm64:
+ value = pcb.sp;
+ break;
+ case gpr_pc_arm64:
+ // The pc of crashing thread is stored in lr.
+ value = pcb.lr;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool RegisterContextFreeBSDKernel_arm64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &value) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.h
new file mode 100644
index 000000000000..155dda6e748f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.h
@@ -0,0 +1,41 @@
+//===-- RegisterContextFreeBSDKernel_arm64.h --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_ARM64_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+class RegisterContextFreeBSDKernel_arm64 : public RegisterContextPOSIX_arm64 {
+public:
+ RegisterContextFreeBSDKernel_arm64(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm64> register_info_up,
+ lldb::addr_t pcb_addr);
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+protected:
+ bool ReadGPR() override;
+
+ bool ReadFPR() override;
+
+ bool WriteGPR() override;
+
+ bool WriteFPR() override;
+
+private:
+ lldb::addr_t m_pcb_addr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_ARM64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.cpp
new file mode 100644
index 000000000000..fde85c9c9f0d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.cpp
@@ -0,0 +1,83 @@
+//===-- RegisterContextFreeBSDKernel_i386.cpp -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSDKernel_i386.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextFreeBSDKernel_i386::RegisterContextFreeBSDKernel_i386(
+ Thread &thread, RegisterInfoInterface *register_info, lldb::addr_t pcb_addr)
+ : RegisterContextPOSIX_x86(thread, 0, register_info), m_pcb_addr(pcb_addr) {
+}
+
+bool RegisterContextFreeBSDKernel_i386::ReadGPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_i386::ReadFPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_i386::WriteGPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextFreeBSDKernel_i386::WriteFPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextFreeBSDKernel_i386::ReadRegister(
+ const RegisterInfo *reg_info, RegisterValue &value) {
+ if (m_pcb_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ struct {
+ llvm::support::ulittle32_t edi;
+ llvm::support::ulittle32_t esi;
+ llvm::support::ulittle32_t ebp;
+ llvm::support::ulittle32_t esp;
+ llvm::support::ulittle32_t ebx;
+ llvm::support::ulittle32_t eip;
+ } pcb;
+
+ Status error;
+ size_t rd =
+ m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
+ if (rd != sizeof(pcb))
+ return false;
+
+ uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ switch (reg) {
+#define REG(x) \
+ case lldb_##x##_i386: \
+ value = pcb.x; \
+ break;
+
+ REG(edi);
+ REG(esi);
+ REG(ebp);
+ REG(esp);
+ REG(eip);
+
+#undef REG
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool RegisterContextFreeBSDKernel_i386::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &value) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.h
new file mode 100644
index 000000000000..218e3374f8df
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.h
@@ -0,0 +1,41 @@
+//===-- RegisterContextFreeBSDKernel_i386.h ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_I386_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_I386_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+class RegisterContextFreeBSDKernel_i386 : public RegisterContextPOSIX_x86 {
+public:
+ RegisterContextFreeBSDKernel_i386(
+ lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ lldb::addr_t pcb_addr);
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+protected:
+ bool ReadGPR() override;
+
+ bool ReadFPR() override;
+
+ bool WriteGPR() override;
+
+ bool WriteFPR() override;
+
+private:
+ lldb::addr_t m_pcb_addr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_I386_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.cpp
new file mode 100644
index 000000000000..ff57842e345c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.cpp
@@ -0,0 +1,88 @@
+//===-- RegisterContextFreeBSDKernel_x86_64.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSDKernel_x86_64.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextFreeBSDKernel_x86_64::RegisterContextFreeBSDKernel_x86_64(
+ Thread &thread, RegisterInfoInterface *register_info, lldb::addr_t pcb_addr)
+ : RegisterContextPOSIX_x86(thread, 0, register_info), m_pcb_addr(pcb_addr) {
+}
+
+bool RegisterContextFreeBSDKernel_x86_64::ReadGPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_x86_64::ReadFPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_x86_64::WriteGPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextFreeBSDKernel_x86_64::WriteFPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextFreeBSDKernel_x86_64::ReadRegister(
+ const RegisterInfo *reg_info, RegisterValue &value) {
+ if (m_pcb_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ struct {
+ llvm::support::ulittle64_t r15;
+ llvm::support::ulittle64_t r14;
+ llvm::support::ulittle64_t r13;
+ llvm::support::ulittle64_t r12;
+ llvm::support::ulittle64_t rbp;
+ llvm::support::ulittle64_t rsp;
+ llvm::support::ulittle64_t rbx;
+ llvm::support::ulittle64_t rip;
+ } pcb;
+
+ Status error;
+ size_t rd =
+ m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
+ if (rd != sizeof(pcb))
+ return false;
+
+ uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ switch (reg) {
+#define REG(x) \
+ case lldb_##x##_x86_64: \
+ value = pcb.x; \
+ break;
+
+ REG(r15);
+ REG(r14);
+ REG(r13);
+ REG(r12);
+ REG(rbp);
+ REG(rsp);
+ REG(rbx);
+ REG(rip);
+
+#undef REG
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool RegisterContextFreeBSDKernel_x86_64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &value) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.h
new file mode 100644
index 000000000000..9a2ac638dfea
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.h
@@ -0,0 +1,41 @@
+//===-- RegisterContextFreeBSDKernel_x86_64.h -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_X86_64_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+class RegisterContextFreeBSDKernel_x86_64 : public RegisterContextPOSIX_x86 {
+public:
+ RegisterContextFreeBSDKernel_x86_64(
+ lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ lldb::addr_t pcb_addr);
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+protected:
+ bool ReadGPR() override;
+
+ bool ReadFPR() override;
+
+ bool WriteGPR() override;
+
+ bool WriteFPR() override;
+
+private:
+ lldb::addr_t m_pcb_addr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_X86_64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp
new file mode 100644
index 000000000000..8d304086a163
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp
@@ -0,0 +1,86 @@
+//===-- ThreadFreeBSDKernel.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThreadFreeBSDKernel.h"
+
+#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/Log.h"
+
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+#include "ProcessFreeBSDKernel.h"
+#include "RegisterContextFreeBSDKernel_arm64.h"
+#include "RegisterContextFreeBSDKernel_i386.h"
+#include "RegisterContextFreeBSDKernel_x86_64.h"
+#include "ThreadFreeBSDKernel.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadFreeBSDKernel::ThreadFreeBSDKernel(Process &process, lldb::tid_t tid,
+ lldb::addr_t pcb_addr,
+ std::string thread_name)
+ : Thread(process, tid), m_thread_name(std::move(thread_name)),
+ m_pcb_addr(pcb_addr) {}
+
+ThreadFreeBSDKernel::~ThreadFreeBSDKernel() {}
+
+void ThreadFreeBSDKernel::RefreshStateAfterStop() {}
+
+lldb::RegisterContextSP ThreadFreeBSDKernel::GetRegisterContext() {
+ if (!m_reg_context_sp)
+ m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadFreeBSDKernel::CreateRegisterContextForFrame(StackFrame *frame) {
+ 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)
+ return m_thread_reg_ctx_sp;
+
+ ProcessFreeBSDKernel *process =
+ static_cast<ProcessFreeBSDKernel *>(GetProcess().get());
+ ArchSpec arch = process->GetTarget().GetArchitecture();
+
+ switch (arch.GetMachine()) {
+ case llvm::Triple::aarch64:
+ m_thread_reg_ctx_sp =
+ std::make_shared<RegisterContextFreeBSDKernel_arm64>(
+ *this, std::make_unique<RegisterInfoPOSIX_arm64>(arch, 0),
+ m_pcb_addr);
+ break;
+ case llvm::Triple::x86:
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextFreeBSDKernel_i386>(
+ *this, new RegisterContextFreeBSD_i386(arch), m_pcb_addr);
+ break;
+ case llvm::Triple::x86_64:
+ m_thread_reg_ctx_sp =
+ std::make_shared<RegisterContextFreeBSDKernel_x86_64>(
+ *this, new RegisterContextFreeBSD_x86_64(arch), m_pcb_addr);
+ break;
+ default:
+ assert(false && "Unsupported architecture passed to ThreadFreeBSDKernel");
+ break;
+ }
+
+ reg_ctx_sp = m_thread_reg_ctx_sp;
+ } else {
+ reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool ThreadFreeBSDKernel::CalculateStopInfo() { return false; }
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h
new file mode 100644
index 000000000000..3bc019b63e68
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h
@@ -0,0 +1,50 @@
+//===-- ThreadFreeBSDKernel.h ------------------------------------- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_THREADFREEBSDKERNEL_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_THREADFREEBSDKERNEL_H
+
+#include "lldb/Target/Thread.h"
+
+class ThreadFreeBSDKernel : public lldb_private::Thread {
+public:
+ ThreadFreeBSDKernel(lldb_private::Process &process, lldb::tid_t tid,
+ lldb::addr_t pcb_addr, std::string thread_name);
+
+ ~ThreadFreeBSDKernel() override;
+
+ void RefreshStateAfterStop() override;
+
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+ const char *GetName() override {
+ if (m_thread_name.empty())
+ return nullptr;
+ return m_thread_name.c_str();
+ }
+
+ void SetName(const char *name) override {
+ if (name && name[0])
+ m_thread_name.assign(name);
+ else
+ m_thread_name.clear();
+ }
+
+protected:
+ bool CalculateStopInfo() override;
+
+private:
+ std::string m_thread_name;
+ lldb::RegisterContextSP m_thread_reg_ctx_sp;
+ lldb::addr_t m_pcb_addr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_THREADFREEBSDKERNEL_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
new file mode 100644
index 000000000000..451bb4866037
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -0,0 +1,1119 @@
+//===-- NativeProcessNetBSD.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessNetBSD.h"
+
+#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/State.h"
+#include "llvm/Support/Errno.h"
+
+// System includes - They have to be included after framework includes because
+// they define some macros which collide with variable names in other modules
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <uvm/uvm_prot.h>
+#include <elf.h>
+#include <util.h>
+// clang-format on
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_netbsd;
+using namespace llvm;
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static Status EnsureFDFlags(int fd, int flags) {
+ Status 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;
+}
+
+// Public Static Methods
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessNetBSD::Manager::Launch(ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate) {
+ Log *log = GetLog(POSIXLog::Process);
+
+ Status status;
+ ::pid_t pid = ProcessLauncherPosixFork()
+ .LaunchProcess(launch_info, status)
+ .GetProcessId();
+ LLDB_LOG(log, "pid = {0:x}", pid);
+ if (status.Fail()) {
+ LLDB_LOG(log, "failed to launch process: {0}", status);
+ return status.ToError();
+ }
+
+ // Wait for the child process to trap on its call to execve.
+ int wstatus;
+ ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
+ assert(wpid == pid);
+ (void)wpid;
+ if (!WIFSTOPPED(wstatus)) {
+ LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
+ WaitStatus::Decode(wstatus));
+ return llvm::make_error<StringError>("Could not sync with inferior process",
+ llvm::inconvertibleErrorCode());
+ }
+ LLDB_LOG(log, "inferior started, now in stopped state");
+
+ ProcessInstanceInfo Info;
+ if (!Host::GetProcessInfo(pid, Info)) {
+ return llvm::make_error<StringError>("Cannot get process architecture",
+ llvm::inconvertibleErrorCode());
+ }
+
+ // Set the architecture to the exe architecture.
+ LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
+ Info.GetArchitecture().GetArchitectureName());
+
+ std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
+ pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
+ Info.GetArchitecture(), m_mainloop));
+
+ status = process_up->SetupTrace();
+ if (status.Fail())
+ return status.ToError();
+
+ for (const auto &thread : process_up->m_threads)
+ static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+ process_up->SetState(StateType::eStateStopped, false);
+
+ return std::move(process_up);
+}
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessNetBSD::Manager::Attach(
+ lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid = {0:x}", pid);
+
+ // Retrieve the architecture for the running process.
+ ProcessInstanceInfo Info;
+ if (!Host::GetProcessInfo(pid, Info)) {
+ return llvm::make_error<StringError>("Cannot get process architecture",
+ llvm::inconvertibleErrorCode());
+ }
+
+ std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
+ pid, -1, native_delegate, Info.GetArchitecture(), m_mainloop));
+
+ Status status = process_up->Attach();
+ if (!status.Success())
+ return status.ToError();
+
+ return std::move(process_up);
+}
+
+NativeProcessNetBSD::Extension
+NativeProcessNetBSD::Manager::GetSupportedExtensions() const {
+ return Extension::multiprocess | Extension::fork | Extension::vfork |
+ Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |
+ Extension::savecore;
+}
+
+// Public Instance Methods
+
+NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd,
+ NativeDelegate &delegate,
+ const ArchSpec &arch,
+ MainLoop &mainloop)
+ : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),
+ m_main_loop(mainloop) {
+ if (m_terminal_fd != -1) {
+ Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
+ assert(status.Success());
+ }
+
+ Status status;
+ m_sigchld_handle = mainloop.RegisterSignal(
+ SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
+ assert(m_sigchld_handle && status.Success());
+}
+
+// Handles all waitpid events from the inferior process.
+void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
+ switch (signal) {
+ case SIGTRAP:
+ return MonitorSIGTRAP(pid);
+ case SIGSTOP:
+ return MonitorSIGSTOP(pid);
+ default:
+ return MonitorSignal(pid, signal);
+ }
+}
+
+void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
+ Log *log = GetLog(POSIXLog::Process);
+
+ LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
+
+ /* Stop Tracking All Threads attached to Process */
+ m_threads.clear();
+
+ SetExitStatus(status, true);
+
+ // Notify delegate that our process has exited.
+ SetState(StateType::eStateExited, true);
+}
+
+void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) {
+ ptrace_siginfo_t info;
+
+ const auto siginfo_err =
+ PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
+
+ // Get details on the signal raised.
+ if (siginfo_err.Success()) {
+ // Handle SIGSTOP from LLGS (LLDB GDB Server)
+ if (info.psi_siginfo.si_code == SI_USER &&
+ info.psi_siginfo.si_pid == ::getpid()) {
+ /* Stop Tracking all Threads attached to Process */
+ for (const auto &thread : m_threads) {
+ static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(
+ SIGSTOP, &info.psi_siginfo);
+ }
+ }
+ SetState(StateType::eStateStopped, true);
+ }
+}
+
+void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
+ Log *log = GetLog(POSIXLog::Process);
+ ptrace_siginfo_t info;
+
+ const auto siginfo_err =
+ PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
+
+ // Get details on the signal raised.
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);
+ return;
+ }
+
+ LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid,
+ info.psi_lwpid, info.psi_siginfo.si_code);
+ NativeThreadNetBSD *thread = nullptr;
+
+ if (info.psi_lwpid > 0) {
+ for (const auto &t : m_threads) {
+ if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) {
+ thread = static_cast<NativeThreadNetBSD *>(t.get());
+ break;
+ }
+ static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason();
+ }
+ if (!thread)
+ LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
+ info.psi_lwpid);
+ }
+
+ switch (info.psi_siginfo.si_code) {
+ case TRAP_BRKPT:
+ if (thread) {
+ thread->SetStoppedByBreakpoint();
+ FixupBreakpointPCAsNeeded(*thread);
+ }
+ SetState(StateType::eStateStopped, true);
+ return;
+ case TRAP_TRACE:
+ if (thread)
+ thread->SetStoppedByTrace();
+ SetState(StateType::eStateStopped, true);
+ return;
+ case TRAP_EXEC: {
+ Status error = ReinitializeThreads();
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+
+ // Let our delegate know we have just exec'd.
+ NotifyDidExec();
+
+ for (const auto &thread : m_threads)
+ static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec();
+ SetState(StateType::eStateStopped, true);
+ return;
+ }
+ case TRAP_CHLD: {
+ ptrace_state_t pst;
+ Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+
+ assert(thread);
+ if (pst.pe_report_event == PTRACE_VFORK_DONE) {
+ if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) {
+ thread->SetStoppedByVForkDone();
+ SetState(StateType::eStateStopped, true);
+ } else {
+ Status error =
+ PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
+ if (error.Fail())
+ SetState(StateType::eStateInvalid);
+ }
+ } else {
+ assert(pst.pe_report_event == PTRACE_FORK ||
+ pst.pe_report_event == PTRACE_VFORK);
+ MonitorClone(pst.pe_other_pid, pst.pe_report_event == PTRACE_VFORK,
+ *thread);
+ }
+ return;
+ }
+ case TRAP_LWP: {
+ ptrace_state_t pst;
+ Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+
+ switch (pst.pe_report_event) {
+ case PTRACE_LWP_CREATE: {
+ LLDB_LOG(log, "monitoring new thread, pid = {0}, LWP = {1}", pid,
+ pst.pe_lwp);
+ NativeThreadNetBSD &t = AddThread(pst.pe_lwp);
+ error = t.CopyWatchpointsFrom(
+ static_cast<NativeThreadNetBSD &>(*GetCurrentThread()));
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}",
+ pst.pe_lwp, error);
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+ } break;
+ case PTRACE_LWP_EXIT:
+ LLDB_LOG(log, "removing exited thread, pid = {0}, LWP = {1}", pid,
+ pst.pe_lwp);
+ RemoveThread(pst.pe_lwp);
+ break;
+ }
+
+ error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
+ if (error.Fail())
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+ case TRAP_DBREG: {
+ if (!thread)
+ break;
+
+ auto &regctx = static_cast<NativeRegisterContextNetBSD &>(
+ thread->GetRegisterContext());
+ uint32_t wp_index = LLDB_INVALID_INDEX32;
+ Status error = regctx.GetWatchpointHitIndex(
+ wp_index, (uintptr_t)info.psi_siginfo.si_addr);
+ if (error.Fail())
+ LLDB_LOG(log,
+ "received error while checking for watchpoint hits, pid = "
+ "{0}, LWP = {1}, error = {2}",
+ pid, info.psi_lwpid, error);
+ if (wp_index != LLDB_INVALID_INDEX32) {
+ thread->SetStoppedByWatchpoint(wp_index);
+ regctx.ClearWatchpointHit(wp_index);
+ SetState(StateType::eStateStopped, true);
+ return;
+ }
+
+ thread->SetStoppedByTrace();
+ SetState(StateType::eStateStopped, true);
+ return;
+ }
+ }
+
+ // Either user-generated SIGTRAP or an unknown event that would
+ // otherwise leave the debugger hanging.
+ LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler");
+ MonitorSignal(pid, SIGTRAP);
+}
+
+void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {
+ Log *log = GetLog(POSIXLog::Process);
+ ptrace_siginfo_t info;
+
+ const auto siginfo_err =
+ PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+ return;
+ }
+
+ for (const auto &abs_thread : m_threads) {
+ NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
+ assert(info.psi_lwpid >= 0);
+ if (info.psi_lwpid == 0 ||
+ static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID())
+ thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo);
+ else
+ thread.SetStoppedWithNoReason();
+ }
+ SetState(StateType::eStateStopped, true);
+}
+
+Status NativeProcessNetBSD::StopProcess(lldb::pid_t pid) {
+#ifdef PT_STOP
+ return PtraceWrapper(PT_STOP, pid);
+#else
+ Log *log = GetLog(POSIXLog::Ptrace);
+ Status error;
+ int ret;
+
+ errno = 0;
+ ret = kill(pid, SIGSTOP);
+
+ if (ret == -1)
+ error.SetErrorToErrno();
+
+ LLDB_LOG(log, "kill({0}, SIGSTOP)", pid);
+
+ if (error.Fail())
+ LLDB_LOG(log, "kill() failed: {0}", error);
+
+ return error;
+#endif
+}
+
+Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
+ int data, int *result) {
+ Log *log = GetLog(POSIXLog::Ptrace);
+ Status error;
+ int ret;
+
+ errno = 0;
+ ret = ptrace(req, static_cast<::pid_t>(pid), addr, data);
+
+ if (ret == -1)
+ error.SetErrorToErrno();
+
+ if (result)
+ *result = ret;
+
+ LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
+
+ if (error.Fail())
+ LLDB_LOG(log, "ptrace() failed: {0}", error);
+
+ return error;
+}
+
+static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo(
+ const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads,
+ const ResumeActionList &resume_actions) {
+ // We need to account for three possible scenarios:
+ // 1. no signal being sent.
+ // 2. a signal being sent to one thread.
+ // 3. a signal being sent to the whole process.
+
+ // Count signaled threads. While at it, determine which signal is being sent
+ // and ensure there's only one.
+ size_t signaled_threads = 0;
+ int signal = LLDB_INVALID_SIGNAL_NUMBER;
+ lldb::tid_t signaled_lwp;
+ for (const auto &thread : threads) {
+ assert(thread && "thread list should not contain NULL threads");
+ const ResumeAction *action =
+ resume_actions.GetActionForThread(thread->GetID(), true);
+ if (action) {
+ if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) {
+ signaled_threads++;
+ if (action->signal != signal) {
+ if (signal != LLDB_INVALID_SIGNAL_NUMBER)
+ return Status("NetBSD does not support passing multiple signals "
+ "simultaneously")
+ .ToError();
+ signal = action->signal;
+ signaled_lwp = thread->GetID();
+ }
+ }
+ }
+ }
+
+ if (signaled_threads == 0) {
+ ptrace_siginfo_t siginfo;
+ siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER;
+ return siginfo;
+ }
+
+ if (signaled_threads > 1 && signaled_threads < threads.size())
+ return Status("NetBSD does not support passing signal to 1<i<all threads")
+ .ToError();
+
+ ptrace_siginfo_t siginfo;
+ siginfo.psi_siginfo.si_signo = signal;
+ siginfo.psi_siginfo.si_code = SI_USER;
+ siginfo.psi_siginfo.si_pid = getpid();
+ siginfo.psi_siginfo.si_uid = getuid();
+ if (signaled_threads == 1)
+ siginfo.psi_lwpid = signaled_lwp;
+ else // signal for the whole process
+ siginfo.psi_lwpid = 0;
+ return siginfo;
+}
+
+Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ Status ret;
+
+ Expected<ptrace_siginfo_t> siginfo =
+ ComputeSignalInfo(m_threads, resume_actions);
+ if (!siginfo)
+ return Status(siginfo.takeError());
+
+ for (const auto &abs_thread : m_threads) {
+ assert(abs_thread && "thread list should not contain NULL threads");
+ NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
+
+ const ResumeAction *action =
+ resume_actions.GetActionForThread(thread.GetID(), true);
+ // we need to explicit issue suspend requests, so it is simpler to map it
+ // into proper action
+ ResumeAction suspend_action{thread.GetID(), eStateSuspended,
+ LLDB_INVALID_SIGNAL_NUMBER};
+
+ if (action == nullptr) {
+ LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
+ thread.GetID());
+ action = &suspend_action;
+ }
+
+ LLDB_LOG(
+ log,
+ "processing resume action state {0} signal {1} for pid {2} tid {3}",
+ action->state, action->signal, GetID(), thread.GetID());
+
+ switch (action->state) {
+ case eStateRunning:
+ ret = thread.Resume();
+ break;
+ case eStateStepping:
+ ret = thread.SingleStep();
+ break;
+ case eStateSuspended:
+ case eStateStopped:
+ if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
+ return Status("Passing signal to suspended thread unsupported");
+
+ ret = thread.Suspend();
+ break;
+
+ default:
+ return Status("NativeProcessNetBSD::%s (): unexpected state %s specified "
+ "for pid %" PRIu64 ", tid %" PRIu64,
+ __FUNCTION__, StateAsCString(action->state), GetID(),
+ thread.GetID());
+ }
+
+ if (!ret.Success())
+ return ret;
+ }
+
+ int signal = 0;
+ if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) {
+ ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(),
+ sizeof(*siginfo));
+ if (!ret.Success())
+ return ret;
+ signal = siginfo->psi_siginfo.si_signo;
+ }
+
+ ret =
+ PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);
+ if (ret.Success())
+ SetState(eStateRunning, true);
+ return ret;
+}
+
+Status NativeProcessNetBSD::Halt() { return StopProcess(GetID()); }
+
+Status NativeProcessNetBSD::Detach() {
+ Status error;
+
+ // Stop monitoring the inferior.
+ m_sigchld_handle.reset();
+
+ // Tell ptrace to detach from the process.
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ return error;
+
+ return PtraceWrapper(PT_DETACH, GetID(), reinterpret_cast<void *>(1));
+}
+
+Status NativeProcessNetBSD::Signal(int signo) {
+ Status error;
+
+ if (kill(GetID(), signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Status NativeProcessNetBSD::Interrupt() { return StopProcess(GetID()); }
+
+Status NativeProcessNetBSD::Kill() {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ Status 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.
+ LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", 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;
+}
+
+Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+
+ if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
+ // We're done.
+ return Status("unsupported");
+ }
+
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail()) {
+ return error;
+ }
+
+ 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->first;
+ // Sanity check assumption that memory map entries are ascending.
+ assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
+ "descending memory map entries detected, unexpected");
+ prev_base_address = proc_entry_info.GetRange().GetRangeBase();
+ UNUSED_IF_ASSERT_DISABLED(prev_base_address);
+ // 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);
+ range_info.SetMapped(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);
+ range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
+ range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
+ return error;
+}
+
+Status NativeProcessNetBSD::PopulateMemoryRegionCache() {
+ Log *log = GetLog(POSIXLog::Process);
+ // 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()) {
+ LLDB_LOG(log, "reusing {0} cached memory region entries",
+ m_mem_region_cache.size());
+ return Status();
+ }
+
+ struct kinfo_vmentry *vm;
+ size_t count, i;
+ vm = kinfo_getvmmap(GetID(), &count);
+ if (vm == NULL) {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ Status error;
+ error.SetErrorString("not supported");
+ return error;
+ }
+ for (i = 0; i < count; i++) {
+ MemoryRegionInfo info;
+ info.Clear();
+ info.GetRange().SetRangeBase(vm[i].kve_start);
+ info.GetRange().SetRangeEnd(vm[i].kve_end);
+ info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
+
+ if (vm[i].kve_protection & VM_PROT_READ)
+ info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (vm[i].kve_protection & VM_PROT_WRITE)
+ info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (vm[i].kve_protection & VM_PROT_EXECUTE)
+ info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (vm[i].kve_path[0])
+ info.SetName(vm[i].kve_path);
+
+ m_mem_region_cache.emplace_back(info,
+ FileSpec(info.GetName().GetCString()));
+ }
+ free(vm);
+
+ if (m_mem_region_cache.empty()) {
+ // No entries after attempting to read them. This shouldn't happen. Assume
+ // we don't support map entries.
+ LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "
+ "for memory region metadata retrieval");
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ Status error;
+ error.SetErrorString("not supported");
+ return error;
+ }
+ LLDB_LOG(log, "read {0} memory region entries from process {1}",
+ m_mem_region_cache.size(), GetID());
+ // We support memory retrieval, remember that.
+ m_supports_mem_region = LazyBool::eLazyBoolYes;
+ return Status();
+}
+
+lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
+ // punt on this for now
+ return LLDB_INVALID_ADDRESS;
+}
+
+size_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); }
+
+Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) {
+ if (hardware)
+ return Status("NativeProcessNetBSD does not support hardware breakpoints");
+ else
+ return SetSoftwareBreakpoint(addr, size);
+}
+
+Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) {
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail())
+ return error;
+
+ FileSpec module_file_spec(module_path);
+ FileSystem::Instance().Resolve(module_file_spec);
+
+ file_spec.Clear();
+ for (const auto &it : m_mem_region_cache) {
+ if (it.second.GetFilename() == module_file_spec.GetFilename()) {
+ file_spec = it.second;
+ return Status();
+ }
+ }
+ return Status("Module file (%s) not found in process' memory map!",
+ module_file_spec.GetFilename().AsCString());
+}
+
+Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) {
+ load_addr = LLDB_INVALID_ADDRESS;
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail())
+ return error;
+
+ FileSpec file(file_name);
+ for (const auto &it : m_mem_region_cache) {
+ if (it.second == file) {
+ load_addr = it.first.GetRange().GetRangeBase();
+ return Status();
+ }
+ }
+ return Status("No load address found for file %s.", file_name.str().c_str());
+}
+
+void NativeProcessNetBSD::SigchldHandler() {
+ Log *log = GetLog(POSIXLog::Process);
+ int status;
+ ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status,
+ WALLSIG | WNOHANG);
+
+ if (wait_pid == 0)
+ return;
+
+ if (wait_pid == -1) {
+ Status error(errno, eErrorTypePOSIX);
+ LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
+ return;
+ }
+
+ WaitStatus wait_status = WaitStatus::Decode(status);
+ bool exited = wait_status.type == WaitStatus::Exit ||
+ (wait_status.type == WaitStatus::Signal &&
+ wait_pid == static_cast<::pid_t>(GetID()));
+
+ LLDB_LOG(log,
+ "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
+ GetID(), wait_pid, status, exited);
+
+ if (exited)
+ MonitorExited(wait_pid, wait_status);
+ else {
+ assert(wait_status.type == WaitStatus::Stop);
+ MonitorCallback(wait_pid, wait_status.status);
+ }
+}
+
+bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {
+ for (const auto &thread : m_threads) {
+ assert(thread && "thread list should not contain NULL threads");
+ if (thread->GetID() == thread_id) {
+ // We have this thread.
+ return true;
+ }
+ }
+
+ // We don't have this thread.
+ return false;
+}
+
+NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
+ Log *log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
+
+ assert(thread_id > 0);
+ 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);
+
+ m_threads.push_back(std::make_unique<NativeThreadNetBSD>(*this, thread_id));
+ return static_cast<NativeThreadNetBSD &>(*m_threads.back());
+}
+
+void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) {
+ Log *log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);
+
+ assert(thread_id > 0);
+ assert(HasThreadNoLock(thread_id) &&
+ "attempted to remove a thread that does not exist");
+
+ for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
+ if ((*it)->GetID() == thread_id) {
+ m_threads.erase(it);
+ break;
+ }
+ }
+}
+
+Status NativeProcessNetBSD::Attach() {
+ // Attach to the requested process.
+ // An attach will cause the thread to stop with a SIGSTOP.
+ Status status = PtraceWrapper(PT_ATTACH, m_pid);
+ if (status.Fail())
+ return status;
+
+ int wstatus;
+ // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this
+ // point we should have a thread stopped if waitpid succeeds.
+ if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr,
+ WALLSIG)) < 0)
+ return Status(errno, eErrorTypePOSIX);
+
+ // Initialize threads and tracing status
+ // NB: this needs to be called before we set thread state
+ status = SetupTrace();
+ if (status.Fail())
+ return status;
+
+ for (const auto &thread : m_threads)
+ static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+
+ // Let our process instance know the thread has stopped.
+ SetCurrentThreadID(m_threads.front()->GetID());
+ SetState(StateType::eStateStopped, false);
+ return Status();
+}
+
+Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf,
+ size_t size, size_t &bytes_read) {
+ unsigned char *dst = static_cast<unsigned char *>(buf);
+ struct ptrace_io_desc io;
+
+ Log *log = GetLog(POSIXLog::Memory);
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_read = 0;
+ io.piod_op = PIOD_READ_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_offs = (void *)(addr + bytes_read);
+ io.piod_addr = dst + bytes_read;
+
+ Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail() || io.piod_len == 0)
+ return error;
+
+ bytes_read += io.piod_len;
+ io.piod_len = size - bytes_read;
+ } while (bytes_read < size);
+
+ return Status();
+}
+
+Status NativeProcessNetBSD::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);
+ Status error;
+ struct ptrace_io_desc io;
+
+ Log *log = GetLog(POSIXLog::Memory);
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_written = 0;
+ io.piod_op = PIOD_WRITE_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_addr =
+ const_cast<void *>(static_cast<const void *>(src + bytes_written));
+ io.piod_offs = (void *)(addr + bytes_written);
+
+ Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail() || io.piod_len == 0)
+ return error;
+
+ bytes_written += io.piod_len;
+ io.piod_len = size - bytes_written;
+ } while (bytes_written < size);
+
+ return error;
+}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+NativeProcessNetBSD::GetAuxvData() const {
+ /*
+ * ELF_AUX_ENTRIES is currently restricted to kernel
+ * (<sys/exec_elf.h> r. 1.155 specifies 15)
+ *
+ * ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this
+ * information isn't needed.
+ */
+ size_t auxv_size = 100 * sizeof(AuxInfo);
+
+ ErrorOr<std::unique_ptr<WritableMemoryBuffer>> buf =
+ llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
+
+ struct ptrace_io_desc io;
+ io.piod_op = PIOD_READ_AUXV;
+ io.piod_offs = 0;
+ io.piod_addr = static_cast<void *>(buf.get()->getBufferStart());
+ io.piod_len = auxv_size;
+
+ Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
+
+ if (error.Fail())
+ return std::error_code(error.GetError(), std::generic_category());
+
+ if (io.piod_len < 1)
+ return std::error_code(ECANCELED, std::generic_category());
+
+ return std::move(buf);
+}
+
+Status NativeProcessNetBSD::SetupTrace() {
+ // Enable event reporting
+ ptrace_event_t events;
+ Status status =
+ PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
+ if (status.Fail())
+ return status;
+ // TODO: PTRACE_POSIX_SPAWN?
+ events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT | PTRACE_FORK |
+ PTRACE_VFORK | PTRACE_VFORK_DONE;
+ status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
+ if (status.Fail())
+ return status;
+
+ return ReinitializeThreads();
+}
+
+Status NativeProcessNetBSD::ReinitializeThreads() {
+ // Clear old threads
+ m_threads.clear();
+
+ // Initialize new thread
+#ifdef PT_LWPSTATUS
+ struct ptrace_lwpstatus info = {};
+ int op = PT_LWPNEXT;
+#else
+ struct ptrace_lwpinfo info = {};
+ int op = PT_LWPINFO;
+#endif
+
+ Status error = PtraceWrapper(op, GetID(), &info, sizeof(info));
+
+ if (error.Fail()) {
+ return error;
+ }
+ // Reinitialize from scratch threads and register them in process
+ while (info.pl_lwpid != 0) {
+ AddThread(info.pl_lwpid);
+ error = PtraceWrapper(op, GetID(), &info, sizeof(info));
+ if (error.Fail()) {
+ return error;
+ }
+ }
+
+ return error;
+}
+
+void NativeProcessNetBSD::MonitorClone(::pid_t child_pid, bool is_vfork,
+ NativeThreadNetBSD &parent_thread) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "clone, child_pid={0}", child_pid);
+
+ int status;
+ ::pid_t wait_pid =
+ llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);
+ if (wait_pid != child_pid) {
+ LLDB_LOG(log,
+ "waiting for pid {0} failed. Assuming the pid has "
+ "disappeared in the meantime",
+ child_pid);
+ return;
+ }
+ if (WIFEXITED(status)) {
+ LLDB_LOG(log,
+ "waiting for pid {0} returned an 'exited' event. Not "
+ "tracking it.",
+ child_pid);
+ return;
+ }
+
+ ptrace_siginfo_t info;
+ const auto siginfo_err =
+ PtraceWrapper(PT_GET_SIGINFO, child_pid, &info, sizeof(info));
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);
+ return;
+ }
+ assert(info.psi_lwpid >= 0);
+ lldb::tid_t child_tid = info.psi_lwpid;
+
+ std::unique_ptr<NativeProcessNetBSD> child_process{
+ new NativeProcessNetBSD(static_cast<::pid_t>(child_pid), m_terminal_fd,
+ m_delegate, m_arch, m_main_loop)};
+ if (!is_vfork)
+ child_process->m_software_breakpoints = m_software_breakpoints;
+
+ Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork;
+ if ((m_enabled_extensions & expected_ext) == expected_ext) {
+ child_process->SetupTrace();
+ for (const auto &thread : child_process->m_threads)
+ static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+ child_process->SetState(StateType::eStateStopped, false);
+
+ m_delegate.NewSubprocess(this, std::move(child_process));
+ if (is_vfork)
+ parent_thread.SetStoppedByVFork(child_pid, child_tid);
+ else
+ parent_thread.SetStoppedByFork(child_pid, child_tid);
+ SetState(StateType::eStateStopped, true);
+ } else {
+ child_process->Detach();
+ Status pt_error =
+ PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0);
+ if (pt_error.Fail()) {
+ LLDB_LOG_ERROR(log, std::move(pt_error.ToError()),
+ "unable to resume parent process {1}: {0}", GetID());
+ SetState(StateType::eStateInvalid);
+ }
+ }
+}
+
+llvm::Expected<std::string>
+NativeProcessNetBSD::SaveCore(llvm::StringRef path_hint) {
+ llvm::SmallString<128> path{path_hint};
+ Status error;
+
+ // Try with the suggested path first.
+ if (!path.empty()) {
+ error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());
+ if (!error.Fail())
+ return path.str().str();
+
+ // If the request errored, fall back to a generic temporary file.
+ }
+
+ if (std::error_code errc =
+ llvm::sys::fs::createTemporaryFile("lldb", "core", path))
+ return llvm::createStringError(errc, "Unable to create a temporary file");
+
+ error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());
+ if (error.Fail())
+ return error.ToError();
+ return path.str().str();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
new file mode 100644
index 000000000000..f3d07651384f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -0,0 +1,130 @@
+//===-- NativeProcessNetBSD.h --------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeProcessNetBSD_H_
+#define liblldb_NativeProcessNetBSD_H_
+
+#include "Plugins/Process/POSIX/NativeProcessELF.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/FileSpec.h"
+
+#include "NativeThreadNetBSD.h"
+
+namespace lldb_private {
+namespace process_netbsd {
+/// \class NativeProcessNetBSD
+/// 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 NativeProcessNetBSD : public NativeProcessELF {
+public:
+ class Manager : public NativeProcessProtocol::Manager {
+ public:
+ using NativeProcessProtocol::Manager::Manager;
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Launch(ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate) override;
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override;
+
+ Extension GetSupportedExtensions() const override;
+ };
+
+ // NativeProcessProtocol Interface
+ Status Resume(const ResumeActionList &resume_actions) override;
+
+ Status Halt() override;
+
+ Status Detach() override;
+
+ Status Signal(int signo) override;
+
+ Status Interrupt() override;
+
+ Status Kill() override;
+
+ Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
+
+ Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) override;
+
+ Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+ size_t &bytes_written) override;
+
+ lldb::addr_t GetSharedLibraryInfoAddress() override;
+
+ size_t UpdateThreads() override;
+
+ const ArchSpec &GetArchitecture() const override { return m_arch; }
+
+ Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) override;
+
+ // The two following methods are probably not necessary and probably
+ // will never be called. Nevertheless, we implement them right now
+ // to reduce the differences between different platforms and reduce
+ // the risk of the lack of implementation actually breaking something,
+ // at least for the time being.
+ Status GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) override;
+ Status GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) override;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ GetAuxvData() const override;
+
+ // Interface used by NativeRegisterContext-derived classes.
+ static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
+ int data = 0, int *result = nullptr);
+ static Status StopProcess(lldb::pid_t pid);
+
+ llvm::Expected<std::string> SaveCore(llvm::StringRef path_hint) override;
+
+private:
+ MainLoop::SignalHandleUP m_sigchld_handle;
+ ArchSpec m_arch;
+ MainLoop& m_main_loop;
+ LazyBool m_supports_mem_region = eLazyBoolCalculate;
+ std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
+
+ // Private Instance Methods
+ NativeProcessNetBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
+ const ArchSpec &arch, MainLoop &mainloop);
+
+ bool HasThreadNoLock(lldb::tid_t thread_id);
+
+ NativeThreadNetBSD &AddThread(lldb::tid_t thread_id);
+ void RemoveThread(lldb::tid_t thread_id);
+
+ void MonitorCallback(lldb::pid_t pid, int signal);
+ void MonitorExited(lldb::pid_t pid, WaitStatus status);
+ void MonitorSIGSTOP(lldb::pid_t pid);
+ void MonitorSIGTRAP(lldb::pid_t pid);
+ void MonitorSignal(lldb::pid_t pid, int signal);
+ void MonitorClone(::pid_t child_pid, bool is_vfork,
+ NativeThreadNetBSD &parent_thread);
+
+ Status PopulateMemoryRegionCache();
+ void SigchldHandler();
+
+ Status Attach();
+ Status SetupTrace();
+ Status ReinitializeThreads();
+};
+
+} // namespace process_netbsd
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeProcessNetBSD_H_
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
new file mode 100644
index 000000000000..4755dab0b073
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
@@ -0,0 +1,34 @@
+//===-- NativeRegisterContextNetBSD.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextNetBSD.h"
+
+#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_netbsd;
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+// clang-format on
+
+Status NativeRegisterContextNetBSD::DoRegisterSet(int ptrace_req, void *buf) {
+ return NativeProcessNetBSD::PtraceWrapper(ptrace_req, GetProcessPid(), buf,
+ m_thread.GetID());
+}
+
+NativeProcessNetBSD &NativeRegisterContextNetBSD::GetProcess() {
+ return static_cast<NativeProcessNetBSD &>(m_thread.GetProcess());
+}
+
+::pid_t NativeRegisterContextNetBSD::GetProcessPid() {
+ return GetProcess().GetID();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
new file mode 100644
index 000000000000..08490aad9e0b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
@@ -0,0 +1,44 @@
+//===-- NativeRegisterContextNetBSD.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextNetBSD_h
+#define lldb_NativeRegisterContextNetBSD_h
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+namespace lldb_private {
+namespace process_netbsd {
+
+class NativeProcessNetBSD;
+
+class NativeRegisterContextNetBSD
+ : public virtual NativeRegisterContextRegisterInfo {
+public:
+ // This function is implemented in the NativeRegisterContextNetBSD_*
+ // subclasses to create a new instance of the host specific
+ // NativeRegisterContextNetBSD. The implementations can't collide as only one
+ // NativeRegisterContextNetBSD_* variant should be compiled into the final
+ // executable.
+ static NativeRegisterContextNetBSD *
+ CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch,
+ NativeThreadProtocol &native_thread);
+ virtual llvm::Error
+ CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) = 0;
+
+protected:
+ Status DoRegisterSet(int req, void *buf);
+ virtual NativeProcessNetBSD &GetProcess();
+ virtual ::pid_t GetProcessPid();
+};
+
+} // namespace process_netbsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextNetBSD_h
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
new file mode 100644
index 000000000000..13607bd261d4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
@@ -0,0 +1,645 @@
+//===-- NativeRegisterContextNetBSD_x86_64.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include "NativeRegisterContextNetBSD_x86_64.h"
+
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/uio.h>
+#include <x86/cpu.h>
+#include <x86/cpu_extended_state.h>
+#include <x86/specialreg.h>
+#include <elf.h>
+#include <err.h>
+#include <cstdint>
+#include <cstdlib>
+#include <optional>
+// clang-format on
+
+using namespace lldb_private;
+using namespace lldb_private::process_netbsd;
+
+// 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_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64,
+ lldb_fdp_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");
+
+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");
+
+static const uint32_t g_mpx_regnums_x86_64[] = {
+ // Note: we currently do not provide them but this is needed to avoid
+ // unnamed groups in SBFrame::GetRegisterContext().
+ lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64,
+ lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) -
+ 1 ==
+ k_num_mpx_registers_x86_64,
+ "g_mpx_regnums_x86_64 has wrong number of register infos");
+
+// x86 debug registers.
+static const uint32_t g_dbr_regnums_x86_64[] = {
+ lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64,
+ lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) -
+ 1 ==
+ k_num_dbr_registers_x86_64,
+ "g_dbr_regnums_x86_64 has wrong number of register infos");
+
+// x86 32-bit general purpose registers.
+static 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.
+static 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");
+
+static 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");
+
+static const uint32_t g_mpx_regnums_i386[] = {
+ // Note: we currently do not provide them but this is needed to avoid
+ // unnamed groups in SBFrame::GetRegisterContext().
+ lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386,
+ lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) -
+ 1 ==
+ k_num_mpx_registers_i386,
+ "g_mpx_regnums_i386 has wrong number of register infos");
+
+// x86 debug registers.
+static const uint32_t g_dbr_regnums_i386[] = {
+ lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386,
+ lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) -
+ 1 ==
+ k_num_dbr_registers_i386,
+ "g_dbr_regnums_i386 has wrong number of register infos");
+
+// Number of register sets provided by this context.
+enum { k_num_register_sets = 5 };
+
+// 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},
+ {"Debug Registers", "dbr", k_num_dbr_registers_i386, g_dbr_regnums_i386},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386,
+ g_avx_regnums_i386},
+ {"Memory Protection Extensions", "mpx", k_num_mpx_registers_i386,
+ g_mpx_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},
+ {"Debug Registers", "dbr", k_num_dbr_registers_x86_64,
+ g_dbr_regnums_x86_64},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64,
+ g_avx_regnums_x86_64},
+ {"Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64,
+ g_mpx_regnums_x86_64},
+};
+
+#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
+
+NativeRegisterContextNetBSD *
+NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+ return new NativeRegisterContextNetBSD_x86_64(target_arch, native_thread);
+}
+
+// NativeRegisterContextNetBSD_x86_64 members.
+
+static RegisterInfoInterface *
+CreateRegisterInfoInterface(const ArchSpec &target_arch) {
+ if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) {
+ // 32-bit hosts run with a RegisterContextNetBSD_i386 context.
+ return new RegisterContextNetBSD_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 RegisterContextNetBSD_x86_64(target_arch);
+ }
+}
+
+NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+ : NativeRegisterContextRegisterInfo(
+ native_thread, CreateRegisterInfoInterface(target_arch)),
+ NativeRegisterContextDBReg_x86(native_thread), m_regset_offsets({0}) {
+ assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize());
+ std::array<uint32_t, MaxRegularRegSet + 1> first_regnos;
+
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ first_regnos[FPRegSet] = lldb_fctrl_i386;
+ first_regnos[DBRegSet] = lldb_dr0_i386;
+ break;
+ case llvm::Triple::x86_64:
+ first_regnos[FPRegSet] = lldb_fctrl_x86_64;
+ first_regnos[DBRegSet] = lldb_dr0_x86_64;
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ for (int i : {FPRegSet, DBRegSet})
+ m_regset_offsets[i] = GetRegisterInfoInterface()
+ .GetRegisterInfo()[first_regnos[i]]
+ .byte_offset;
+}
+
+uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
+const RegisterSet *
+NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
+ 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:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+}
+
+std::optional<NativeRegisterContextNetBSD_x86_64::RegSetKind>
+NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
+ uint32_t reg_num) const {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386)
+ return GPRegSet;
+ if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386)
+ return FPRegSet;
+ if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386)
+ return YMMRegSet;
+ if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386)
+ return std::nullopt; // MPXR
+ if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386)
+ return std::nullopt; // MPXC
+ if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386)
+ return DBRegSet; // DBR
+ break;
+ case llvm::Triple::x86_64:
+ if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64)
+ return GPRegSet;
+ if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64)
+ return FPRegSet;
+ if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64)
+ return YMMRegSet;
+ if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64)
+ return std::nullopt; // MPXR
+ if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64)
+ return std::nullopt; // MPXC
+ if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64)
+ return DBRegSet; // DBR
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ llvm_unreachable("Register does not belong to any register set");
+}
+
+Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(RegSetKind set) {
+ switch (set) {
+ case GPRegSet:
+ return DoRegisterSet(PT_GETREGS, m_gpr.data());
+ case DBRegSet:
+ return DoRegisterSet(PT_GETDBREGS, m_dbr.data());
+ case FPRegSet:
+ case YMMRegSet:
+ case MPXRegSet: {
+ struct iovec iov = {m_xstate.data(), m_xstate.size()};
+ Status ret = DoRegisterSet(PT_GETXSTATE, &iov);
+ assert(reinterpret_cast<xstate *>(m_xstate.data())->xs_rfbm & XCR0_X87);
+ return ret;
+ }
+ }
+ llvm_unreachable("NativeRegisterContextNetBSD_x86_64::ReadRegisterSet");
+}
+
+Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(RegSetKind set) {
+ switch (set) {
+ case GPRegSet:
+ return DoRegisterSet(PT_SETREGS, m_gpr.data());
+ case DBRegSet:
+ return DoRegisterSet(PT_SETDBREGS, m_dbr.data());
+ case FPRegSet:
+ case YMMRegSet:
+ case MPXRegSet: {
+ struct iovec iov = {&m_xstate, sizeof(m_xstate)};
+ return DoRegisterSet(PT_SETXSTATE, &iov);
+ }
+ }
+ llvm_unreachable("NativeRegisterContextNetBSD_x86_64::WriteRegisterSet");
+}
+
+Status
+NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ 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;
+ }
+
+ std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ RegSetKind set = *opt_set;
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ switch (set) {
+ case GPRegSet:
+ case FPRegSet:
+ case DBRegSet: {
+ void *data = GetOffsetRegSetData(set, reg_info->byte_offset);
+ FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_xstate.data() +
+ offsetof(xstate, xs_fxsave));
+ if (data == &fpr->ftag) // ftag
+ reg_value.SetUInt16(
+ AbridgedToFullTagWord(fpr->ftag, fpr->fstat, fpr->stmm));
+ else
+ reg_value.SetBytes(data, reg_info->byte_size, endian::InlHostByteOrder());
+ break;
+ }
+ case YMMRegSet: {
+ std::optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
+ if (!ymm_reg) {
+ error.SetErrorStringWithFormat(
+ "register \"%s\" not supported by CPU/kernel", reg_info->name);
+ } else {
+ YMMReg ymm = XStateToYMM(ymm_reg->xmm, ymm_reg->ymm_hi);
+ reg_value.SetBytes(ymm.bytes, reg_info->byte_size,
+ endian::InlHostByteOrder());
+ }
+ break;
+ }
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
+
+ return error;
+}
+
+Status NativeRegisterContextNetBSD_x86_64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+
+ Status error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ 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;
+ }
+
+ std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ RegSetKind set = *opt_set;
+ uint64_t new_xstate_bv = 0;
+
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ switch (set) {
+ case GPRegSet:
+ case DBRegSet:
+ ::memcpy(GetOffsetRegSetData(set, reg_info->byte_offset),
+ reg_value.GetBytes(), reg_value.GetByteSize());
+ break;
+ case FPRegSet: {
+ void *data = GetOffsetRegSetData(set, reg_info->byte_offset);
+ FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_xstate.data() +
+ offsetof(xstate, xs_fxsave));
+ if (data == &fpr->ftag) // ftag
+ fpr->ftag = FullToAbridgedTagWord(reg_value.GetAsUInt16());
+ else
+ ::memcpy(data, reg_value.GetBytes(), reg_value.GetByteSize());
+ if (data >= &fpr->xmm)
+ new_xstate_bv |= XCR0_SSE;
+ else if (data >= &fpr->mxcsr && data < &fpr->stmm)
+ new_xstate_bv |= XCR0_SSE;
+ else
+ new_xstate_bv |= XCR0_X87;
+ break;
+ }
+ case YMMRegSet: {
+ std::optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
+ if (!ymm_reg) {
+ error.SetErrorStringWithFormat(
+ "register \"%s\" not supported by CPU/kernel", reg_info->name);
+ } else {
+ YMMReg ymm;
+ ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+ YMMToXState(ymm, ymm_reg->xmm, ymm_reg->ymm_hi);
+ new_xstate_bv |= XCR0_SSE | XCR0_YMM_Hi128;
+ }
+ break;
+ }
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
+
+ if (new_xstate_bv != 0)
+ reinterpret_cast<xstate *>(m_xstate.data())->xs_xstate_bv |= new_xstate_bv;
+ return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ Status error;
+
+ data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
+ error = ReadRegisterSet(GPRegSet);
+ if (error.Fail())
+ return error;
+
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, m_gpr.data(), GetRegisterInfoInterface().GetGPRSize());
+ dst += GetRegisterInfoInterface().GetGPRSize();
+
+ return error;
+}
+
+Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextNetBSD_x86_64::%s invalid data_sp provided",
+ __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextNetBSD_x86_64::%s data_sp contained mismatched "
+ "data size, expected %zu, actual %" PRIu64,
+ __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
+ return error;
+ }
+
+ const uint8_t *src = data_sp->GetBytes();
+ if (src == nullptr) {
+ error.SetErrorStringWithFormat("NativeRegisterContextNetBSD_x86_64::%s "
+ "DataBuffer::GetBytes() returned a null "
+ "pointer",
+ __FUNCTION__);
+ return error;
+ }
+ ::memcpy(m_gpr.data(), src, GetRegisterInfoInterface().GetGPRSize());
+
+ error = WriteRegisterSet(GPRegSet);
+ if (error.Fail())
+ return error;
+ src += GetRegisterInfoInterface().GetGPRSize();
+
+ return error;
+}
+
+llvm::Error NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom(
+ NativeRegisterContextNetBSD &source) {
+ auto &r_source = static_cast<NativeRegisterContextNetBSD_x86_64 &>(source);
+ // NB: This implicitly reads the whole dbreg set.
+ RegisterValue dr7;
+ Status res = r_source.ReadRegister(GetDR(7), dr7);
+ if (!res.Fail()) {
+ // copy dbregs only if any watchpoints were set
+ if ((dr7.GetAsUInt64() & 0xFF) == 0)
+ return llvm::Error::success();
+
+ m_dbr = r_source.m_dbr;
+ res = WriteRegisterSet(DBRegSet);
+ }
+ return res.ToError();
+}
+
+uint8_t *
+NativeRegisterContextNetBSD_x86_64::GetOffsetRegSetData(RegSetKind set,
+ size_t reg_offset) {
+ uint8_t *base;
+ switch (set) {
+ case GPRegSet:
+ base = m_gpr.data();
+ break;
+ case FPRegSet:
+ base = m_xstate.data() + offsetof(xstate, xs_fxsave);
+ break;
+ case DBRegSet:
+ base = m_dbr.data();
+ break;
+ case YMMRegSet:
+ llvm_unreachable("GetRegSetData() is unsuitable for this regset.");
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
+ assert(reg_offset >= m_regset_offsets[set]);
+ return base + (reg_offset - m_regset_offsets[set]);
+}
+
+std::optional<NativeRegisterContextNetBSD_x86_64::YMMSplitPtr>
+NativeRegisterContextNetBSD_x86_64::GetYMMSplitReg(uint32_t reg) {
+ auto xst = reinterpret_cast<xstate *>(m_xstate.data());
+ if (!(xst->xs_rfbm & XCR0_SSE) || !(xst->xs_rfbm & XCR0_YMM_Hi128))
+ return std::nullopt;
+
+ uint32_t reg_index;
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ reg_index = reg - lldb_ymm0_i386;
+ break;
+ case llvm::Triple::x86_64:
+ reg_index = reg - lldb_ymm0_x86_64;
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ return YMMSplitPtr{&xst->xs_fxsave.fx_xmm[reg_index],
+ &xst->xs_ymm_hi128.xs_ymm[reg_index]};
+}
+
+#endif // defined(__x86_64__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
new file mode 100644
index 000000000000..e4597b2f69c6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
@@ -0,0 +1,94 @@
+//===-- NativeRegisterContextNetBSD_x86_64.h --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifndef lldb_NativeRegisterContextNetBSD_x86_64_h
+#define lldb_NativeRegisterContextNetBSD_x86_64_h
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include <array>
+#include <optional>
+
+#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
+#include "Plugins/Process/Utility/RegisterContext_x86.h"
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+namespace lldb_private {
+namespace process_netbsd {
+
+class NativeProcessNetBSD;
+
+class NativeRegisterContextNetBSD_x86_64
+ : public NativeRegisterContextNetBSD,
+ public NativeRegisterContextDBReg_x86 {
+public:
+ NativeRegisterContextNetBSD_x86_64(const ArchSpec &target_arch,
+ NativeThreadProtocol &native_thread);
+ uint32_t GetRegisterSetCount() const override;
+
+ const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+ Status ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ llvm::Error
+ CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) override;
+
+private:
+ // Private member types.
+ enum RegSetKind {
+ GPRegSet,
+ FPRegSet,
+ DBRegSet,
+ MaxRegularRegSet = DBRegSet,
+ YMMRegSet,
+ MPXRegSet,
+ MaxRegSet = MPXRegSet,
+ };
+
+ // Private member variables.
+ std::array<uint8_t, sizeof(struct reg)> m_gpr;
+ std::array<uint8_t, sizeof(struct xstate)> m_xstate;
+ std::array<uint8_t, sizeof(struct dbreg)> m_dbr;
+ std::array<size_t, MaxRegularRegSet + 1> m_regset_offsets;
+
+ std::optional<RegSetKind> GetSetForNativeRegNum(uint32_t reg_num) const;
+
+ Status ReadRegisterSet(RegSetKind set);
+ Status WriteRegisterSet(RegSetKind set);
+
+ uint8_t *GetOffsetRegSetData(RegSetKind set, size_t reg_offset);
+
+ struct YMMSplitPtr {
+ void *xmm;
+ void *ymm_hi;
+ };
+ std::optional<YMMSplitPtr> GetYMMSplitReg(uint32_t reg);
+};
+
+} // namespace process_netbsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextNetBSD_x86_64_h
+
+#endif // defined(__x86_64__)
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
new file mode 100644
index 000000000000..77b4301ea22e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
@@ -0,0 +1,329 @@
+//===-- NativeThreadNetBSD.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadNetBSD.h"
+#include "NativeRegisterContextNetBSD.h"
+
+#include "NativeProcessNetBSD.h"
+
+#include "Plugins/Process/POSIX/CrashReason.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/State.h"
+#include "llvm/Support/Errno.h"
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+// clang-format on
+
+#include <sstream>
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/sysctl.h>
+// clang-format on
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_netbsd;
+
+NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process,
+ lldb::tid_t tid)
+ : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
+ m_stop_info(), m_reg_context_up(
+NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this)
+), m_stop_description() {}
+
+Status NativeThreadNetBSD::Resume() {
+ Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
+ nullptr, GetID());
+ if (!ret.Success())
+ return ret;
+ ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(),
+ nullptr, GetID());
+ if (ret.Success())
+ SetRunning();
+ return ret;
+}
+
+Status NativeThreadNetBSD::SingleStep() {
+ Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
+ nullptr, GetID());
+ if (!ret.Success())
+ return ret;
+ ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(),
+ nullptr, GetID());
+ if (ret.Success())
+ SetStepping();
+ return ret;
+}
+
+Status NativeThreadNetBSD::Suspend() {
+ Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(),
+ nullptr, GetID());
+ if (ret.Success())
+ SetStopped();
+ return ret;
+}
+
+void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
+ const siginfo_t *info) {
+ Log *log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
+
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.signo = signo;
+
+ m_stop_description.clear();
+ if (info) {
+ switch (signo) {
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ m_stop_description = GetCrashReasonString(*info);
+ break;
+ }
+ }
+}
+
+void NativeThreadNetBSD::SetStoppedByBreakpoint() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonBreakpoint;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadNetBSD::SetStoppedByTrace() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonTrace;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadNetBSD::SetStoppedByExec() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonExec;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
+ lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
+
+ std::ostringstream ostr;
+ ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
+ ostr << wp_index;
+
+ ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
+
+ SetStopped();
+ m_stop_description = ostr.str();
+ m_stop_info.reason = StopReason::eStopReasonWatchpoint;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadNetBSD::SetStoppedByFork(lldb::pid_t child_pid,
+ lldb::tid_t child_tid) {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonFork;
+ m_stop_info.signo = SIGTRAP;
+ m_stop_info.details.fork.child_pid = child_pid;
+ m_stop_info.details.fork.child_tid = child_tid;
+}
+
+void NativeThreadNetBSD::SetStoppedByVFork(lldb::pid_t child_pid,
+ lldb::tid_t child_tid) {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonVFork;
+ m_stop_info.signo = SIGTRAP;
+ m_stop_info.details.fork.child_pid = child_pid;
+ m_stop_info.details.fork.child_tid = child_tid;
+}
+
+void NativeThreadNetBSD::SetStoppedByVForkDone() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonVForkDone;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadNetBSD::SetStoppedWithNoReason() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+ m_stop_info.signo = 0;
+}
+
+void NativeThreadNetBSD::SetStopped() {
+ const StateType new_state = StateType::eStateStopped;
+ m_state = new_state;
+ m_stop_description.clear();
+}
+
+void NativeThreadNetBSD::SetRunning() {
+ m_state = StateType::eStateRunning;
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void NativeThreadNetBSD::SetStepping() {
+ m_state = StateType::eStateStepping;
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+std::string NativeThreadNetBSD::GetName() {
+#ifdef PT_LWPSTATUS
+ struct ptrace_lwpstatus info = {};
+ info.pl_lwpid = m_tid;
+ Status error = NativeProcessNetBSD::PtraceWrapper(
+ PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info));
+ if (error.Fail()) {
+ return "";
+ }
+ return info.pl_name;
+#else
+ std::vector<struct kinfo_lwp> infos;
+ Log *log = GetLog(POSIXLog::Thread);
+
+ int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()),
+ sizeof(struct kinfo_lwp), 0};
+ size_t size;
+
+ if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) {
+ LLDB_LOG(log, "sysctl() for LWP info size failed: {0}",
+ llvm::sys::StrError());
+ return "";
+ }
+
+ mib[4] = size / sizeof(size_t);
+ infos.resize(size / sizeof(struct kinfo_lwp));
+
+ if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) {
+ LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError());
+ return "";
+ }
+
+ size_t nlwps = size / sizeof(struct kinfo_lwp);
+ for (size_t i = 0; i < nlwps; i++) {
+ if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) {
+ return infos[i].l_name;
+ }
+ }
+
+ LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid);
+ return "";
+#endif
+}
+
+lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
+
+bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) {
+ Log *log = GetLog(POSIXLog::Thread);
+ description.clear();
+
+ switch (m_state) {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ case eStateUnloaded:
+ stop_info = m_stop_info;
+ description = m_stop_description;
+
+ return true;
+
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
+ StateAsCString(m_state));
+ return false;
+ }
+ llvm_unreachable("unhandled StateType!");
+}
+
+NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() {
+ assert(m_reg_context_up);
+ return *m_reg_context_up;
+}
+
+Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, bool hardware) {
+ assert(m_state == eStateStopped);
+ if (!hardware)
+ return Status("not implemented");
+ Status error = RemoveWatchpoint(addr);
+ if (error.Fail())
+ return error;
+ uint32_t wp_index =
+ GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return Status("Setting hardware watchpoint failed.");
+ m_watchpoint_index_map.insert({addr, wp_index});
+ return Status();
+}
+
+Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
+ auto wp = m_watchpoint_index_map.find(addr);
+ if (wp == m_watchpoint_index_map.end())
+ return Status();
+ uint32_t wp_index = wp->second;
+ m_watchpoint_index_map.erase(wp);
+ if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
+ return Status();
+ return Status("Clearing hardware watchpoint failed.");
+}
+
+Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ assert(m_state == eStateStopped);
+ Status error = RemoveHardwareBreakpoint(addr);
+ if (error.Fail())
+ return error;
+
+ uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
+
+ if (bp_index == LLDB_INVALID_INDEX32)
+ return Status("Setting hardware breakpoint failed.");
+
+ m_hw_break_index_map.insert({addr, bp_index});
+ return Status();
+}
+
+Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+ auto bp = m_hw_break_index_map.find(addr);
+ if (bp == m_hw_break_index_map.end())
+ return Status();
+
+ uint32_t bp_index = bp->second;
+ if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
+ m_hw_break_index_map.erase(bp);
+ return Status();
+ }
+
+ return Status("Clearing hardware breakpoint failed.");
+}
+
+llvm::Error
+NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) {
+ llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
+ source.GetRegisterContext());
+ if (!s) {
+ m_watchpoint_index_map = source.m_watchpoint_index_map;
+ m_hw_break_index_map = source.m_hw_break_index_map;
+ }
+ return s;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
new file mode 100644
index 000000000000..ee9305337fda
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
@@ -0,0 +1,86 @@
+//===-- NativeThreadNetBSD.h ---------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeThreadNetBSD_H_
+#define liblldb_NativeThreadNetBSD_H_
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
+
+#include <csignal>
+#include <map>
+#include <string>
+
+namespace lldb_private {
+namespace process_netbsd {
+
+class NativeProcessNetBSD;
+
+class NativeThreadNetBSD : public NativeThreadProtocol {
+ friend class NativeProcessNetBSD;
+
+public:
+ NativeThreadNetBSD(NativeProcessNetBSD &process, lldb::tid_t tid);
+
+ // NativeThreadProtocol Interface
+ std::string GetName() override;
+
+ lldb::StateType GetState() override;
+
+ bool GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) override;
+
+ NativeRegisterContextNetBSD &GetRegisterContext() override;
+
+ Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+ bool hardware) override;
+
+ Status RemoveWatchpoint(lldb::addr_t addr) override;
+
+ Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+ Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+
+private:
+ // Interface for friend classes
+
+ Status Resume();
+ Status SingleStep();
+ Status Suspend();
+
+ void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
+ void SetStoppedByBreakpoint();
+ void SetStoppedByTrace();
+ void SetStoppedByExec();
+ void SetStoppedByWatchpoint(uint32_t wp_index);
+ void SetStoppedByFork(lldb::pid_t child_pid, lldb::tid_t child_tid);
+ void SetStoppedByVFork(lldb::pid_t child_pid, lldb::tid_t child_tid);
+ void SetStoppedByVForkDone();
+ void SetStoppedWithNoReason();
+ void SetStopped();
+ void SetRunning();
+ void SetStepping();
+
+ llvm::Error CopyWatchpointsFrom(NativeThreadNetBSD& source);
+
+ // Member Variables
+ lldb::StateType m_state;
+ ThreadStopInfo m_stop_info;
+ std::unique_ptr<NativeRegisterContextNetBSD> m_reg_context_up;
+ std::string m_stop_description;
+ using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
+ WatchpointIndexMap m_watchpoint_index_map;
+ WatchpointIndexMap m_hw_break_index_map;
+};
+
+typedef std::shared_ptr<NativeThreadNetBSD> NativeThreadNetBSDSP;
+} // namespace process_netbsd
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeThreadNetBSD_H_
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
new file mode 100644
index 000000000000..d93b7cd0ce56
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
@@ -0,0 +1,31 @@
+//===-- CrashReason.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CrashReason.h"
+
+#include "lldb/Target/UnixSignals.h"
+
+std::string GetCrashReasonString(const siginfo_t &info) {
+#if defined(si_lower) && defined(si_upper)
+ std::optional<lldb::addr_t> lower =
+ reinterpret_cast<lldb::addr_t>(info.si_lower);
+ std::optional<lldb::addr_t> upper =
+ reinterpret_cast<lldb::addr_t>(info.si_upper);
+#else
+ std::optional<lldb::addr_t> lower;
+ std::optional<lldb::addr_t> upper;
+#endif
+
+ std::string description =
+ lldb_private::UnixSignals::CreateForHost()->GetSignalDescription(
+ info.si_signo, info.si_code,
+ reinterpret_cast<uintptr_t>(info.si_addr), lower, upper);
+ assert(description.size() && "unexpected signal");
+
+ return "signal " + description;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.h b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.h
new file mode 100644
index 000000000000..2177726b76f0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/CrashReason.h
@@ -0,0 +1,20 @@
+//===-- CrashReason.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CrashReason_H_
+#define liblldb_CrashReason_H_
+
+#include "lldb/lldb-types.h"
+
+#include <csignal>
+
+#include <string>
+
+std::string GetCrashReasonString(const siginfo_t &info);
+
+#endif // #ifndef liblldb_CrashReason_H_
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp
new file mode 100644
index 000000000000..23e94a5f55e2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp
@@ -0,0 +1,189 @@
+//===-- NativeProcessELF.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessELF.h"
+
+#include "lldb/Utility/DataExtractor.h"
+#include <optional>
+
+namespace lldb_private {
+
+std::optional<uint64_t>
+NativeProcessELF::GetAuxValue(enum AuxVector::EntryType type) {
+ if (m_aux_vector == nullptr) {
+ auto buffer_or_error = GetAuxvData();
+ if (!buffer_or_error)
+ return std::nullopt;
+ DataExtractor auxv_data(buffer_or_error.get()->getBufferStart(),
+ buffer_or_error.get()->getBufferSize(),
+ GetByteOrder(), GetAddressByteSize());
+ m_aux_vector = std::make_unique<AuxVector>(auxv_data);
+ }
+
+ return m_aux_vector->GetAuxValue(type);
+}
+
+lldb::addr_t NativeProcessELF::GetSharedLibraryInfoAddress() {
+ if (!m_shared_library_info_addr) {
+ if (GetAddressByteSize() == 8)
+ m_shared_library_info_addr =
+ GetELFImageInfoAddress<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr,
+ llvm::ELF::Elf64_Dyn>();
+ else
+ m_shared_library_info_addr =
+ GetELFImageInfoAddress<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr,
+ llvm::ELF::Elf32_Dyn>();
+ }
+
+ return *m_shared_library_info_addr;
+}
+
+template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
+lldb::addr_t NativeProcessELF::GetELFImageInfoAddress() {
+ std::optional<uint64_t> maybe_phdr_addr =
+ GetAuxValue(AuxVector::AUXV_AT_PHDR);
+ std::optional<uint64_t> maybe_phdr_entry_size =
+ GetAuxValue(AuxVector::AUXV_AT_PHENT);
+ std::optional<uint64_t> maybe_phdr_num_entries =
+ GetAuxValue(AuxVector::AUXV_AT_PHNUM);
+ if (!maybe_phdr_addr || !maybe_phdr_entry_size || !maybe_phdr_num_entries)
+ return LLDB_INVALID_ADDRESS;
+ lldb::addr_t phdr_addr = *maybe_phdr_addr;
+ size_t phdr_entry_size = *maybe_phdr_entry_size;
+ size_t phdr_num_entries = *maybe_phdr_num_entries;
+
+ // Find the PT_DYNAMIC segment (.dynamic section) in the program header and
+ // what the load bias by calculating the difference of the program header
+ // load address and its virtual address.
+ lldb::offset_t load_bias;
+ bool found_load_bias = false;
+ lldb::addr_t dynamic_section_addr = 0;
+ uint64_t dynamic_section_size = 0;
+ bool found_dynamic_section = false;
+ ELF_PHDR phdr_entry;
+ for (size_t i = 0; i < phdr_num_entries; i++) {
+ size_t bytes_read;
+ auto error = ReadMemory(phdr_addr + i * phdr_entry_size, &phdr_entry,
+ sizeof(phdr_entry), bytes_read);
+ if (!error.Success())
+ return LLDB_INVALID_ADDRESS;
+ if (phdr_entry.p_type == llvm::ELF::PT_PHDR) {
+ load_bias = phdr_addr - phdr_entry.p_vaddr;
+ found_load_bias = true;
+ }
+
+ if (phdr_entry.p_type == llvm::ELF::PT_DYNAMIC) {
+ dynamic_section_addr = phdr_entry.p_vaddr;
+ dynamic_section_size = phdr_entry.p_memsz;
+ found_dynamic_section = true;
+ }
+ }
+
+ if (!found_load_bias || !found_dynamic_section)
+ return LLDB_INVALID_ADDRESS;
+
+ // Find the DT_DEBUG entry in the .dynamic section
+ dynamic_section_addr += load_bias;
+ ELF_DYN dynamic_entry;
+ size_t dynamic_num_entries = dynamic_section_size / sizeof(dynamic_entry);
+ for (size_t i = 0; i < dynamic_num_entries; i++) {
+ size_t bytes_read;
+ auto error = ReadMemory(dynamic_section_addr + i * sizeof(dynamic_entry),
+ &dynamic_entry, sizeof(dynamic_entry), bytes_read);
+ if (!error.Success())
+ return LLDB_INVALID_ADDRESS;
+ // Return the &DT_DEBUG->d_ptr which points to r_debug which contains the
+ // link_map.
+ if (dynamic_entry.d_tag == llvm::ELF::DT_DEBUG) {
+ return dynamic_section_addr + i * sizeof(dynamic_entry) +
+ sizeof(dynamic_entry.d_tag);
+ }
+ }
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
+ llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
+template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
+ llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr, llvm::ELF::Elf64_Dyn>();
+
+template <typename T>
+llvm::Expected<SVR4LibraryInfo>
+NativeProcessELF::ReadSVR4LibraryInfo(lldb::addr_t link_map_addr) {
+ ELFLinkMap<T> link_map;
+ size_t bytes_read;
+ auto error =
+ ReadMemory(link_map_addr, &link_map, sizeof(link_map), bytes_read);
+ if (!error.Success())
+ return error.ToError();
+
+ char name_buffer[PATH_MAX];
+ llvm::Expected<llvm::StringRef> string_or_error = ReadCStringFromMemory(
+ link_map.l_name, &name_buffer[0], sizeof(name_buffer), bytes_read);
+ if (!string_or_error)
+ return string_or_error.takeError();
+
+ SVR4LibraryInfo info;
+ info.name = string_or_error->str();
+ info.link_map = link_map_addr;
+ info.base_addr = link_map.l_addr;
+ info.ld_addr = link_map.l_ld;
+ info.next = link_map.l_next;
+
+ return info;
+}
+
+llvm::Expected<std::vector<SVR4LibraryInfo>>
+NativeProcessELF::GetLoadedSVR4Libraries() {
+ // Address of DT_DEBUG.d_ptr which points to r_debug
+ lldb::addr_t info_address = GetSharedLibraryInfoAddress();
+ if (info_address == LLDB_INVALID_ADDRESS)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Invalid shared library info address");
+ // Address of r_debug
+ lldb::addr_t address = 0;
+ size_t bytes_read;
+ auto status =
+ ReadMemory(info_address, &address, GetAddressByteSize(), bytes_read);
+ if (!status.Success())
+ return status.ToError();
+ if (address == 0)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Invalid r_debug address");
+ // Read r_debug.r_map
+ lldb::addr_t link_map = 0;
+ status = ReadMemory(address + GetAddressByteSize(), &link_map,
+ GetAddressByteSize(), bytes_read);
+ if (!status.Success())
+ return status.ToError();
+ if (link_map == 0)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Invalid link_map address");
+
+ std::vector<SVR4LibraryInfo> library_list;
+ while (link_map) {
+ llvm::Expected<SVR4LibraryInfo> info =
+ GetAddressByteSize() == 8 ? ReadSVR4LibraryInfo<uint64_t>(link_map)
+ : ReadSVR4LibraryInfo<uint32_t>(link_map);
+ if (!info)
+ return info.takeError();
+ if (!info->name.empty() && info->base_addr != 0)
+ library_list.push_back(*info);
+ link_map = info->next;
+ }
+
+ return library_list;
+}
+
+void NativeProcessELF::NotifyDidExec() {
+ NativeProcessProtocol::NotifyDidExec();
+ m_shared_library_info_addr.reset();
+}
+
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h
new file mode 100644
index 000000000000..937def94436b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h
@@ -0,0 +1,65 @@
+//===-- NativeProcessELF.h ------------------------------------ -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeProcessELF_H_
+#define liblldb_NativeProcessELF_H_
+
+#include "Plugins/Process/Utility/AuxVector.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include <optional>
+
+namespace lldb_private {
+
+/// \class NativeProcessELF
+/// Abstract class that extends \a NativeProcessProtocol with ELF specific
+/// logic. Meant to be subclassed by ELF based NativeProcess* implementations.
+class NativeProcessELF : public NativeProcessProtocol {
+ using NativeProcessProtocol::NativeProcessProtocol;
+
+public:
+ std::optional<uint64_t> GetAuxValue(enum AuxVector::EntryType type);
+
+protected:
+ template <typename T> struct ELFLinkMap {
+ T l_addr;
+ T l_name;
+ T l_ld;
+ T l_next;
+ T l_prev;
+ };
+
+ lldb::addr_t GetSharedLibraryInfoAddress() override;
+
+ template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
+ lldb::addr_t GetELFImageInfoAddress();
+
+ llvm::Expected<std::vector<SVR4LibraryInfo>>
+ GetLoadedSVR4Libraries() override;
+
+ template <typename T>
+ llvm::Expected<SVR4LibraryInfo>
+ ReadSVR4LibraryInfo(lldb::addr_t link_map_addr);
+
+ void NotifyDidExec() override;
+
+ std::unique_ptr<AuxVector> m_aux_vector;
+ std::optional<lldb::addr_t> m_shared_library_info_addr;
+};
+
+// Explicitly declare the two 32/64 bit templates that NativeProcessELF.cpp will
+// define. This allows us to keep the template definition here and usable
+// elsewhere.
+extern template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
+ llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
+extern template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
+ llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr, llvm::ELF::Elf64_Dyn>();
+
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
new file mode 100644
index 000000000000..7ad88aabc2c0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
@@ -0,0 +1,34 @@
+//===-- ProcessPOSIXLog.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessPOSIXLog.h"
+
+#include "llvm/Support/Threading.h"
+
+using namespace lldb_private;
+
+static constexpr Log::Category g_categories[] = {
+ {{"break"}, {"log breakpoints"}, POSIXLog::Breakpoints},
+ {{"memory"}, {"log memory reads and writes"}, POSIXLog::Memory},
+ {{"process"}, {"log process events and activities"}, POSIXLog::Process},
+ {{"ptrace"}, {"log all calls to ptrace"}, POSIXLog::Ptrace},
+ {{"registers"}, {"log register read/writes"}, POSIXLog::Registers},
+ {{"thread"}, {"log thread events and activities"}, POSIXLog::Thread},
+ {{"watch"}, {"log watchpoint related activities"}, POSIXLog::Watchpoints},
+};
+
+static Log::Channel g_channel(g_categories, POSIXLog::Process);
+
+template <> Log::Channel &lldb_private::LogChannelFor<POSIXLog>() {
+ return g_channel;
+}
+
+void ProcessPOSIXLog::Initialize() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() { Log::Register("posix", g_channel); });
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
new file mode 100644
index 000000000000..88cfdfd204c0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
@@ -0,0 +1,39 @@
+//===-- ProcessPOSIXLog.h -----------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessPOSIXLog_h_
+#define liblldb_ProcessPOSIXLog_h_
+
+#include "lldb/Utility/Log.h"
+#include "llvm/ADT/BitmaskEnum.h"
+
+namespace lldb_private {
+
+enum class POSIXLog : Log::MaskType {
+ Breakpoints = Log::ChannelFlag<0>,
+ Memory = Log::ChannelFlag<1>,
+ Process = Log::ChannelFlag<2>,
+ Ptrace = Log::ChannelFlag<3>,
+ Registers = Log::ChannelFlag<4>,
+ Thread = Log::ChannelFlag<5>,
+ Watchpoints = Log::ChannelFlag<6>,
+ Trace = Log::ChannelFlag<7>,
+ LLVM_MARK_AS_BITMASK_ENUM(Trace)
+};
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+class ProcessPOSIXLog {
+public:
+ static void Initialize();
+};
+
+template <> Log::Channel &LogChannelFor<POSIXLog>();
+} // namespace lldb_private
+
+#endif // liblldb_ProcessPOSIXLog_h_
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ARMDefines.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ARMDefines.h
new file mode 100644
index 000000000000..fd3965fade19
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ARMDefines.h
@@ -0,0 +1,191 @@
+//===-- ARMDefines.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMDEFINES_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMDEFINES_H
+
+#include "llvm/Support/ErrorHandling.h"
+
+#include <cassert>
+#include <cstdint>
+
+// Common definitions for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+// ARM shifter types
+enum ARM_ShifterType {
+ SRType_LSL,
+ SRType_LSR,
+ SRType_ASR,
+ SRType_ROR,
+ SRType_RRX,
+ SRType_Invalid
+};
+
+// ARM conditions // Meaning (integer) Meaning (floating-point)
+// Condition flags
+#define COND_EQ \
+ 0x0 // Equal Equal Z == 1
+#define COND_NE \
+ 0x1 // Not equal Not equal, or unordered Z == 0
+#define COND_CS \
+ 0x2 // Carry set >, ==, or unordered C == 1
+#define COND_HS 0x2
+#define COND_CC \
+ 0x3 // Carry clear Less than C == 0
+#define COND_LO 0x3
+#define COND_MI \
+ 0x4 // Minus, negative Less than N == 1
+#define COND_PL \
+ 0x5 // Plus, positive or zero >, ==, or unordered N == 0
+#define COND_VS \
+ 0x6 // Overflow Unordered V == 1
+#define COND_VC \
+ 0x7 // No overflow Not unordered V == 0
+#define COND_HI \
+ 0x8 // Unsigned higher Greater than, or unordered C == 1 and Z ==
+ // 0
+#define COND_LS \
+ 0x9 // Unsigned lower or same Less than or equal C == 0 or Z ==
+ // 1
+#define COND_GE \
+ 0xA // Greater than or equal Greater than or equal N == V
+#define COND_LT \
+ 0xB // Less than Less than, or unordered N != V
+#define COND_GT \
+ 0xC // Greater than Greater than Z == 0 and N ==
+ // V
+#define COND_LE \
+ 0xD // Less than or equal <, ==, or unordered Z == 1 or N !=
+ // V
+#define COND_AL \
+ 0xE // Always (unconditional) Always (unconditional) Any
+#define COND_UNCOND 0xF
+
+static inline const char *ARMCondCodeToString(uint32_t CC) {
+ switch (CC) {
+ case COND_EQ:
+ return "eq";
+ case COND_NE:
+ return "ne";
+ case COND_HS:
+ return "hs";
+ case COND_LO:
+ return "lo";
+ case COND_MI:
+ return "mi";
+ case COND_PL:
+ return "pl";
+ case COND_VS:
+ return "vs";
+ case COND_VC:
+ return "vc";
+ case COND_HI:
+ return "hi";
+ case COND_LS:
+ return "ls";
+ case COND_GE:
+ return "ge";
+ case COND_LT:
+ return "lt";
+ case COND_GT:
+ return "gt";
+ case COND_LE:
+ return "le";
+ case COND_AL:
+ return "al";
+ }
+ llvm_unreachable("Unknown condition code");
+}
+
+static inline bool ARMConditionPassed(const uint32_t condition,
+ const uint32_t cpsr) {
+ const uint32_t cpsr_n = (cpsr >> 31) & 1u; // Negative condition code flag
+ const uint32_t cpsr_z = (cpsr >> 30) & 1u; // Zero condition code flag
+ const uint32_t cpsr_c = (cpsr >> 29) & 1u; // Carry condition code flag
+ const uint32_t cpsr_v = (cpsr >> 28) & 1u; // Overflow condition code flag
+
+ switch (condition) {
+ case COND_EQ:
+ return (cpsr_z == 1);
+ case COND_NE:
+ return (cpsr_z == 0);
+ case COND_CS:
+ return (cpsr_c == 1);
+ case COND_CC:
+ return (cpsr_c == 0);
+ case COND_MI:
+ return (cpsr_n == 1);
+ case COND_PL:
+ return (cpsr_n == 0);
+ case COND_VS:
+ return (cpsr_v == 1);
+ case COND_VC:
+ return (cpsr_v == 0);
+ case COND_HI:
+ return ((cpsr_c == 1) && (cpsr_z == 0));
+ case COND_LS:
+ return ((cpsr_c == 0) || (cpsr_z == 1));
+ case COND_GE:
+ return (cpsr_n == cpsr_v);
+ case COND_LT:
+ return (cpsr_n != cpsr_v);
+ case COND_GT:
+ return ((cpsr_z == 0) && (cpsr_n == cpsr_v));
+ case COND_LE:
+ return ((cpsr_z == 1) || (cpsr_n != cpsr_v));
+ case COND_AL:
+ case COND_UNCOND:
+ default:
+ return true;
+ }
+ return false;
+}
+
+// Bit positions for CPSR
+#define CPSR_T_POS 5
+#define CPSR_F_POS 6
+#define CPSR_I_POS 7
+#define CPSR_A_POS 8
+#define CPSR_E_POS 9
+#define CPSR_J_POS 24
+#define CPSR_Q_POS 27
+#define CPSR_V_POS 28
+#define CPSR_C_POS 29
+#define CPSR_Z_POS 30
+#define CPSR_N_POS 31
+
+// CPSR mode definitions
+#define CPSR_MODE_USR 0x10u
+#define CPSR_MODE_FIQ 0x11u
+#define CPSR_MODE_IRQ 0x12u
+#define CPSR_MODE_SVC 0x13u
+#define CPSR_MODE_ABT 0x17u
+#define CPSR_MODE_UND 0x1bu
+#define CPSR_MODE_SYS 0x1fu
+
+// Masks for CPSR
+#define MASK_CPSR_MODE_MASK (0x0000001fu)
+#define MASK_CPSR_IT_MASK (0x0600fc00u)
+#define MASK_CPSR_T (1u << CPSR_T_POS)
+#define MASK_CPSR_F (1u << CPSR_F_POS)
+#define MASK_CPSR_I (1u << CPSR_I_POS)
+#define MASK_CPSR_A (1u << CPSR_A_POS)
+#define MASK_CPSR_E (1u << CPSR_E_POS)
+#define MASK_CPSR_GE_MASK (0x000f0000u)
+#define MASK_CPSR_J (1u << CPSR_J_POS)
+#define MASK_CPSR_Q (1u << CPSR_Q_POS)
+#define MASK_CPSR_V (1u << CPSR_V_POS)
+#define MASK_CPSR_C (1u << CPSR_C_POS)
+#define MASK_CPSR_Z (1u << CPSR_Z_POS)
+#define MASK_CPSR_N (1u << CPSR_N_POS)
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMDEFINES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ARMUtils.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ARMUtils.h
new file mode 100644
index 000000000000..9256f926275b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ARMUtils.h
@@ -0,0 +1,377 @@
+//===-- ARMUtils.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H
+
+#include "ARMDefines.h"
+#include "InstructionUtils.h"
+#include "llvm/ADT/bit.h"
+#include "llvm/Support/MathExtras.h"
+
+// Common utilities for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+static inline uint32_t Align(uint32_t val, uint32_t alignment) {
+ return alignment * (val / alignment);
+}
+
+static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5,
+ ARM_ShifterType &shift_t) {
+ switch (type) {
+ default:
+ assert(0 && "Invalid shift type");
+ break;
+ case 0:
+ shift_t = SRType_LSL;
+ return imm5;
+ case 1:
+ shift_t = SRType_LSR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 2:
+ shift_t = SRType_ASR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 3:
+ if (imm5 == 0) {
+ shift_t = SRType_RRX;
+ return 1;
+ } else {
+ shift_t = SRType_ROR;
+ return imm5;
+ }
+ }
+ shift_t = SRType_Invalid;
+ return UINT32_MAX;
+}
+
+// A8.6.35 CMP (register) -- Encoding T3
+// Convenience function.
+static inline uint32_t DecodeImmShiftThumb(const uint32_t opcode,
+ ARM_ShifterType &shift_t) {
+ return DecodeImmShift(Bits32(opcode, 5, 4),
+ Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 6),
+ shift_t);
+}
+
+// A8.6.35 CMP (register) -- Encoding A1
+// Convenience function.
+static inline uint32_t DecodeImmShiftARM(const uint32_t opcode,
+ ARM_ShifterType &shift_t) {
+ return DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t);
+}
+
+static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t,
+ const uint32_t imm5) {
+ ARM_ShifterType dont_care;
+ return DecodeImmShift(shift_t, imm5, dont_care);
+}
+
+static inline ARM_ShifterType DecodeRegShift(const uint32_t type) {
+ switch (type) {
+ default:
+ // assert(0 && "Invalid shift type");
+ return SRType_Invalid;
+ case 0:
+ return SRType_LSL;
+ case 1:
+ return SRType_LSR;
+ case 2:
+ return SRType_ASR;
+ case 3:
+ return SRType_ROR;
+ }
+}
+
+static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount,
+ uint32_t &carry_out, bool *success) {
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;
+ return value << amount;
+}
+
+static inline uint32_t LSL(const uint32_t value, const uint32_t amount,
+ bool *success) {
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSL_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount,
+ uint32_t &carry_out, bool *success) {
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;
+ return value >> amount;
+}
+
+static inline uint32_t LSR(const uint32_t value, const uint32_t amount,
+ bool *success) {
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount,
+ uint32_t &carry_out, bool *success) {
+ if (amount == 0 || amount > 32) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ bool negative = BitIsSet(value, 31);
+ if (amount <= 32) {
+ carry_out = Bit32(value, amount - 1);
+ int64_t extended = llvm::SignExtend64<32>(value);
+ return UnsignedBits(extended, amount + 31, amount);
+ } else {
+ carry_out = (negative ? 1 : 0);
+ return (negative ? 0xffffffff : 0);
+ }
+}
+
+static inline uint32_t ASR(const uint32_t value, const uint32_t amount,
+ bool *success) {
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ASR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount,
+ uint32_t &carry_out, bool *success) {
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ uint32_t result = llvm::rotr<uint32_t>(value, amount);
+ carry_out = Bit32(value, 31);
+ return result;
+}
+
+static inline uint32_t ROR(const uint32_t value, const uint32_t amount,
+ bool *success) {
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ROR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in,
+ uint32_t &carry_out, bool *success) {
+ *success = true;
+ carry_out = Bit32(value, 0);
+ return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
+}
+
+static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in,
+ bool *success) {
+ *success = true;
+ uint32_t dont_care;
+ uint32_t result = RRX_C(value, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type,
+ const uint32_t amount, const uint32_t carry_in,
+ uint32_t &carry_out, bool *success) {
+ if (type == SRType_RRX && amount != 1) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+
+ if (amount == 0) {
+ carry_out = carry_in;
+ return value;
+ }
+ uint32_t result;
+ switch (type) {
+ case SRType_LSL:
+ result = LSL_C(value, amount, carry_out, success);
+ break;
+ case SRType_LSR:
+ result = LSR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ASR:
+ result = ASR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ROR:
+ result = ROR_C(value, amount, carry_out, success);
+ break;
+ case SRType_RRX:
+ result = RRX_C(value, carry_in, carry_out, success);
+ break;
+ default:
+ *success = false;
+ break;
+ }
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type,
+ const uint32_t amount, const uint32_t carry_in,
+ bool *success) {
+ // Don't care about carry out in this case.
+ uint32_t dont_care;
+ uint32_t result = Shift_C(value, type, amount, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t bits(const uint32_t val, const uint32_t msbit,
+ const uint32_t lsbit) {
+ return Bits32(val, msbit, lsbit);
+}
+
+static inline uint32_t bit(const uint32_t val, const uint32_t msbit) {
+ return bits(val, msbit, msbit);
+}
+
+static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift) {
+ uint32_t m = shift % N;
+ return (val >> m) | (val << (N - m));
+}
+
+// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
+static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in,
+ uint32_t &carry_out) {
+ uint32_t imm32; // the expanded result
+ uint32_t imm = bits(opcode, 7, 0); // immediate value
+ uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount
+ if (amt == 0) {
+ imm32 = imm;
+ carry_out = carry_in;
+ } else {
+ imm32 = ror(imm, 32, amt);
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ARMExpandImm(uint32_t opcode) {
+ // 'carry_in' argument to following function call does not affect the imm32
+ // result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ARMExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
+static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in,
+ uint32_t &carry_out) {
+ uint32_t imm32 = 0; // the expanded result
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t abcdefgh = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
+
+ if (bits(imm12, 11, 10) == 0) {
+ switch (bits(imm12, 9, 8)) {
+ default: // Keep static analyzer happy with a default case
+ break;
+
+ case 0:
+ imm32 = abcdefgh;
+ break;
+
+ case 1:
+ imm32 = abcdefgh << 16 | abcdefgh;
+ break;
+
+ case 2:
+ imm32 = abcdefgh << 24 | abcdefgh << 8;
+ break;
+
+ case 3:
+ imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
+ break;
+ }
+ carry_out = carry_in;
+ } else {
+ const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
+ imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ThumbExpandImm(uint32_t opcode) {
+ // 'carry_in' argument to following function call does not affect the imm32
+ // result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ThumbExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// imm32 = ZeroExtend(i:imm3:imm8, 32)
+static inline uint32_t ThumbImm12(uint32_t opcode) {
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
+ return imm12;
+}
+
+// imm32 = ZeroExtend(imm7:'00', 32)
+static inline uint32_t ThumbImm7Scaled(uint32_t opcode) {
+ const uint32_t imm7 = bits(opcode, 6, 0);
+ return imm7 * 4;
+}
+
+// imm32 = ZeroExtend(imm8:'00', 32)
+static inline uint32_t ThumbImm8Scaled(uint32_t opcode) {
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ return imm8 * 4;
+}
+
+// This function performs the check for the register numbers 13 and 15 that are
+// not permitted for many Thumb register specifiers.
+static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.cpp
new file mode 100644
index 000000000000..f495ffb1924e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.cpp
@@ -0,0 +1,98 @@
+//===-- AuxVector.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "AuxVector.h"
+#include <optional>
+
+AuxVector::AuxVector(const lldb_private::DataExtractor &data) {
+ ParseAuxv(data);
+}
+
+void AuxVector::ParseAuxv(const lldb_private::DataExtractor &data) {
+ lldb::offset_t offset = 0;
+ const size_t value_type_size = data.GetAddressByteSize() * 2;
+ while (data.ValidOffsetForDataOfSize(offset, value_type_size)) {
+ // We're not reading an address but an int that could be 32 or 64 bit
+ // depending on the address size, which is what GetAddress does.
+ const uint64_t type = data.GetAddress(&offset);
+ const uint64_t value = data.GetAddress(&offset);
+ if (type == AUXV_AT_NULL)
+ break;
+ if (type == AUXV_AT_IGNORE)
+ continue;
+
+ m_auxv_entries[type] = value;
+ }
+}
+
+std::optional<uint64_t>
+AuxVector::GetAuxValue(enum EntryType entry_type) const {
+ auto it = m_auxv_entries.find(static_cast<uint64_t>(entry_type));
+ if (it != m_auxv_entries.end())
+ return it->second;
+ return std::nullopt;
+}
+
+void AuxVector::DumpToLog(lldb_private::Log *log) const {
+ if (!log)
+ return;
+
+ log->PutCString("AuxVector: ");
+ for (auto entry : m_auxv_entries) {
+ LLDB_LOGF(log, " %s [%" PRIu64 "]: %" PRIx64,
+ GetEntryName(static_cast<EntryType>(entry.first)), entry.first,
+ entry.second);
+ }
+}
+
+const char *AuxVector::GetEntryName(EntryType type) const {
+ const char *name = "AT_???";
+
+#define ENTRY_NAME(_type) \
+ _type: \
+ name = &#_type[5]
+ switch (type) {
+ case ENTRY_NAME(AUXV_AT_NULL); break;
+ case ENTRY_NAME(AUXV_AT_IGNORE); break;
+ case ENTRY_NAME(AUXV_AT_EXECFD); break;
+ case ENTRY_NAME(AUXV_AT_PHDR); break;
+ case ENTRY_NAME(AUXV_AT_PHENT); break;
+ case ENTRY_NAME(AUXV_AT_PHNUM); break;
+ case ENTRY_NAME(AUXV_AT_PAGESZ); break;
+ case ENTRY_NAME(AUXV_AT_BASE); break;
+ case ENTRY_NAME(AUXV_AT_FLAGS); break;
+ case ENTRY_NAME(AUXV_AT_ENTRY); break;
+ case ENTRY_NAME(AUXV_AT_NOTELF); break;
+ case ENTRY_NAME(AUXV_AT_UID); break;
+ case ENTRY_NAME(AUXV_AT_EUID); break;
+ case ENTRY_NAME(AUXV_AT_GID); break;
+ case ENTRY_NAME(AUXV_AT_EGID); break;
+ case ENTRY_NAME(AUXV_AT_CLKTCK); break;
+ case ENTRY_NAME(AUXV_AT_PLATFORM); break;
+ case ENTRY_NAME(AUXV_AT_HWCAP); break;
+ case ENTRY_NAME(AUXV_AT_FPUCW); break;
+ case ENTRY_NAME(AUXV_AT_DCACHEBSIZE); break;
+ case ENTRY_NAME(AUXV_AT_ICACHEBSIZE); break;
+ case ENTRY_NAME(AUXV_AT_UCACHEBSIZE); break;
+ case ENTRY_NAME(AUXV_AT_IGNOREPPC); break;
+ case ENTRY_NAME(AUXV_AT_SECURE); break;
+ case ENTRY_NAME(AUXV_AT_BASE_PLATFORM); break;
+ case ENTRY_NAME(AUXV_AT_RANDOM); break;
+ case ENTRY_NAME(AUXV_AT_HWCAP2); break;
+ case ENTRY_NAME(AUXV_AT_EXECFN); break;
+ case ENTRY_NAME(AUXV_AT_SYSINFO); break;
+ case ENTRY_NAME(AUXV_AT_SYSINFO_EHDR); break;
+ case ENTRY_NAME(AUXV_AT_L1I_CACHESHAPE); break;
+ case ENTRY_NAME(AUXV_AT_L1D_CACHESHAPE); break;
+ case ENTRY_NAME(AUXV_AT_L2_CACHESHAPE); break;
+ case ENTRY_NAME(AUXV_AT_L3_CACHESHAPE); break;
+ }
+#undef ENTRY_NAME
+
+ return name;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h
new file mode 100644
index 000000000000..2670b34f6b0a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h
@@ -0,0 +1,84 @@
+//===-- AuxVector.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_AUXVECTOR_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_AUXVECTOR_H
+
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include <optional>
+#include <unordered_map>
+
+class AuxVector {
+
+public:
+ AuxVector(const lldb_private::DataExtractor &data);
+
+ /// Constants describing the type of entry.
+ /// On Linux and FreeBSD, running "LD_SHOW_AUXV=1 ./executable" will spew AUX
+ /// information. Added AUXV prefix to avoid potential conflicts with system-
+ /// defined macros. For FreeBSD, the numbers can be found in sys/elf_common.h.
+ enum EntryType {
+ AUXV_AT_NULL = 0, ///< End of auxv.
+ AUXV_AT_IGNORE = 1, ///< Ignore entry.
+ AUXV_AT_EXECFD = 2, ///< File descriptor of program.
+ AUXV_AT_PHDR = 3, ///< Program headers.
+ AUXV_AT_PHENT = 4, ///< Size of program header.
+ AUXV_AT_PHNUM = 5, ///< Number of program headers.
+ AUXV_AT_PAGESZ = 6, ///< Page size.
+ AUXV_AT_BASE = 7, ///< Interpreter base address.
+ AUXV_AT_FLAGS = 8, ///< Flags.
+ AUXV_AT_ENTRY = 9, ///< Program entry point.
+ AUXV_AT_NOTELF = 10, ///< Set if program is not an ELF.
+ AUXV_AT_UID = 11, ///< UID.
+ AUXV_AT_EUID = 12, ///< Effective UID.
+ AUXV_AT_GID = 13, ///< GID.
+ AUXV_AT_EGID = 14, ///< Effective GID.
+
+ // At this point Linux and FreeBSD diverge and many of the following values
+ // are Linux specific. If you use them make sure you are in Linux specific
+ // code or they have the same value on other platforms.
+
+ AUXV_AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)).
+ AUXV_AT_PLATFORM = 15, ///< String identifying platform.
+ AUXV_AT_HWCAP =
+ 16, ///< Machine dependent hints about processor capabilities.
+ AUXV_AT_FPUCW = 18, ///< Used FPU control word.
+ AUXV_AT_DCACHEBSIZE = 19, ///< Data cache block size.
+ AUXV_AT_ICACHEBSIZE = 20, ///< Instruction cache block size.
+ AUXV_AT_UCACHEBSIZE = 21, ///< Unified cache block size.
+ AUXV_AT_IGNOREPPC = 22, ///< Entry should be ignored.
+ AUXV_AT_SECURE = 23, ///< Boolean, was exec setuid-like?
+ AUXV_AT_BASE_PLATFORM = 24, ///< String identifying real platforms.
+ AUXV_AT_RANDOM = 25, ///< Address of 16 random bytes.
+ AUXV_AT_HWCAP2 = 26, ///< Extension of AT_HWCAP.
+ AUXV_AT_EXECFN = 31, ///< Filename of executable.
+ AUXV_AT_SYSINFO = 32, ///< Pointer to the global system page used for system
+ /// calls and other nice things.
+ AUXV_AT_SYSINFO_EHDR = 33,
+ AUXV_AT_L1I_CACHESHAPE = 34, ///< Shapes of the caches.
+ AUXV_AT_L1D_CACHESHAPE = 35,
+ AUXV_AT_L2_CACHESHAPE = 36,
+ AUXV_AT_L3_CACHESHAPE = 37,
+
+ // Platform specific values which may overlap the Linux values.
+
+ AUXV_FREEBSD_AT_HWCAP = 25, ///< FreeBSD specific AT_HWCAP value.
+ };
+
+ std::optional<uint64_t> GetAuxValue(enum EntryType entry_type) const;
+ void DumpToLog(lldb_private::Log *log) const;
+ const char *GetEntryName(EntryType type) const;
+
+private:
+ void ParseAuxv(const lldb_private::DataExtractor &data);
+
+ std::unordered_map<uint64_t, uint64_t> m_auxv_entries;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp
new file mode 100644
index 000000000000..ebf197339446
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp
@@ -0,0 +1,139 @@
+//===-- FreeBSDSignals.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "FreeBSDSignals.h"
+
+#ifdef __FreeBSD__
+#include <csignal>
+
+#ifndef FPE_FLTIDO
+#define FPE_FLTIDO 9
+#endif
+
+#define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \
+ static_assert(signal_name == signal_value, \
+ "Value mismatch for signal number " #signal_name); \
+ static_assert(code_name == code_value, \
+ "Value mismatch for signal code " #code_name); \
+ AddSignalCode(signal_value, code_value, __VA_ARGS__)
+#else
+#define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \
+ AddSignalCode(signal_value, code_value, __VA_ARGS__)
+#endif /* ifdef __FreeBSD */
+
+using namespace lldb_private;
+
+FreeBSDSignals::FreeBSDSignals() : UnixSignals() { Reset(); }
+
+void FreeBSDSignals::Reset() {
+ UnixSignals::Reset();
+
+ // clang-format off
+ // SIGILL
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLOPC, 1, "illegal opcode");
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLOPN, 2, "illegal operand");
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLADR, 3, "illegal addressing mode");
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLTRP, 4, "illegal trap");
+ ADD_SIGCODE(SIGILL, 4, ILL_PRVOPC, 5, "privileged opcode");
+ ADD_SIGCODE(SIGILL, 4, ILL_PRVREG, 6, "privileged register");
+ ADD_SIGCODE(SIGILL, 4, ILL_COPROC, 7, "coprocessor error");
+ ADD_SIGCODE(SIGILL, 4, ILL_BADSTK, 8, "internal stack error");
+
+ // SIGFPE
+ ADD_SIGCODE(SIGFPE, 8, FPE_INTOVF, 1, "integer overflow");
+ ADD_SIGCODE(SIGFPE, 8, FPE_INTDIV, 2, "integer divide by zero");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTDIV, 3, "floating point divide by zero");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTOVF, 4, "floating point overflow");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTUND, 5, "floating point underflow");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTRES, 6, "floating point inexact result");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTINV, 7, "invalid floating point operation");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTSUB, 8, "subscript out of range");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTIDO, 9, "input denormal operation");
+
+ // SIGBUS
+ ADD_SIGCODE(SIGBUS, 10, BUS_ADRALN, 1, "invalid address alignment");
+ ADD_SIGCODE(SIGBUS, 10, BUS_ADRERR, 2, "nonexistent physical address");
+ ADD_SIGCODE(SIGBUS, 10, BUS_OBJERR, 3, "object-specific hardware error");
+ ADD_SIGCODE(SIGBUS, 10, BUS_OOMERR, 100, "no memory");
+
+ // SIGSEGV
+ ADD_SIGCODE(SIGSEGV, 11, SEGV_MAPERR, 1, "address not mapped to object",
+ SignalCodePrintOption::Address);
+ ADD_SIGCODE(SIGSEGV, 11, SEGV_ACCERR, 2, "invalid permissions for mapped object",
+ SignalCodePrintOption::Address);
+ ADD_SIGCODE(SIGSEGV, 11, SEGV_PKUERR, 100, "PKU violation",
+ SignalCodePrintOption::Address);
+
+ // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION
+ // ===== ============== ======== ====== ====== ========================
+ AddSignal(32, "SIGTHR", false, false, false, "thread interrupt");
+ AddSignal(33, "SIGLIBRT", false, false, false, "reserved by real-time library");
+ AddSignal(65, "SIGRTMIN", false, false, false, "real time signal 0");
+ AddSignal(66, "SIGRTMIN+1", false, false, false, "real time signal 1");
+ AddSignal(67, "SIGRTMIN+2", false, false, false, "real time signal 2");
+ AddSignal(68, "SIGRTMIN+3", false, false, false, "real time signal 3");
+ AddSignal(69, "SIGRTMIN+4", false, false, false, "real time signal 4");
+ AddSignal(70, "SIGRTMIN+5", false, false, false, "real time signal 5");
+ AddSignal(71, "SIGRTMIN+6", false, false, false, "real time signal 6");
+ AddSignal(72, "SIGRTMIN+7", false, false, false, "real time signal 7");
+ AddSignal(73, "SIGRTMIN+8", false, false, false, "real time signal 8");
+ AddSignal(74, "SIGRTMIN+9", false, false, false, "real time signal 9");
+ AddSignal(75, "SIGRTMIN+10", false, false, false, "real time signal 10");
+ AddSignal(76, "SIGRTMIN+11", false, false, false, "real time signal 11");
+ AddSignal(77, "SIGRTMIN+12", false, false, false, "real time signal 12");
+ AddSignal(78, "SIGRTMIN+13", false, false, false, "real time signal 13");
+ AddSignal(79, "SIGRTMIN+14", false, false, false, "real time signal 14");
+ AddSignal(80, "SIGRTMIN+15", false, false, false, "real time signal 15");
+ AddSignal(81, "SIGRTMIN+16", false, false, false, "real time signal 16");
+ AddSignal(82, "SIGRTMIN+17", false, false, false, "real time signal 17");
+ AddSignal(83, "SIGRTMIN+18", false, false, false, "real time signal 18");
+ AddSignal(84, "SIGRTMIN+19", false, false, false, "real time signal 19");
+ AddSignal(85, "SIGRTMIN+20", false, false, false, "real time signal 20");
+ AddSignal(86, "SIGRTMIN+21", false, false, false, "real time signal 21");
+ AddSignal(87, "SIGRTMIN+22", false, false, false, "real time signal 22");
+ AddSignal(88, "SIGRTMIN+23", false, false, false, "real time signal 23");
+ AddSignal(89, "SIGRTMIN+24", false, false, false, "real time signal 24");
+ AddSignal(90, "SIGRTMIN+25", false, false, false, "real time signal 25");
+ AddSignal(91, "SIGRTMIN+26", false, false, false, "real time signal 26");
+ AddSignal(92, "SIGRTMIN+27", false, false, false, "real time signal 27");
+ AddSignal(93, "SIGRTMIN+28", false, false, false, "real time signal 28");
+ AddSignal(94, "SIGRTMIN+29", false, false, false, "real time signal 29");
+ AddSignal(95, "SIGRTMIN+30", false, false, false, "real time signal 30");
+ AddSignal(96, "SIGRTMAX-30", false, false, false, "real time signal 31");
+ AddSignal(97, "SIGRTMAX-29", false, false, false, "real time signal 32");
+ AddSignal(98, "SIGRTMAX-28", false, false, false, "real time signal 33");
+ AddSignal(99, "SIGRTMAX-27", false, false, false, "real time signal 34");
+ AddSignal(100, "SIGRTMAX-26", false, false, false, "real time signal 35");
+ AddSignal(101, "SIGRTMAX-25", false, false, false, "real time signal 36");
+ AddSignal(102, "SIGRTMAX-24", false, false, false, "real time signal 37");
+ AddSignal(103, "SIGRTMAX-23", false, false, false, "real time signal 38");
+ AddSignal(104, "SIGRTMAX-22", false, false, false, "real time signal 39");
+ AddSignal(105, "SIGRTMAX-21", false, false, false, "real time signal 40");
+ AddSignal(106, "SIGRTMAX-20", false, false, false, "real time signal 41");
+ AddSignal(107, "SIGRTMAX-19", false, false, false, "real time signal 42");
+ AddSignal(108, "SIGRTMAX-18", false, false, false, "real time signal 43");
+ AddSignal(109, "SIGRTMAX-17", false, false, false, "real time signal 44");
+ AddSignal(110, "SIGRTMAX-16", false, false, false, "real time signal 45");
+ AddSignal(111, "SIGRTMAX-15", false, false, false, "real time signal 46");
+ AddSignal(112, "SIGRTMAX-14", false, false, false, "real time signal 47");
+ AddSignal(113, "SIGRTMAX-13", false, false, false, "real time signal 48");
+ AddSignal(114, "SIGRTMAX-12", false, false, false, "real time signal 49");
+ AddSignal(115, "SIGRTMAX-11", false, false, false, "real time signal 50");
+ AddSignal(116, "SIGRTMAX-10", false, false, false, "real time signal 51");
+ AddSignal(117, "SIGRTMAX-9", false, false, false, "real time signal 52");
+ AddSignal(118, "SIGRTMAX-8", false, false, false, "real time signal 53");
+ AddSignal(119, "SIGRTMAX-7", false, false, false, "real time signal 54");
+ AddSignal(120, "SIGRTMAX-6", false, false, false, "real time signal 55");
+ AddSignal(121, "SIGRTMAX-5", false, false, false, "real time signal 56");
+ AddSignal(122, "SIGRTMAX-4", false, false, false, "real time signal 57");
+ AddSignal(123, "SIGRTMAX-3", false, false, false, "real time signal 58");
+ AddSignal(124, "SIGRTMAX-2", false, false, false, "real time signal 59");
+ AddSignal(125, "SIGRTMAX-1", false, false, false, "real time signal 60");
+ AddSignal(126, "SIGRTMAX", false, false, false, "real time signal 61");
+ // clang-format on
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h
new file mode 100644
index 000000000000..c4c810e54985
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h
@@ -0,0 +1,27 @@
+//===-- FreeBSDSignals.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_FREEBSDSIGNALS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_FREEBSDSIGNALS_H
+
+#include "lldb/Target/UnixSignals.h"
+
+namespace lldb_private {
+
+/// FreeBSD specific set of Unix signals.
+class FreeBSDSignals : public UnixSignals {
+public:
+ FreeBSDSignals();
+
+private:
+ void Reset() override;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_FREEBSDSIGNALS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp
new file mode 100644
index 000000000000..15981a2c1cb8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp
@@ -0,0 +1,181 @@
+//===-- GDBRemoteSignals.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteSignals.h"
+
+using namespace lldb_private;
+
+GDBRemoteSignals::GDBRemoteSignals() : UnixSignals() { Reset(); }
+
+GDBRemoteSignals::GDBRemoteSignals(const lldb::UnixSignalsSP &rhs)
+ : UnixSignals(*rhs) {}
+
+void GDBRemoteSignals::Reset() {
+ m_signals.clear();
+ // clang-format off
+ // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION
+ // ====== ============== ======== ====== ====== ===================================================
+ AddSignal(1, "SIGHUP", false, true, true, "hangup");
+ AddSignal(2, "SIGINT", true, true, true, "interrupt");
+ AddSignal(3, "SIGQUIT", false, true, true, "quit");
+ AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
+ AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)");
+ AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT");
+ AddSignal(7, "SIGEMT", false, true, true, "emulation trap");
+ AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
+ AddSignal(9, "SIGKILL", false, true, true, "kill");
+ AddSignal(10, "SIGBUS", false, true, true, "bus error");
+ AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
+ AddSignal(12, "SIGSYS", false, true, true, "invalid system call");
+ AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed");
+ AddSignal(14, "SIGALRM", false, false, false, "alarm");
+ AddSignal(15, "SIGTERM", false, true, true, "termination requested");
+ AddSignal(16, "SIGURG", false, true, true, "urgent data on socket");
+ AddSignal(17, "SIGSTOP", true, true, true, "process stop");
+ AddSignal(18, "SIGTSTP", false, true, true, "tty stop");
+ AddSignal(19, "SIGCONT", false, false, true, "process continue");
+ AddSignal(20, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD");
+ AddSignal(21, "SIGTTIN", false, true, true, "background tty read");
+ AddSignal(22, "SIGTTOU", false, true, true, "background tty write");
+ AddSignal(23, "SIGIO", false, true, true, "input/output ready/Pollable event");
+ AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded");
+ AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded");
+ AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm");
+ AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm");
+ AddSignal(28, "SIGWINCH", false, true, true, "window size changes");
+ AddSignal(29, "SIGLOST", false, true, true, "resource lost");
+ AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1");
+ AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2");
+ AddSignal(32, "SIGPWR", false, true, true, "power failure");
+ AddSignal(33, "SIGPOLL", false, true, true, "pollable event");
+ AddSignal(34, "SIGWIND", false, true, true, "SIGWIND");
+ AddSignal(35, "SIGPHONE", false, true, true, "SIGPHONE");
+ AddSignal(36, "SIGWAITING", false, true, true, "process's LWPs are blocked");
+ AddSignal(37, "SIGLWP", false, true, true, "signal LWP");
+ AddSignal(38, "SIGDANGER", false, true, true, "swap space dangerously low");
+ AddSignal(39, "SIGGRANT", false, true, true, "monitor mode granted");
+ AddSignal(40, "SIGRETRACT", false, true, true, "need to relinquish monitor mode");
+ AddSignal(41, "SIGMSG", false, true, true, "monitor mode data available");
+ AddSignal(42, "SIGSOUND", false, true, true, "sound completed");
+ AddSignal(43, "SIGSAK", false, true, true, "secure attention");
+ AddSignal(44, "SIGPRIO", false, true, true, "SIGPRIO");
+
+ AddSignal(45, "SIG33", false, false, false, "real-time event 33");
+ AddSignal(46, "SIG34", false, false, false, "real-time event 34");
+ AddSignal(47, "SIG35", false, false, false, "real-time event 35");
+ AddSignal(48, "SIG36", false, false, false, "real-time event 36");
+ AddSignal(49, "SIG37", false, false, false, "real-time event 37");
+ AddSignal(50, "SIG38", false, false, false, "real-time event 38");
+ AddSignal(51, "SIG39", false, false, false, "real-time event 39");
+ AddSignal(52, "SIG40", false, false, false, "real-time event 40");
+ AddSignal(53, "SIG41", false, false, false, "real-time event 41");
+ AddSignal(54, "SIG42", false, false, false, "real-time event 42");
+ AddSignal(55, "SIG43", false, false, false, "real-time event 43");
+ AddSignal(56, "SIG44", false, false, false, "real-time event 44");
+ AddSignal(57, "SIG45", false, false, false, "real-time event 45");
+ AddSignal(58, "SIG46", false, false, false, "real-time event 46");
+ AddSignal(59, "SIG47", false, false, false, "real-time event 47");
+ AddSignal(60, "SIG48", false, false, false, "real-time event 48");
+ AddSignal(61, "SIG49", false, false, false, "real-time event 49");
+ AddSignal(62, "SIG50", false, false, false, "real-time event 50");
+ AddSignal(63, "SIG51", false, false, false, "real-time event 51");
+ AddSignal(64, "SIG52", false, false, false, "real-time event 52");
+ AddSignal(65, "SIG53", false, false, false, "real-time event 53");
+ AddSignal(66, "SIG54", false, false, false, "real-time event 54");
+ AddSignal(67, "SIG55", false, false, false, "real-time event 55");
+ AddSignal(68, "SIG56", false, false, false, "real-time event 56");
+ AddSignal(69, "SIG57", false, false, false, "real-time event 57");
+ AddSignal(70, "SIG58", false, false, false, "real-time event 58");
+ AddSignal(71, "SIG59", false, false, false, "real-time event 59");
+ AddSignal(72, "SIG60", false, false, false, "real-time event 60");
+ AddSignal(73, "SIG61", false, false, false, "real-time event 61");
+ AddSignal(74, "SIG62", false, false, false, "real-time event 62");
+ AddSignal(75, "SIG63", false, false, false, "real-time event 63");
+
+ AddSignal(76, "SIGCANCEL", false, true, true, "LWP internal signal");
+
+ AddSignal(77, "SIG32", false, false, false, "real-time event 32");
+ AddSignal(78, "SIG64", false, false, false, "real-time event 64");
+ AddSignal(79, "SIG65", false, false, false, "real-time event 65");
+ AddSignal(80, "SIG66", false, false, false, "real-time event 66");
+ AddSignal(81, "SIG67", false, false, false, "real-time event 67");
+ AddSignal(82, "SIG68", false, false, false, "real-time event 68");
+ AddSignal(83, "SIG69", false, false, false, "real-time event 69");
+ AddSignal(84, "SIG70", false, false, false, "real-time event 70");
+ AddSignal(85, "SIG71", false, false, false, "real-time event 71");
+ AddSignal(86, "SIG72", false, false, false, "real-time event 72");
+ AddSignal(87, "SIG73", false, false, false, "real-time event 73");
+ AddSignal(88, "SIG74", false, false, false, "real-time event 74");
+ AddSignal(89, "SIG75", false, false, false, "real-time event 75");
+ AddSignal(90, "SIG76", false, false, false, "real-time event 76");
+ AddSignal(91, "SIG77", false, false, false, "real-time event 77");
+ AddSignal(92, "SIG78", false, false, false, "real-time event 78");
+ AddSignal(93, "SIG79", false, false, false, "real-time event 79");
+ AddSignal(94, "SIG80", false, false, false, "real-time event 80");
+ AddSignal(95, "SIG81", false, false, false, "real-time event 81");
+ AddSignal(96, "SIG82", false, false, false, "real-time event 82");
+ AddSignal(97, "SIG83", false, false, false, "real-time event 83");
+ AddSignal(98, "SIG84", false, false, false, "real-time event 84");
+ AddSignal(99, "SIG85", false, false, false, "real-time event 85");
+ AddSignal(100, "SIG86", false, false, false, "real-time event 86");
+ AddSignal(101, "SIG87", false, false, false, "real-time event 87");
+ AddSignal(102, "SIG88", false, false, false, "real-time event 88");
+ AddSignal(103, "SIG89", false, false, false, "real-time event 89");
+ AddSignal(104, "SIG90", false, false, false, "real-time event 90");
+ AddSignal(105, "SIG91", false, false, false, "real-time event 91");
+ AddSignal(106, "SIG92", false, false, false, "real-time event 92");
+ AddSignal(107, "SIG93", false, false, false, "real-time event 93");
+ AddSignal(108, "SIG94", false, false, false, "real-time event 94");
+ AddSignal(109, "SIG95", false, false, false, "real-time event 95");
+ AddSignal(110, "SIG96", false, false, false, "real-time event 96");
+ AddSignal(111, "SIG97", false, false, false, "real-time event 97");
+ AddSignal(112, "SIG98", false, false, false, "real-time event 98");
+ AddSignal(113, "SIG99", false, false, false, "real-time event 99");
+ AddSignal(114, "SIG100", false, false, false, "real-time event 100");
+ AddSignal(115, "SIG101", false, false, false, "real-time event 101");
+ AddSignal(116, "SIG102", false, false, false, "real-time event 102");
+ AddSignal(117, "SIG103", false, false, false, "real-time event 103");
+ AddSignal(118, "SIG104", false, false, false, "real-time event 104");
+ AddSignal(119, "SIG105", false, false, false, "real-time event 105");
+ AddSignal(120, "SIG106", false, false, false, "real-time event 106");
+ AddSignal(121, "SIG107", false, false, false, "real-time event 107");
+ AddSignal(122, "SIG108", false, false, false, "real-time event 108");
+ AddSignal(123, "SIG109", false, false, false, "real-time event 109");
+ AddSignal(124, "SIG110", false, false, false, "real-time event 110");
+ AddSignal(125, "SIG111", false, false, false, "real-time event 111");
+ AddSignal(126, "SIG112", false, false, false, "real-time event 112");
+ AddSignal(127, "SIG113", false, false, false, "real-time event 113");
+ AddSignal(128, "SIG114", false, false, false, "real-time event 114");
+ AddSignal(129, "SIG115", false, false, false, "real-time event 115");
+ AddSignal(130, "SIG116", false, false, false, "real-time event 116");
+ AddSignal(131, "SIG117", false, false, false, "real-time event 117");
+ AddSignal(132, "SIG118", false, false, false, "real-time event 118");
+ AddSignal(133, "SIG119", false, false, false, "real-time event 119");
+ AddSignal(134, "SIG120", false, false, false, "real-time event 120");
+ AddSignal(135, "SIG121", false, false, false, "real-time event 121");
+ AddSignal(136, "SIG122", false, false, false, "real-time event 122");
+ AddSignal(137, "SIG123", false, false, false, "real-time event 123");
+ AddSignal(138, "SIG124", false, false, false, "real-time event 124");
+ AddSignal(139, "SIG125", false, false, false, "real-time event 125");
+ AddSignal(140, "SIG126", false, false, false, "real-time event 126");
+ AddSignal(141, "SIG127", false, false, false, "real-time event 127");
+
+ AddSignal(142, "SIGINFO", false, true, true, "information request");
+ AddSignal(143, "unknown", false, true, true, "unknown signal");
+
+ AddSignal(145, "EXC_BAD_ACCESS", false, true, true, "could not access memory");
+ AddSignal(146, "EXC_BAD_INSTRUCTION", false, true, true, "illegal instruction/operand");
+ AddSignal(147, "EXC_ARITHMETIC", false, true, true, "arithmetic exception");
+ AddSignal(148, "EXC_EMULATION", false, true, true, "emulation instruction");
+ AddSignal(149, "EXC_SOFTWARE", false, true, true, "software generated exception");
+ AddSignal(150, "EXC_BREAKPOINT", false, true, true, "breakpoint");
+
+ AddSignal(151, "SIGLIBRT", false, true, true, "librt internal signal");
+
+ // clang-format on
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h
new file mode 100644
index 000000000000..4c260b94eba8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h
@@ -0,0 +1,30 @@
+//===-- GDBRemoteSignals.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_GDBREMOTESIGNALS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_GDBREMOTESIGNALS_H
+
+#include "lldb/Target/UnixSignals.h"
+
+namespace lldb_private {
+
+/// Initially carries signals defined by the GDB Remote Serial Protocol.
+/// Can be filled with platform's signals through PlatformRemoteGDBServer.
+class GDBRemoteSignals : public UnixSignals {
+public:
+ GDBRemoteSignals();
+
+ GDBRemoteSignals(const lldb::UnixSignalsSP &rhs);
+
+private:
+ void Reset() override;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_GDBREMOTESIGNALS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
new file mode 100644
index 000000000000..bc06757c806a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
@@ -0,0 +1,85 @@
+//===-- HistoryThread.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+
+#include "Plugins/Process/Utility/HistoryThread.h"
+
+#include "Plugins/Process/Utility/HistoryUnwind.h"
+#include "Plugins/Process/Utility/RegisterContextHistory.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrameList.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Constructor
+
+HistoryThread::HistoryThread(lldb_private::Process &process, lldb::tid_t tid,
+ std::vector<lldb::addr_t> pcs,
+ bool pcs_are_call_addresses)
+ : Thread(process, tid, true), m_framelist_mutex(), m_framelist(),
+ m_pcs(pcs), m_extended_unwind_token(LLDB_INVALID_ADDRESS), m_queue_name(),
+ m_thread_name(), m_originating_unique_thread_id(tid),
+ m_queue_id(LLDB_INVALID_QUEUE_ID) {
+ m_unwinder_up =
+ std::make_unique<HistoryUnwind>(*this, pcs, pcs_are_call_addresses);
+ Log *log = GetLog(LLDBLog::Object);
+ LLDB_LOGF(log, "%p HistoryThread::HistoryThread", static_cast<void *>(this));
+}
+
+// Destructor
+
+HistoryThread::~HistoryThread() {
+ Log *log = GetLog(LLDBLog::Object);
+ LLDB_LOGF(log, "%p HistoryThread::~HistoryThread (tid=0x%" PRIx64 ")",
+ static_cast<void *>(this), GetID());
+ DestroyThread();
+}
+
+lldb::RegisterContextSP HistoryThread::GetRegisterContext() {
+ RegisterContextSP rctx;
+ if (m_pcs.size() > 0) {
+ rctx = std::make_shared<RegisterContextHistory>(
+ *this, 0, GetProcess()->GetAddressByteSize(), m_pcs[0]);
+ }
+ return rctx;
+}
+
+lldb::RegisterContextSP
+HistoryThread::CreateRegisterContextForFrame(StackFrame *frame) {
+ return m_unwinder_up->CreateRegisterContextForFrame(frame);
+}
+
+lldb::StackFrameListSP HistoryThread::GetStackFrameList() {
+ // FIXME do not throw away the lock after we acquire it..
+ std::unique_lock<std::mutex> lock(m_framelist_mutex);
+ lock.unlock();
+ if (m_framelist.get() == nullptr) {
+ m_framelist =
+ std::make_shared<StackFrameList>(*this, StackFrameListSP(), true);
+ }
+
+ return m_framelist;
+}
+
+uint32_t HistoryThread::GetExtendedBacktraceOriginatingIndexID() {
+ if (m_originating_unique_thread_id != LLDB_INVALID_THREAD_ID) {
+ if (GetProcess()->HasAssignedIndexIDToThread(
+ m_originating_unique_thread_id)) {
+ return GetProcess()->AssignIndexIDToThread(
+ m_originating_unique_thread_id);
+ }
+ }
+ return LLDB_INVALID_THREAD_ID;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryThread.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryThread.h
new file mode 100644
index 000000000000..a66e0f2d4207
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryThread.h
@@ -0,0 +1,92 @@
+//===-- HistoryThread.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYTHREAD_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYTHREAD_H
+
+#include <mutex>
+
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/StackFrameList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Broadcaster.h"
+#include "lldb/Utility/Event.h"
+#include "lldb/Utility/UserID.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+/// \class HistoryThread HistoryThread.h "HistoryThread.h"
+/// A thread object representing a backtrace from a previous point in the
+/// process execution
+///
+/// This subclass of Thread is used to provide a backtrace from earlier in
+/// process execution. It is given a backtrace list of pc addresses and it
+/// will create stack frames for them.
+
+class HistoryThread : public lldb_private::Thread {
+public:
+ HistoryThread(lldb_private::Process &process, lldb::tid_t tid,
+ std::vector<lldb::addr_t> pcs,
+ bool pcs_are_call_addresses = false);
+
+ ~HistoryThread() override;
+
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(StackFrame *frame) override;
+
+ void RefreshStateAfterStop() override {}
+
+ bool CalculateStopInfo() override { return false; }
+
+ void SetExtendedBacktraceToken(uint64_t token) override {
+ m_extended_unwind_token = token;
+ }
+
+ uint64_t GetExtendedBacktraceToken() override {
+ return m_extended_unwind_token;
+ }
+
+ const char *GetQueueName() override { return m_queue_name.c_str(); }
+
+ void SetQueueName(const char *name) override { m_queue_name = name; }
+
+ lldb::queue_id_t GetQueueID() override { return m_queue_id; }
+
+ void SetQueueID(lldb::queue_id_t queue) override { m_queue_id = queue; }
+
+ const char *GetThreadName() { return m_thread_name.c_str(); }
+
+ uint32_t GetExtendedBacktraceOriginatingIndexID() override;
+
+ void SetThreadName(const char *name) { m_thread_name = name; }
+
+ const char *GetName() override { return m_thread_name.c_str(); }
+
+ void SetName(const char *name) override { m_thread_name = name; }
+
+protected:
+ virtual lldb::StackFrameListSP GetStackFrameList();
+
+ mutable std::mutex m_framelist_mutex;
+ lldb::StackFrameListSP m_framelist;
+ std::vector<lldb::addr_t> m_pcs;
+
+ uint64_t m_extended_unwind_token;
+ std::string m_queue_name;
+ std::string m_thread_name;
+ lldb::tid_t m_originating_unique_thread_id;
+ lldb::queue_id_t m_queue_id;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYTHREAD_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp
new file mode 100644
index 000000000000..7749dc6f5d51
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp
@@ -0,0 +1,73 @@
+//===-- HistoryUnwind.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+
+#include "Plugins/Process/Utility/HistoryUnwind.h"
+#include "Plugins/Process/Utility/RegisterContextHistory.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Constructor
+
+HistoryUnwind::HistoryUnwind(Thread &thread, std::vector<lldb::addr_t> pcs,
+ bool pcs_are_call_addresses)
+ : Unwind(thread), m_pcs(pcs),
+ m_pcs_are_call_addresses(pcs_are_call_addresses) {}
+
+// Destructor
+
+HistoryUnwind::~HistoryUnwind() = default;
+
+void HistoryUnwind::DoClear() {
+ std::lock_guard<std::recursive_mutex> guard(m_unwind_mutex);
+ m_pcs.clear();
+}
+
+lldb::RegisterContextSP
+HistoryUnwind::DoCreateRegisterContextForFrame(StackFrame *frame) {
+ RegisterContextSP rctx;
+ if (frame) {
+ addr_t pc = frame->GetFrameCodeAddress().GetLoadAddress(
+ &frame->GetThread()->GetProcess()->GetTarget());
+ if (pc != LLDB_INVALID_ADDRESS) {
+ rctx = std::make_shared<RegisterContextHistory>(
+ *frame->GetThread().get(), frame->GetConcreteFrameIndex(),
+ frame->GetThread()->GetProcess()->GetAddressByteSize(), pc);
+ }
+ }
+ return rctx;
+}
+
+bool HistoryUnwind::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
+ lldb::addr_t &pc,
+ bool &behaves_like_zeroth_frame) {
+ // FIXME do not throw away the lock after we acquire it..
+ std::unique_lock<std::recursive_mutex> guard(m_unwind_mutex);
+ guard.unlock();
+ if (frame_idx < m_pcs.size()) {
+ cfa = frame_idx;
+ pc = m_pcs[frame_idx];
+ if (m_pcs_are_call_addresses)
+ behaves_like_zeroth_frame = true;
+ else
+ behaves_like_zeroth_frame = (frame_idx == 0);
+ return true;
+ }
+ return false;
+}
+
+uint32_t HistoryUnwind::DoGetFrameCount() { return m_pcs.size(); }
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryUnwind.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryUnwind.h
new file mode 100644
index 000000000000..cb72b5d0a176
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/HistoryUnwind.h
@@ -0,0 +1,46 @@
+//===-- HistoryUnwind.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYUNWIND_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYUNWIND_H
+
+#include <vector>
+
+#include "lldb/Target/Unwind.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class HistoryUnwind : public lldb_private::Unwind {
+public:
+ HistoryUnwind(Thread &thread, std::vector<lldb::addr_t> pcs,
+ bool pcs_are_call_addresses = false);
+
+ ~HistoryUnwind() override;
+
+protected:
+ void DoClear() override;
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame(StackFrame *frame) override;
+
+ bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
+ lldb::addr_t &pc,
+ bool &behaves_like_zeroth_frame) override;
+ uint32_t DoGetFrameCount() override;
+
+private:
+ std::vector<lldb::addr_t> m_pcs;
+ /// This boolean indicates that the PCs in the non-0 frames are call
+ /// addresses and not return addresses.
+ bool m_pcs_are_call_addresses;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_HISTORYUNWIND_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
new file mode 100644
index 000000000000..32c71d87c7f5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -0,0 +1,190 @@
+//===-- InferiorCallPOSIX.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "InferiorCallPOSIX.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/DiagnosticManager.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+
+#if LLDB_ENABLE_POSIX
+#include <sys/mman.h>
+#else
+// define them
+#define PROT_NONE 0
+#define PROT_READ 1
+#define PROT_WRITE 2
+#define PROT_EXEC 4
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
+ addr_t addr, addr_t length, unsigned prot,
+ unsigned flags, addr_t fd, addr_t offset) {
+ Thread *thread =
+ process->GetThreadList().GetExpressionExecutionThread().get();
+ if (thread == nullptr)
+ return false;
+
+ ModuleFunctionSearchOptions function_options;
+ function_options.include_symbols = true;
+ function_options.include_inlines = false;
+
+ SymbolContextList sc_list;
+ process->GetTarget().GetImages().FindFunctions(
+ ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list);
+ const uint32_t count = sc_list.GetSize();
+ if (count > 0) {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc)) {
+ const uint32_t range_scope =
+ eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ EvaluateExpressionOptions options;
+ options.SetStopOthers(true);
+ options.SetUnwindOnError(true);
+ options.SetIgnoreBreakpoints(true);
+ options.SetTryAllThreads(true);
+ options.SetDebug(false);
+ options.SetTimeout(process->GetUtilityExpressionTimeout());
+ options.SetTrapExceptions(false);
+
+ addr_t prot_arg;
+ if (prot == eMmapProtNone)
+ prot_arg = PROT_NONE;
+ else {
+ prot_arg = 0;
+ if (prot & eMmapProtExec)
+ prot_arg |= PROT_EXEC;
+ if (prot & eMmapProtRead)
+ prot_arg |= PROT_READ;
+ if (prot & eMmapProtWrite)
+ prot_arg |= PROT_WRITE;
+ }
+
+ AddressRange mmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range,
+ mmap_range)) {
+ auto type_system_or_err =
+ process->GetTarget().GetScratchTypeSystemForLanguage(
+ eLanguageTypeC);
+ if (!type_system_or_err) {
+ llvm::consumeError(type_system_or_err.takeError());
+ return false;
+ }
+ auto ts = *type_system_or_err;
+ if (!ts)
+ return false;
+ CompilerType void_ptr_type =
+ ts->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType();
+ const ArchSpec arch = process->GetTarget().GetArchitecture();
+ MmapArgList args =
+ process->GetTarget().GetPlatform()->GetMmapArgumentList(
+ arch, addr, length, prot_arg, flags, fd, offset);
+ lldb::ThreadPlanSP call_plan_sp(
+ new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(),
+ void_ptr_type, args, options));
+ if (call_plan_sp) {
+ DiagnosticManager diagnostics;
+
+ StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+ if (frame) {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext(exe_ctx);
+ ExpressionResults result = process->RunThreadPlan(
+ exe_ctx, call_plan_sp, options, diagnostics);
+ if (result == eExpressionCompleted) {
+
+ allocated_addr =
+ call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(
+ LLDB_INVALID_ADDRESS);
+ if (process->GetAddressByteSize() == 4) {
+ if (allocated_addr == UINT32_MAX)
+ return false;
+ } else if (process->GetAddressByteSize() == 8) {
+ if (allocated_addr == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
+ addr_t length) {
+ Thread *thread =
+ process->GetThreadList().GetExpressionExecutionThread().get();
+ if (thread == nullptr)
+ return false;
+
+ ModuleFunctionSearchOptions function_options;
+ function_options.include_symbols = true;
+ function_options.include_inlines = false;
+
+ SymbolContextList sc_list;
+ process->GetTarget().GetImages().FindFunctions(
+ ConstString("munmap"), eFunctionNameTypeFull, function_options, sc_list);
+ const uint32_t count = sc_list.GetSize();
+ if (count > 0) {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc)) {
+ const uint32_t range_scope =
+ eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ EvaluateExpressionOptions options;
+ options.SetStopOthers(true);
+ options.SetUnwindOnError(true);
+ options.SetIgnoreBreakpoints(true);
+ options.SetTryAllThreads(true);
+ options.SetDebug(false);
+ options.SetTimeout(process->GetUtilityExpressionTimeout());
+ options.SetTrapExceptions(false);
+
+ AddressRange munmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range,
+ munmap_range)) {
+ lldb::addr_t args[] = {addr, length};
+ lldb::ThreadPlanSP call_plan_sp(
+ new ThreadPlanCallFunction(*thread, munmap_range.GetBaseAddress(),
+ CompilerType(), args, options));
+ if (call_plan_sp) {
+ DiagnosticManager diagnostics;
+
+ StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+ if (frame) {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext(exe_ctx);
+ ExpressionResults result = process->RunThreadPlan(
+ exe_ctx, call_plan_sp, options, diagnostics);
+ if (result == eExpressionCompleted) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h
new file mode 100644
index 000000000000..3623e10194f9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h
@@ -0,0 +1,35 @@
+//===-- InferiorCallPOSIX.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INFERIORCALLPOSIX_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INFERIORCALLPOSIX_H
+
+// Inferior execution of POSIX functions.
+
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+
+class Process;
+
+enum MmapProt {
+ eMmapProtNone = 0,
+ eMmapProtExec = 1,
+ eMmapProtRead = 2,
+ eMmapProtWrite = 4
+};
+
+bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr,
+ lldb::addr_t addr, lldb::addr_t length, unsigned prot,
+ unsigned flags, lldb::addr_t fd, lldb::addr_t offset);
+
+bool InferiorCallMunmap(Process *proc, lldb::addr_t addr, lldb::addr_t length);
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INFERIORCALLPOSIX_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InstructionUtils.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InstructionUtils.h
new file mode 100644
index 000000000000..55b89440700b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/InstructionUtils.h
@@ -0,0 +1,116 @@
+//===-- InstructionUtils.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INSTRUCTIONUTILS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INSTRUCTIONUTILS_H
+
+#include <cassert>
+#include <cstdint>
+
+// Common utilities for manipulating instruction bit fields.
+
+namespace lldb_private {
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 64-bit unsigned value.
+static inline uint64_t Bits64(const uint64_t bits, const uint32_t msbit,
+ const uint32_t lsbit) {
+ assert(msbit < 64 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1ull << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value.
+static inline uint32_t Bits32(const uint32_t bits, const uint32_t msbit,
+ const uint32_t lsbit) {
+ assert(msbit < 32 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit value from the 'bit' position of a 32-bit unsigned value.
+static inline uint32_t Bit32(const uint32_t bits, const uint32_t bit) {
+ return (bits >> bit) & 1u;
+}
+
+static inline uint64_t Bit64(const uint64_t bits, const uint32_t bit) {
+ return (bits >> bit) & 1ull;
+}
+
+// Set the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value to 'val'.
+static inline void SetBits32(uint32_t &bits, const uint32_t msbit,
+ const uint32_t lsbit, const uint32_t val) {
+ assert(msbit < 32 && lsbit < 32 && msbit >= lsbit);
+ uint32_t mask = ((1u << (msbit - lsbit + 1)) - 1);
+ bits &= ~(mask << lsbit);
+ bits |= (val & mask) << lsbit;
+}
+
+// Set the 'bit' position of a 32-bit unsigned value to 'val'.
+static inline void SetBit32(uint32_t &bits, const uint32_t bit,
+ const uint32_t val) {
+ SetBits32(bits, bit, bit, val);
+}
+
+// Rotate a 32-bit unsigned value right by the specified amount.
+static inline uint32_t Rotr32(uint32_t bits, uint32_t amt) {
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits >> amt) | (bits << ((32 - amt) & 31));
+}
+
+// Rotate a 32-bit unsigned value left by the specified amount.
+static inline uint32_t Rotl32(uint32_t bits, uint32_t amt) {
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits << amt) | (bits >> ((32 - amt) & 31));
+}
+
+// Create a mask that starts at bit zero and includes "bit"
+static inline uint64_t MaskUpToBit(const uint64_t bit) {
+ if (bit >= 63)
+ return -1ll;
+ return (1ull << (bit + 1ull)) - 1ull;
+}
+
+// Return an integer result equal to the number of bits of x that are ones.
+static inline uint32_t BitCount(uint64_t x) {
+ // c accumulates the total bits set in x
+ uint32_t c;
+ for (c = 0; x; ++c) {
+ x &= x - 1; // clear the least significant bit set
+ }
+ return c;
+}
+
+static inline bool BitIsSet(const uint64_t value, const uint64_t bit) {
+ return (value & (1ull << bit)) != 0;
+}
+
+static inline bool BitIsClear(const uint64_t value, const uint64_t bit) {
+ return (value & (1ull << bit)) == 0;
+}
+
+static inline uint64_t UnsignedBits(const uint64_t value, const uint64_t msbit,
+ const uint64_t lsbit) {
+ uint64_t result = value >> lsbit;
+ result &= MaskUpToBit(msbit - lsbit);
+ return result;
+}
+
+static inline int64_t SignedBits(const uint64_t value, const uint64_t msbit,
+ const uint64_t lsbit) {
+ uint64_t result = UnsignedBits(value, msbit, lsbit);
+ if (BitIsSet(value, msbit)) {
+ // Sign extend
+ result |= ~MaskUpToBit(msbit - lsbit);
+ }
+ return result;
+}
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_INSTRUCTIONUTILS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h
new file mode 100644
index 000000000000..8b5393ca1888
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h
@@ -0,0 +1,293 @@
+//===-- LinuxPTraceDefines_arm64sve.h ------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H
+
+#include <cstdint>
+
+namespace lldb_private {
+namespace sve {
+
+/*
+ * The SVE architecture leaves space for future expansion of the
+ * vector length beyond its initial architectural limit of 2048 bits
+ * (16 quadwords).
+ *
+ * See <Linux kernel source tree>/Documentation/arm64/sve.rst for a description
+ * of the vl/vq terminology.
+ */
+
+const uint16_t vq_bytes = 16; /* number of bytes per quadword */
+
+const uint16_t vq_min = 1;
+const uint16_t vq_max = 512;
+
+const uint16_t vl_min = vq_min * vq_bytes;
+const uint16_t vl_max = vq_max * vq_bytes;
+
+const uint16_t num_of_zregs = 32;
+const uint16_t num_of_pregs = 16;
+
+inline uint16_t vl_valid(uint16_t vl) {
+ return (vl % vq_bytes == 0 && vl >= vl_min && vl <= vl_max);
+}
+
+inline uint16_t vq_from_vl(uint16_t vl) { return vl / vq_bytes; }
+inline uint16_t vl_from_vq(uint16_t vq) { return vq * vq_bytes; }
+
+/* A new signal frame record sve_context encodes the SVE Registers on signal
+ * delivery. sve_context struct definition may be included in asm/sigcontext.h.
+ * We define sve_context_size which will be used by LLDB sve helper functions.
+ * More information on sve_context can be found in Linux kernel source tree at
+ * Documentation/arm64/sve.rst.
+ */
+
+const uint16_t sve_context_size = 16;
+
+/*
+ * If the SVE registers are currently live for the thread at signal delivery,
+ * sve_context.head.size >=
+ * SigContextSize(vq_from_vl(sve_context.vl))
+ * and the register data may be accessed using the Sig*() functions.
+ *
+ * If sve_context.head.size <
+ * SigContextSize(vq_from_vl(sve_context.vl)),
+ * the SVE registers were not live for the thread and no register data
+ * is included: in this case, the Sig*() functions should not be
+ * used except for this check.
+ *
+ * The same convention applies when returning from a signal: a caller
+ * will need to remove or resize the sve_context block if it wants to
+ * make the SVE registers live when they were previously non-live or
+ * vice-versa. This may require the caller to allocate fresh
+ * memory and/or move other context blocks in the signal frame.
+ *
+ * Changing the vector length during signal return is not permitted:
+ * sve_context.vl must equal the thread's current vector length when
+ * doing a sigreturn.
+ *
+ *
+ * Note: for all these functions, the "vq" argument denotes the SVE
+ * vector length in quadwords (i.e., units of 128 bits).
+ *
+ * The correct way to obtain vq is to use vq_from_vl(vl). The
+ * result is valid if and only if vl_valid(vl) is true. This is
+ * guaranteed for a struct sve_context written by the kernel.
+ *
+ *
+ * Additional functions describe the contents and layout of the payload.
+ * For each, Sig*Offset(args) is the start offset relative to
+ * the start of struct sve_context, and Sig*Size(args) is the
+ * size in bytes:
+ *
+ * x type description
+ * - ---- -----------
+ * REGS the entire SVE context
+ *
+ * ZREGS __uint128_t[num_of_zregs][vq] all Z-registers
+ * ZREG __uint128_t[vq] individual Z-register Zn
+ *
+ * PREGS uint16_t[num_of_pregs][vq] all P-registers
+ * PREG uint16_t[vq] individual P-register Pn
+ *
+ * FFR uint16_t[vq] first-fault status register
+ *
+ * Additional data might be appended in the future.
+ */
+
+inline uint16_t SigZRegSize(uint16_t vq) { return vq * vq_bytes; }
+inline uint16_t SigPRegSize(uint16_t vq) { return vq * vq_bytes / 8; }
+inline uint16_t SigFFRSize(uint16_t vq) { return SigPRegSize(vq); }
+
+inline uint32_t SigRegsOffset() {
+ return (sve_context_size + vq_bytes - 1) / vq_bytes * vq_bytes;
+}
+
+inline uint32_t SigZRegsOffset() { return SigRegsOffset(); }
+
+inline uint32_t SigZRegOffset(uint16_t vq, uint16_t n) {
+ return SigRegsOffset() + SigZRegSize(vq) * n;
+}
+
+inline uint32_t SigZRegsSize(uint16_t vq) {
+ return SigZRegOffset(vq, num_of_zregs) - SigRegsOffset();
+}
+
+inline uint32_t SigPRegsOffset(uint16_t vq) {
+ return SigRegsOffset() + SigZRegsSize(vq);
+}
+
+inline uint32_t SigPRegOffset(uint16_t vq, uint16_t n) {
+ return SigPRegsOffset(vq) + SigPRegSize(vq) * n;
+}
+
+inline uint32_t SigpRegsSize(uint16_t vq) {
+ return SigPRegOffset(vq, num_of_pregs) - SigPRegsOffset(vq);
+}
+
+inline uint32_t SigFFROffset(uint16_t vq) {
+ return SigPRegsOffset(vq) + SigpRegsSize(vq);
+}
+
+inline uint32_t SigRegsSize(uint16_t vq) {
+ return SigFFROffset(vq) + SigFFRSize(vq) - SigRegsOffset();
+}
+
+inline uint32_t SVESigContextSize(uint16_t vq) {
+ return SigRegsOffset() + SigRegsSize(vq);
+}
+
+struct user_sve_header {
+ uint32_t size; /* total meaningful regset content in bytes */
+ uint32_t max_size; /* maxmium possible size for this thread */
+ uint16_t vl; /* current vector length */
+ uint16_t max_vl; /* maximum possible vector length */
+ uint16_t flags;
+ uint16_t reserved;
+};
+
+using user_za_header = user_sve_header;
+
+/* Definitions for user_sve_header.flags: */
+const uint16_t ptrace_regs_mask = 1 << 0;
+const uint16_t ptrace_regs_fpsimd = 0;
+const uint16_t ptrace_regs_sve = ptrace_regs_mask;
+
+/*
+ * The remainder of the SVE state follows struct user_sve_header. The
+ * total size of the SVE state (including header) depends on the
+ * metadata in the header: PTraceSize(vq, flags) gives the total size
+ * of the state in bytes, including the header.
+ *
+ * Refer to <asm/sigcontext.h> for details of how to pass the correct
+ * "vq" argument to these macros.
+ */
+
+/* Offset from the start of struct user_sve_header to the register data */
+inline uint16_t PTraceRegsOffset() {
+ return (sizeof(struct user_sve_header) + vq_bytes - 1) / vq_bytes * vq_bytes;
+}
+
+/*
+ * The register data content and layout depends on the value of the
+ * flags field.
+ */
+
+/*
+ * (flags & ptrace_regs_mask) == ptrace_regs_fpsimd case:
+ *
+ * The payload starts at offset PTraceFPSIMDOffset, and is of type
+ * struct user_fpsimd_state. Additional data might be appended in the
+ * future: use PTraceFPSIMDSize(vq, flags) to compute the total size.
+ * PTraceFPSIMDSize(vq, flags) will never be less than
+ * sizeof(struct user_fpsimd_state).
+ */
+
+const uint32_t ptrace_fpsimd_offset = PTraceRegsOffset();
+
+/* Return size of struct user_fpsimd_state from asm/ptrace.h */
+inline uint32_t PTraceFPSIMDSize(uint16_t vq, uint16_t flags) { return 528; }
+
+/*
+ * (flags & ptrace_regs_mask) == ptrace_regs_sve case:
+ *
+ * The payload starts at offset PTraceSVEOffset, and is of size
+ * PTraceSVESize(vq, flags).
+ *
+ * Additional functions describe the contents and layout of the payload.
+ * For each, PTrace*X*Offset(args) is the start offset relative to
+ * the start of struct user_sve_header, and PTrace*X*Size(args) is
+ * the size in bytes:
+ *
+ * x type description
+ * - ---- -----------
+ * ZREGS \
+ * ZREG |
+ * PREGS | refer to <asm/sigcontext.h>
+ * PREG |
+ * FFR /
+ *
+ * FPSR uint32_t FPSR
+ * FPCR uint32_t FPCR
+ *
+ * Additional data might be appended in the future.
+ */
+
+inline uint32_t PTraceZRegSize(uint16_t vq) { return SigZRegSize(vq); }
+
+inline uint32_t PTracePRegSize(uint16_t vq) { return SigPRegSize(vq); }
+
+inline uint32_t PTraceFFRSize(uint16_t vq) { return SigFFRSize(vq); }
+
+const uint32_t fpsr_size = sizeof(uint32_t);
+const uint32_t fpcr_size = sizeof(uint32_t);
+
+inline uint32_t SigToPTrace(uint32_t offset) {
+ return offset - SigRegsOffset() + PTraceRegsOffset();
+}
+
+const uint32_t ptrace_sve_offset = PTraceRegsOffset();
+
+inline uint32_t PTraceZRegsOffset(uint16_t vq) {
+ return SigToPTrace(SigZRegsOffset());
+}
+
+inline uint32_t PTraceZRegOffset(uint16_t vq, uint16_t n) {
+ return SigToPTrace(SigZRegOffset(vq, n));
+}
+
+inline uint32_t PTraceZRegsSize(uint16_t vq) {
+ return PTraceZRegOffset(vq, num_of_zregs) - SigToPTrace(SigRegsOffset());
+}
+
+inline uint32_t PTracePRegsOffset(uint16_t vq) {
+ return SigToPTrace(SigPRegsOffset(vq));
+}
+
+inline uint32_t PTracePRegOffset(uint16_t vq, uint16_t n) {
+ return SigToPTrace(SigPRegOffset(vq, n));
+}
+
+inline uint32_t PTracePRegsSize(uint16_t vq) {
+ return PTracePRegOffset(vq, num_of_pregs) - PTracePRegsOffset(vq);
+}
+
+inline uint32_t PTraceFFROffset(uint16_t vq) {
+ return SigToPTrace(SigFFROffset(vq));
+}
+
+inline uint32_t PTraceFPSROffset(uint16_t vq) {
+ return (PTraceFFROffset(vq) + PTraceFFRSize(vq) + (vq_bytes - 1)) / vq_bytes *
+ vq_bytes;
+}
+
+inline uint32_t PTraceFPCROffset(uint16_t vq) {
+ return PTraceFPSROffset(vq) + fpsr_size;
+}
+
+/*
+ * Any future extension appended after FPCR must be aligned to the next
+ * 128-bit boundary.
+ */
+
+inline uint32_t PTraceSVESize(uint16_t vq, uint16_t flags) {
+ return (PTraceFPCROffset(vq) + fpcr_size - ptrace_sve_offset + vq_bytes - 1) /
+ vq_bytes * vq_bytes;
+}
+
+inline uint32_t PTraceSize(uint16_t vq, uint16_t flags) {
+ return (flags & ptrace_regs_mask) == ptrace_regs_sve
+ ? ptrace_sve_offset + PTraceSVESize(vq, flags)
+ : ptrace_fpsimd_offset + PTraceFPSIMDSize(vq, flags);
+}
+
+} // namespace SVE
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
new file mode 100644
index 000000000000..fd803c8cabaf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
@@ -0,0 +1,205 @@
+//===-- LinuxProcMaps.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinuxProcMaps.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StringExtractor.h"
+#include "llvm/ADT/StringRef.h"
+#include <optional>
+
+using namespace lldb_private;
+
+enum class MapsKind { Maps, SMaps };
+
+static llvm::Expected<MemoryRegionInfo> ProcMapError(const char *msg,
+ MapsKind kind) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(), msg,
+ kind == MapsKind::Maps ? "maps" : "smaps");
+}
+
+static llvm::Expected<MemoryRegionInfo>
+ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,
+ MapsKind maps_kind) {
+ MemoryRegionInfo region;
+ StringExtractor line_extractor(maps_line);
+
+ // 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 ProcMapError(
+ "malformed /proc/{pid}/%s entry, missing dash between address range",
+ maps_kind);
+
+ // 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 ProcMapError(
+ "malformed /proc/{pid}/%s entry, missing space after range", maps_kind);
+
+ // Save the range.
+ region.GetRange().SetRangeBase(start_address);
+ region.GetRange().SetRangeEnd(end_address);
+
+ // Any memory region in /proc/{pid}/(maps|smaps) is by definition mapped
+ // into the process.
+ region.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
+
+ // Parse out each permission entry.
+ if (line_extractor.GetBytesLeft() < 4)
+ return ProcMapError(
+ "malformed /proc/{pid}/%s entry, missing some portion of "
+ "permissions",
+ maps_kind);
+
+ // Handle read permission.
+ const char read_perm_char = line_extractor.GetChar();
+ if (read_perm_char == 'r')
+ region.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
+ else if (read_perm_char == '-')
+ region.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ else
+ return ProcMapError("unexpected /proc/{pid}/%s read permission char",
+ maps_kind);
+
+ // Handle write permission.
+ const char write_perm_char = line_extractor.GetChar();
+ if (write_perm_char == 'w')
+ region.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
+ else if (write_perm_char == '-')
+ region.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ else
+ return ProcMapError("unexpected /proc/{pid}/%s write permission char",
+ maps_kind);
+
+ // Handle execute permission.
+ const char exec_perm_char = line_extractor.GetChar();
+ if (exec_perm_char == 'x')
+ region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
+ else if (exec_perm_char == '-')
+ region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ else
+ return ProcMapError("unexpected /proc/{pid}/%s exec permission char",
+ maps_kind);
+
+ // Handle sharing status (private/shared).
+ const char sharing_char = line_extractor.GetChar();
+ if (sharing_char == 's')
+ region.SetShared(MemoryRegionInfo::OptionalBool::eYes);
+ else if (sharing_char == 'p')
+ region.SetShared(MemoryRegionInfo::OptionalBool::eNo);
+ else
+ region.SetShared(MemoryRegionInfo::OptionalBool::eDontKnow);
+
+ line_extractor.SkipSpaces(); // Skip the separator
+ line_extractor.GetHexMaxU64(false, 0); // Read the offset
+ line_extractor.GetHexMaxU64(false, 0); // Read the major device number
+ line_extractor.GetChar(); // Read the device id separator
+ line_extractor.GetHexMaxU64(false, 0); // Read the major device number
+ line_extractor.SkipSpaces(); // Skip the separator
+ line_extractor.GetU64(0, 10); // Read the inode number
+
+ line_extractor.SkipSpaces();
+ const char *name = line_extractor.Peek();
+ if (name)
+ region.SetName(name);
+
+ return region;
+}
+
+void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map,
+ LinuxMapCallback const &callback) {
+ llvm::StringRef lines(linux_map);
+ llvm::StringRef line;
+ while (!lines.empty()) {
+ std::tie(line, lines) = lines.split('\n');
+ if (!callback(ParseMemoryRegionInfoFromProcMapsLine(line, MapsKind::Maps)))
+ break;
+ }
+}
+
+void lldb_private::ParseLinuxSMapRegions(llvm::StringRef linux_smap,
+ LinuxMapCallback const &callback) {
+ // Entries in /smaps look like:
+ // 00400000-0048a000 r-xp 00000000 fd:03 960637
+ // Size: 552 kB
+ // Rss: 460 kB
+ // <...>
+ // VmFlags: rd ex mr mw me dw
+ // 00500000-0058a000 rwxp 00000000 fd:03 960637
+ // <...>
+ //
+ // Where the first line is identical to the /maps format
+ // and VmFlags is only printed for kernels >= 3.8.
+
+ llvm::StringRef lines(linux_smap);
+ llvm::StringRef line;
+ std::optional<MemoryRegionInfo> region;
+
+ while (lines.size()) {
+ std::tie(line, lines) = lines.split('\n');
+
+ // A property line looks like:
+ // <word>: <value>
+ // (no spaces on the left hand side)
+ // A header will have a ':' but the LHS will contain spaces
+ llvm::StringRef name;
+ llvm::StringRef value;
+ std::tie(name, value) = line.split(':');
+
+ // If this line is a property line
+ if (!name.contains(' ')) {
+ if (region) {
+ if (name == "VmFlags") {
+ if (value.contains("mt"))
+ region->SetMemoryTagged(MemoryRegionInfo::eYes);
+ else
+ region->SetMemoryTagged(MemoryRegionInfo::eNo);
+ }
+ // Ignore anything else
+ } else {
+ // Orphaned settings line
+ callback(ProcMapError(
+ "Found a property line without a corresponding mapping "
+ "in /proc/{pid}/%s",
+ MapsKind::SMaps));
+ return;
+ }
+ } else {
+ // Must be a new region header
+ if (region) {
+ // Save current region
+ callback(*region);
+ region.reset();
+ }
+
+ // Try to start a new region
+ llvm::Expected<MemoryRegionInfo> new_region =
+ ParseMemoryRegionInfoFromProcMapsLine(line, MapsKind::SMaps);
+ if (new_region) {
+ region = *new_region;
+ } else {
+ // Stop at first invalid region header
+ callback(new_region.takeError());
+ return;
+ }
+ }
+ }
+
+ // Catch last region
+ if (region)
+ callback(*region);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
new file mode 100644
index 000000000000..02f78d55c290
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
@@ -0,0 +1,27 @@
+//===-- LinuxProcMaps.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPROCMAPS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPROCMAPS_H
+
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+namespace lldb_private {
+
+typedef std::function<bool(llvm::Expected<MemoryRegionInfo>)> LinuxMapCallback;
+
+void ParseLinuxMapRegions(llvm::StringRef linux_map,
+ LinuxMapCallback const &callback);
+void ParseLinuxSMapRegions(llvm::StringRef linux_smap,
+ LinuxMapCallback const &callback);
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPROCMAPS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
new file mode 100644
index 000000000000..3f25dbc6abbb
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
@@ -0,0 +1,143 @@
+//===-- LinuxSignals.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinuxSignals.h"
+
+#ifdef __linux__
+#include <csignal>
+
+#ifndef SEGV_BNDERR
+#define SEGV_BNDERR 3
+#endif
+#ifndef SEGV_MTEAERR
+#define SEGV_MTEAERR 8
+#endif
+#ifndef SEGV_MTESERR
+#define SEGV_MTESERR 9
+#endif
+
+#define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \
+ static_assert(signal_name == signal_value, \
+ "Value mismatch for signal number " #signal_name); \
+ static_assert(code_name == code_value, \
+ "Value mismatch for signal code " #code_name); \
+ AddSignalCode(signal_value, code_value, __VA_ARGS__)
+#else
+#define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \
+ AddSignalCode(signal_value, code_value, __VA_ARGS__)
+#endif /* ifdef __linux__ */
+
+using namespace lldb_private;
+
+LinuxSignals::LinuxSignals() : UnixSignals() { Reset(); }
+
+void LinuxSignals::Reset() {
+ m_signals.clear();
+ // clang-format off
+ // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION
+ // ====== ============== ======== ====== ====== ===================================================
+ AddSignal(1, "SIGHUP", false, true, true, "hangup");
+ AddSignal(2, "SIGINT", true, true, true, "interrupt");
+ AddSignal(3, "SIGQUIT", false, true, true, "quit");
+
+ AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLOPC, 1, "illegal opcode");
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLOPN, 2, "illegal operand");
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLADR, 3, "illegal addressing mode");
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLTRP, 4, "illegal trap");
+ ADD_SIGCODE(SIGILL, 4, ILL_PRVOPC, 5, "privileged opcode");
+ ADD_SIGCODE(SIGILL, 4, ILL_PRVREG, 6, "privileged register");
+ ADD_SIGCODE(SIGILL, 4, ILL_COPROC, 7, "coprocessor error");
+ ADD_SIGCODE(SIGILL, 4, ILL_BADSTK, 8, "internal stack error");
+
+ AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)");
+ AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT");
+
+ AddSignal(7, "SIGBUS", false, true, true, "bus error");
+ ADD_SIGCODE(SIGBUS, 7, BUS_ADRALN, 1, "illegal alignment");
+ ADD_SIGCODE(SIGBUS, 7, BUS_ADRERR, 2, "illegal address");
+ ADD_SIGCODE(SIGBUS, 7, BUS_OBJERR, 3, "hardware error");
+
+ AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
+ ADD_SIGCODE(SIGFPE, 8, FPE_INTDIV, 1, "integer divide by zero");
+ ADD_SIGCODE(SIGFPE, 8, FPE_INTOVF, 2, "integer overflow");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTDIV, 3, "floating point divide by zero");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTOVF, 4, "floating point overflow");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTUND, 5, "floating point underflow");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTRES, 6, "floating point inexact result");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTINV, 7, "floating point invalid operation");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTSUB, 8, "subscript out of range");
+
+ AddSignal(9, "SIGKILL", false, true, true, "kill");
+ AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1");
+
+ AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
+ ADD_SIGCODE(SIGSEGV, 11, SEGV_MAPERR, 1, "address not mapped to object", SignalCodePrintOption::Address);
+ ADD_SIGCODE(SIGSEGV, 11, SEGV_ACCERR, 2, "invalid permissions for mapped object", SignalCodePrintOption::Address);
+ ADD_SIGCODE(SIGSEGV, 11, SEGV_BNDERR, 3, "failed address bounds checks", SignalCodePrintOption::Bounds);
+ ADD_SIGCODE(SIGSEGV, 11, SEGV_MTEAERR, 8, "async tag check fault");
+ ADD_SIGCODE(SIGSEGV, 11, SEGV_MTESERR, 9, "sync tag check fault", SignalCodePrintOption::Address);
+ // Some platforms will occasionally send nonstandard spurious SI_KERNEL
+ // codes. One way to get this is via unaligned SIMD loads. Treat it as invalid address.
+ ADD_SIGCODE(SIGSEGV, 11, SI_KERNEL, 0x80, "invalid address", SignalCodePrintOption::Address);
+
+ AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2");
+ AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed");
+ AddSignal(14, "SIGALRM", false, false, false, "alarm");
+ AddSignal(15, "SIGTERM", false, true, true, "termination requested");
+ AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault");
+ AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD");
+ AddSignal(18, "SIGCONT", false, false, true, "process continue");
+ AddSignal(19, "SIGSTOP", true, true, true, "process stop");
+ AddSignal(20, "SIGTSTP", false, true, true, "tty stop");
+ AddSignal(21, "SIGTTIN", false, true, true, "background tty read");
+ AddSignal(22, "SIGTTOU", false, true, true, "background tty write");
+ AddSignal(23, "SIGURG", false, true, true, "urgent data on socket");
+ AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded");
+ AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded");
+ AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm");
+ AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm");
+ AddSignal(28, "SIGWINCH", false, true, true, "window size changes");
+ AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL");
+ AddSignal(30, "SIGPWR", false, true, true, "power failure");
+ AddSignal(31, "SIGSYS", false, true, true, "invalid system call");
+ AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1");
+ AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2");
+ AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0");
+ AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1");
+ AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2");
+ AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3");
+ AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4");
+ AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5");
+ AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6");
+ AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7");
+ AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8");
+ AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9");
+ AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10");
+ AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11");
+ AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12");
+ AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13");
+ AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14");
+ AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15");
+ AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output
+ AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17");
+ AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18");
+ AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19");
+ AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20");
+ AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21");
+ AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22");
+ AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23");
+ AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24");
+ AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25");
+ AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26");
+ AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27");
+ AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28");
+ AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29");
+ AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30");
+ // clang-format on
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.h
new file mode 100644
index 000000000000..32c4744a96d0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/LinuxSignals.h
@@ -0,0 +1,27 @@
+//===-- LinuxSignals.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXSIGNALS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXSIGNALS_H
+
+#include "lldb/Target/UnixSignals.h"
+
+namespace lldb_private {
+
+/// Linux specific set of Unix signals.
+class LinuxSignals : public UnixSignals {
+public:
+ LinuxSignals();
+
+private:
+ void Reset() override;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXSIGNALS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
new file mode 100644
index 000000000000..7e25bc4ea2a2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
@@ -0,0 +1,356 @@
+//===-- MemoryTagManagerAArch64MTE.cpp --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MemoryTagManagerAArch64MTE.h"
+#include "llvm/Support/Error.h"
+#include <assert.h>
+
+using namespace lldb_private;
+
+static const unsigned MTE_START_BIT = 56;
+static const unsigned MTE_TAG_MAX = 0xf;
+static const unsigned MTE_GRANULE_SIZE = 16;
+
+lldb::addr_t
+MemoryTagManagerAArch64MTE::GetLogicalTag(lldb::addr_t addr) const {
+ return (addr >> MTE_START_BIT) & MTE_TAG_MAX;
+}
+
+lldb::addr_t
+MemoryTagManagerAArch64MTE::RemoveTagBits(lldb::addr_t addr) const {
+ // Here we're ignoring the whole top byte. If you've got MTE
+ // you must also have TBI (top byte ignore).
+ // The other 4 bits could contain other extension bits or
+ // user metadata.
+ return addr & ~((lldb::addr_t)0xFF << MTE_START_BIT);
+}
+
+ptrdiff_t MemoryTagManagerAArch64MTE::AddressDiff(lldb::addr_t addr1,
+ lldb::addr_t addr2) const {
+ return RemoveTagBits(addr1) - RemoveTagBits(addr2);
+}
+
+lldb::addr_t MemoryTagManagerAArch64MTE::GetGranuleSize() const {
+ return MTE_GRANULE_SIZE;
+}
+
+int32_t MemoryTagManagerAArch64MTE::GetAllocationTagType() const {
+ return eMTE_allocation;
+}
+
+size_t MemoryTagManagerAArch64MTE::GetTagSizeInBytes() const { return 1; }
+
+MemoryTagManagerAArch64MTE::TagRange
+MemoryTagManagerAArch64MTE::ExpandToGranule(TagRange range) const {
+ // Ignore reading a length of 0
+ if (!range.IsValid())
+ return range;
+
+ const size_t granule = GetGranuleSize();
+
+ // Align start down to granule start
+ lldb::addr_t new_start = range.GetRangeBase();
+ lldb::addr_t align_down_amount = new_start % granule;
+ new_start -= align_down_amount;
+
+ // Account for the distance we moved the start above
+ size_t new_len = range.GetByteSize() + align_down_amount;
+ // Then align up to the end of the granule
+ size_t align_up_amount = granule - (new_len % granule);
+ if (align_up_amount != granule)
+ new_len += align_up_amount;
+
+ return TagRange(new_start, new_len);
+}
+
+static llvm::Error MakeInvalidRangeErr(lldb::addr_t addr,
+ lldb::addr_t end_addr) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "End address (0x%" PRIx64
+ ") must be greater than the start address (0x%" PRIx64 ")",
+ end_addr, addr);
+}
+
+llvm::Expected<MemoryTagManager::TagRange>
+MemoryTagManagerAArch64MTE::MakeTaggedRange(
+ lldb::addr_t addr, lldb::addr_t end_addr,
+ const lldb_private::MemoryRegionInfos &memory_regions) const {
+ // First check that the range is not inverted.
+ // We must remove tags here otherwise an address with a higher
+ // tag value will always be > the other.
+ ptrdiff_t len = AddressDiff(end_addr, addr);
+ if (len <= 0)
+ return MakeInvalidRangeErr(addr, end_addr);
+
+ // Region addresses will not have memory tags. So when searching
+ // we must use an untagged address.
+ MemoryRegionInfo::RangeType tag_range(RemoveTagBits(addr), len);
+ tag_range = ExpandToGranule(tag_range);
+
+ // Make a copy so we can use the original for errors and the final return.
+ MemoryRegionInfo::RangeType remaining_range(tag_range);
+
+ // While there are parts of the range that don't have a matching tagged memory
+ // region
+ while (remaining_range.IsValid()) {
+ // Search for a region that contains the start of the range
+ MemoryRegionInfos::const_iterator region = std::find_if(
+ memory_regions.cbegin(), memory_regions.cend(),
+ [&remaining_range](const MemoryRegionInfo &region) {
+ return region.GetRange().Contains(remaining_range.GetRangeBase());
+ });
+
+ if (region == memory_regions.cend() ||
+ region->GetMemoryTagged() != MemoryRegionInfo::eYes) {
+ // Some part of this range is untagged (or unmapped) so error
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Address range 0x%" PRIx64 ":0x%" PRIx64
+ " is not in a memory tagged region",
+ tag_range.GetRangeBase(),
+ tag_range.GetRangeEnd());
+ }
+
+ // We've found some part of the range so remove that part and continue
+ // searching for the rest. Moving the base "slides" the range so we need to
+ // save/restore the original end. If old_end is less than the new base, the
+ // range will be set to have 0 size and we'll exit the while.
+ lldb::addr_t old_end = remaining_range.GetRangeEnd();
+ remaining_range.SetRangeBase(region->GetRange().GetRangeEnd());
+ remaining_range.SetRangeEnd(old_end);
+ }
+
+ // Every part of the range is contained within a tagged memory region.
+ return tag_range;
+}
+
+llvm::Expected<std::vector<MemoryTagManager::TagRange>>
+MemoryTagManagerAArch64MTE::MakeTaggedRanges(
+ lldb::addr_t addr, lldb::addr_t end_addr,
+ const lldb_private::MemoryRegionInfos &memory_regions) const {
+ // First check that the range is not inverted.
+ // We must remove tags here otherwise an address with a higher
+ // tag value will always be > the other.
+ ptrdiff_t len = AddressDiff(end_addr, addr);
+ if (len <= 0)
+ return MakeInvalidRangeErr(addr, end_addr);
+
+ std::vector<MemoryTagManager::TagRange> tagged_ranges;
+ // No memory regions means no tagged memory at all
+ if (memory_regions.empty())
+ return tagged_ranges;
+
+ // For the logic to work regions must be in ascending order
+ // which is what you'd have if you used GetMemoryRegions.
+ assert(std::is_sorted(
+ memory_regions.begin(), memory_regions.end(),
+ [](const MemoryRegionInfo &lhs, const MemoryRegionInfo &rhs) {
+ return lhs.GetRange().GetRangeBase() < rhs.GetRange().GetRangeBase();
+ }));
+
+ // If we're debugging userspace in an OS like Linux that uses an MMU,
+ // the only reason we'd get overlapping regions is incorrect data.
+ // It is possible that won't hold for embedded with memory protection
+ // units (MPUs) that allow overlaps.
+ //
+ // For now we're going to assume the former, as there is no good way
+ // to handle overlaps. For example:
+ // < requested range >
+ // [-- region 1 --]
+ // [-- region 2--]
+ // Where the first region will reduce the requested range to nothing
+ // and exit early before it sees the overlap.
+ MemoryRegionInfos::const_iterator overlap = std::adjacent_find(
+ memory_regions.begin(), memory_regions.end(),
+ [](const MemoryRegionInfo &lhs, const MemoryRegionInfo &rhs) {
+ return rhs.GetRange().DoesIntersect(lhs.GetRange());
+ });
+ UNUSED_IF_ASSERT_DISABLED(overlap);
+ assert(overlap == memory_regions.end());
+
+ // Region addresses will not have memory tags so when searching
+ // we must use an untagged address.
+ MemoryRegionInfo::RangeType range(RemoveTagBits(addr), len);
+ range = ExpandToGranule(range);
+
+ // While there are regions to check and the range has non zero length
+ for (const MemoryRegionInfo &region : memory_regions) {
+ // If range we're checking has been reduced to zero length, exit early
+ if (!range.IsValid())
+ break;
+
+ // If the region doesn't overlap the range at all, ignore it.
+ if (!region.GetRange().DoesIntersect(range))
+ continue;
+
+ // If it's tagged record this sub-range.
+ // (assuming that it's already granule aligned)
+ if (region.GetMemoryTagged()) {
+ // The region found may extend outside the requested range.
+ // For example the first region might start before the range.
+ // We must only add what covers the requested range.
+ lldb::addr_t start =
+ std::max(range.GetRangeBase(), region.GetRange().GetRangeBase());
+ lldb::addr_t end =
+ std::min(range.GetRangeEnd(), region.GetRange().GetRangeEnd());
+ tagged_ranges.push_back(MemoryTagManager::TagRange(start, end - start));
+ }
+
+ // Move the range up to start at the end of the region.
+ lldb::addr_t old_end = range.GetRangeEnd();
+ // This "slides" the range so it moves the end as well.
+ range.SetRangeBase(region.GetRange().GetRangeEnd());
+ // So we set the end back to the original end address after sliding it up.
+ range.SetRangeEnd(old_end);
+ // (if the above were to try to set end < begin the range will just be set
+ // to 0 size)
+ }
+
+ return tagged_ranges;
+}
+
+llvm::Expected<std::vector<lldb::addr_t>>
+MemoryTagManagerAArch64MTE::UnpackTagsData(const std::vector<uint8_t> &tags,
+ size_t granules /*=0*/) const {
+ // 0 means don't check the number of tags before unpacking
+ if (granules) {
+ size_t num_tags = tags.size() / GetTagSizeInBytes();
+ if (num_tags != granules) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Packed tag data size does not match expected number of tags. "
+ "Expected %zu tag(s) for %zu granule(s), got %zu tag(s).",
+ granules, granules, num_tags);
+ }
+ }
+
+ // (if bytes per tag was not 1, we would reconstruct them here)
+
+ std::vector<lldb::addr_t> unpacked;
+ unpacked.reserve(tags.size());
+ for (auto it = tags.begin(); it != tags.end(); ++it) {
+ // Check all tags are in range
+ if (*it > MTE_TAG_MAX) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Found tag 0x%x which is > max MTE tag value of 0x%x.", *it,
+ MTE_TAG_MAX);
+ }
+ unpacked.push_back(*it);
+ }
+
+ return unpacked;
+}
+
+std::vector<lldb::addr_t>
+MemoryTagManagerAArch64MTE::UnpackTagsFromCoreFileSegment(
+ CoreReaderFn reader, lldb::addr_t tag_segment_virtual_address,
+ lldb::addr_t tag_segment_data_address, lldb::addr_t addr,
+ size_t len) const {
+ // We can assume by now that addr and len have been granule aligned by a tag
+ // manager. However because we have 2 tags per byte we need to round the range
+ // up again to align to 2 granule boundaries.
+ const size_t granule = GetGranuleSize();
+ const size_t two_granules = granule * 2;
+ lldb::addr_t aligned_addr = addr;
+ size_t aligned_len = len;
+
+ // First align the start address down.
+ if (aligned_addr % two_granules) {
+ assert(aligned_addr % two_granules == granule);
+ aligned_addr -= granule;
+ aligned_len += granule;
+ }
+
+ // Then align the length up.
+ bool aligned_length_up = false;
+ if (aligned_len % two_granules) {
+ assert(aligned_len % two_granules == granule);
+ aligned_len += granule;
+ aligned_length_up = true;
+ }
+
+ // ProcessElfCore should have validated this when it found the segment.
+ assert(aligned_addr >= tag_segment_virtual_address);
+
+ // By now we know that aligned_addr is aligned to a 2 granule boundary.
+ const size_t offset_granules =
+ (aligned_addr - tag_segment_virtual_address) / granule;
+ // 2 tags per byte.
+ const size_t file_offset_in_bytes = offset_granules / 2;
+
+ // By now we know that aligned_len is at least 2 granules.
+ const size_t tag_bytes_to_read = aligned_len / granule / 2;
+ std::vector<uint8_t> tag_data(tag_bytes_to_read);
+ const size_t bytes_copied =
+ reader(tag_segment_data_address + file_offset_in_bytes, tag_bytes_to_read,
+ tag_data.data());
+ UNUSED_IF_ASSERT_DISABLED(bytes_copied);
+ assert(bytes_copied == tag_bytes_to_read);
+
+ std::vector<lldb::addr_t> tags;
+ tags.reserve(2 * tag_data.size());
+ // No need to check the range of the tag value here as each occupies only 4
+ // bits.
+ for (auto tag_byte : tag_data) {
+ tags.push_back(tag_byte & 0xf);
+ tags.push_back(tag_byte >> 4);
+ }
+
+ // If we aligned the address down, don't return the extra first tag.
+ if (addr != aligned_addr)
+ tags.erase(tags.begin());
+ // If we aligned the length up, don't return the extra last tag.
+ if (aligned_length_up)
+ tags.pop_back();
+
+ return tags;
+}
+
+llvm::Expected<std::vector<uint8_t>> MemoryTagManagerAArch64MTE::PackTags(
+ const std::vector<lldb::addr_t> &tags) const {
+ std::vector<uint8_t> packed;
+ packed.reserve(tags.size() * GetTagSizeInBytes());
+
+ for (auto tag : tags) {
+ if (tag > MTE_TAG_MAX) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Found tag 0x%" PRIx64
+ " which is > max MTE tag value of 0x%x.",
+ tag, MTE_TAG_MAX);
+ }
+ packed.push_back(static_cast<uint8_t>(tag));
+ }
+
+ return packed;
+}
+
+llvm::Expected<std::vector<lldb::addr_t>>
+MemoryTagManagerAArch64MTE::RepeatTagsForRange(
+ const std::vector<lldb::addr_t> &tags, TagRange range) const {
+ std::vector<lldb::addr_t> new_tags;
+
+ // If the range is not empty
+ if (range.IsValid()) {
+ if (tags.empty()) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Expected some tags to cover given range, got zero.");
+ }
+
+ // We assume that this range has already been expanded/aligned to granules
+ size_t granules = range.GetByteSize() / GetGranuleSize();
+ new_tags.reserve(granules);
+ for (size_t to_copy = 0; granules > 0; granules -= to_copy) {
+ to_copy = granules > tags.size() ? tags.size() : granules;
+ new_tags.insert(new_tags.end(), tags.begin(), tags.begin() + to_copy);
+ }
+ }
+
+ return new_tags;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
new file mode 100644
index 000000000000..365e176e5b1d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
@@ -0,0 +1,63 @@
+//===-- MemoryTagManagerAArch64MTE.h ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_MEMORYTAGMANAGERAARCH64MTE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_MEMORYTAGMANAGERAARCH64MTE_H
+
+#include "lldb/Target/MemoryTagManager.h"
+
+namespace lldb_private {
+
+class MemoryTagManagerAArch64MTE : public MemoryTagManager {
+public:
+ // This enum is supposed to be shared for all of AArch64 but until
+ // there are more tag types than MTE, it will live here.
+ enum MTETagTypes {
+ eMTE_logical = 0,
+ eMTE_allocation = 1,
+ };
+
+ lldb::addr_t GetGranuleSize() const override;
+ int32_t GetAllocationTagType() const override;
+ size_t GetTagSizeInBytes() const override;
+
+ lldb::addr_t GetLogicalTag(lldb::addr_t addr) const override;
+ lldb::addr_t RemoveTagBits(lldb::addr_t addr) const override;
+ ptrdiff_t AddressDiff(lldb::addr_t addr1, lldb::addr_t addr2) const override;
+
+ TagRange ExpandToGranule(TagRange range) const override;
+
+ llvm::Expected<TagRange> MakeTaggedRange(
+ lldb::addr_t addr, lldb::addr_t end_addr,
+ const lldb_private::MemoryRegionInfos &memory_regions) const override;
+
+ llvm::Expected<std::vector<TagRange>> MakeTaggedRanges(
+ lldb::addr_t addr, lldb::addr_t end_addr,
+ const lldb_private::MemoryRegionInfos &memory_regions) const override;
+
+ llvm::Expected<std::vector<lldb::addr_t>>
+ UnpackTagsData(const std::vector<uint8_t> &tags,
+ size_t granules = 0) const override;
+
+ std::vector<lldb::addr_t>
+ UnpackTagsFromCoreFileSegment(CoreReaderFn reader,
+ lldb::addr_t tag_segment_virtual_address,
+ lldb::addr_t tag_segment_data_address,
+ lldb::addr_t addr, size_t len) const override;
+
+ llvm::Expected<std::vector<uint8_t>>
+ PackTags(const std::vector<lldb::addr_t> &tags) const override;
+
+ llvm::Expected<std::vector<lldb::addr_t>>
+ RepeatTagsForRange(const std::vector<lldb::addr_t> &tags,
+ TagRange range) const override;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_MEMORYTAGMANAGERAARCH64MTE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
new file mode 100644
index 000000000000..ef71a964eaf2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
@@ -0,0 +1,210 @@
+//===-- NativeProcessSoftwareSingleStep.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessSoftwareSingleStep.h"
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include <unordered_map>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+struct EmulatorBaton {
+ NativeProcessProtocol &m_process;
+ NativeRegisterContext &m_reg_context;
+
+ // eRegisterKindDWARF -> RegsiterValue
+ std::unordered_map<uint32_t, RegisterValue> m_register_values;
+
+ EmulatorBaton(NativeProcessProtocol &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]);
+
+ Status 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);
+}
+
+static int GetSoftwareBreakpointSize(const ArchSpec &arch,
+ lldb::addr_t next_flags) {
+ if (arch.GetMachine() == llvm::Triple::arm) {
+ if (next_flags & 0x20)
+ // Thumb mode
+ return 2;
+ // Arm mode
+ return 4;
+ }
+ if (arch.IsMIPS() || arch.GetTriple().isPPC64() ||
+ arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch())
+ return 4;
+ return 0;
+}
+
+static Status SetSoftwareBreakpointOnPC(const ArchSpec &arch, lldb::addr_t pc,
+ lldb::addr_t next_flags,
+ NativeProcessProtocol &process) {
+ int size_hint = GetSoftwareBreakpointSize(arch, next_flags);
+ Status error;
+ error = process.SetBreakpoint(pc, size_hint, /*hardware=*/false);
+
+ // If setting the breakpoint fails because pc is out of the address
+ // space, ignore it and let the debugee segfault.
+ if (error.GetError() == EIO || error.GetError() == EFAULT)
+ return Status();
+ if (error.Fail())
+ return error;
+
+ return Status();
+}
+
+Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
+ NativeThreadProtocol &thread) {
+ Status error;
+ NativeProcessProtocol &process = thread.GetProcess();
+ NativeRegisterContext &register_context = thread.GetRegisterContext();
+ const ArchSpec &arch = process.GetArchitecture();
+
+ std::unique_ptr<EmulateInstruction> emulator_up(
+ EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying,
+ nullptr));
+
+ if (emulator_up == nullptr)
+ return Status("Instruction emulator not found!");
+
+ EmulatorBaton baton(process, register_context);
+ emulator_up->SetBaton(&baton);
+ emulator_up->SetReadMemCallback(&ReadMemoryCallback);
+ emulator_up->SetReadRegCallback(&ReadRegisterCallback);
+ emulator_up->SetWriteMemCallback(&WriteMemoryCallback);
+ emulator_up->SetWriteRegCallback(&WriteRegisterCallback);
+
+ if (!emulator_up->ReadInstruction()) {
+ // try to get at least the size of next instruction to set breakpoint.
+ auto instr_size = emulator_up->GetLastInstrSize();
+ if (!instr_size)
+ return Status("Read instruction failed!");
+ bool success = false;
+ auto pc = emulator_up->ReadRegisterUnsigned(eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC,
+ LLDB_INVALID_ADDRESS, &success);
+ if (!success)
+ return Status("Reading pc failed!");
+ lldb::addr_t next_pc = pc + *instr_size;
+ auto result =
+ SetSoftwareBreakpointOnPC(arch, next_pc, /* next_flags */ 0x0, process);
+ m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
+ return result;
+ }
+
+ bool emulation_result =
+ emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
+
+ const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+
+ auto pc_it =
+ baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);
+ auto flags_it = reg_info_flags == nullptr
+ ? baton.m_register_values.end()
+ : 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);
+ } 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.GetPC() + emulator_up->GetOpcode().GetByteSize();
+ next_flags = ReadFlags(register_context);
+ } 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 Status("Instruction emulation failed unexpectedly.");
+ }
+ auto result = SetSoftwareBreakpointOnPC(arch, next_pc, next_flags, process);
+ m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
+ return result;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h
new file mode 100644
index 000000000000..f9435b7a84ba
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h
@@ -0,0 +1,31 @@
+//===-- NativeProcessSoftwareSingleStep.h -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeProcessSoftwareSingleStep_h
+#define lldb_NativeProcessSoftwareSingleStep_h
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include <map>
+
+namespace lldb_private {
+
+class NativeProcessSoftwareSingleStep {
+public:
+ Status SetupSoftwareSingleStepping(NativeThreadProtocol &thread);
+
+protected:
+ // 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;
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeProcessSoftwareSingleStep_h
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
new file mode 100644
index 000000000000..4bec3de58668
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
@@ -0,0 +1,470 @@
+//===-- NativeRegisterContextDBReg_arm64.cpp ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextDBReg_arm64.h"
+
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+
+using namespace lldb_private;
+
+// E (bit 0), used to enable breakpoint/watchpoint
+constexpr uint32_t g_enable_bit = 1;
+// PAC (bits 2:1): 0b10
+constexpr uint32_t g_pac_bits = (2 << 1);
+
+// Returns appropriate control register bits for the specified size
+static constexpr inline uint64_t GetSizeBits(int size) {
+ // BAS (bits 12:5) hold a bit-mask of addresses to watch
+ // e.g. 0b00000001 means 1 byte at address
+ // 0b00000011 means 2 bytes (addr..addr+1)
+ // ...
+ // 0b11111111 means 8 bytes (addr..addr+7)
+ return ((1 << size) - 1) << 5;
+}
+
+uint32_t NativeRegisterContextDBReg_arm64::NumSupportedHardwareBreakpoints() {
+ Log *log = GetLog(LLDBLog::Breakpoints);
+ llvm::Error error = ReadHardwareDebugInfo();
+ if (error) {
+ LLDB_LOG_ERROR(log, std::move(error),
+ "failed to read debug registers: {0}");
+ return 0;
+ }
+
+ return m_max_hbp_supported;
+}
+
+uint32_t
+NativeRegisterContextDBReg_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ Log *log = GetLog(LLDBLog::Breakpoints);
+ LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
+
+ // Read hardware breakpoint and watchpoint information.
+ llvm::Error error = ReadHardwareDebugInfo();
+ if (error) {
+ LLDB_LOG_ERROR(
+ log, std::move(error),
+ "unable to set breakpoint: failed to read debug registers: {0}");
+ 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 = g_enable_bit | g_pac_bits | GetSizeBits(size);
+
+ // Iterate over stored breakpoints and find a free bp_index
+ bp_index = LLDB_INVALID_INDEX32;
+ for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
+ if (!BreakpointIsEnabled(i))
+ bp_index = i; // Mark last free slot
+ else if (m_hbp_regs[i].address == addr)
+ return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
+ }
+
+ if (bp_index == LLDB_INVALID_INDEX32)
+ return LLDB_INVALID_INDEX32;
+
+ // Update breakpoint in local cache
+ m_hbp_regs[bp_index].real_addr = addr;
+ m_hbp_regs[bp_index].address = addr;
+ m_hbp_regs[bp_index].control = control_value;
+
+ // PTRACE call to set corresponding hardware breakpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+ if (error) {
+ m_hbp_regs[bp_index].address = 0;
+ m_hbp_regs[bp_index].control &= ~1;
+
+ LLDB_LOG_ERROR(
+ log, std::move(error),
+ "unable to set breakpoint: failed to write debug registers: {0}");
+ return LLDB_INVALID_INDEX32;
+ }
+
+ return bp_index;
+}
+
+bool NativeRegisterContextDBReg_arm64::ClearHardwareBreakpoint(
+ uint32_t hw_idx) {
+ Log *log = GetLog(LLDBLog::Breakpoints);
+ LLDB_LOG(log, "hw_idx: {0}", hw_idx);
+
+ // Read hardware breakpoint and watchpoint information.
+ llvm::Error error = ReadHardwareDebugInfo();
+ if (error) {
+ LLDB_LOG_ERROR(
+ log, std::move(error),
+ "unable to clear breakpoint: failed to read debug registers: {0}");
+ return false;
+ }
+
+ if (hw_idx >= m_max_hbp_supported)
+ return false;
+
+ // Create a backup we can revert to in case of failure.
+ lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address;
+ uint32_t tempControl = m_hbp_regs[hw_idx].control;
+
+ m_hbp_regs[hw_idx].control &= ~g_enable_bit;
+ m_hbp_regs[hw_idx].address = 0;
+
+ // PTRACE call to clear corresponding hardware breakpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+ if (error) {
+ m_hbp_regs[hw_idx].control = tempControl;
+ m_hbp_regs[hw_idx].address = tempAddr;
+
+ LLDB_LOG_ERROR(
+ log, std::move(error),
+ "unable to clear breakpoint: failed to write debug registers: {0}");
+ return false;
+ }
+
+ return true;
+}
+
+Status NativeRegisterContextDBReg_arm64::GetHardwareBreakHitIndex(
+ uint32_t &bp_index, lldb::addr_t trap_addr) {
+ Log *log = GetLog(LLDBLog::Breakpoints);
+
+ LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__);
+
+ lldb::addr_t break_addr;
+
+ for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
+ break_addr = m_hbp_regs[bp_index].address;
+
+ if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) {
+ m_hbp_regs[bp_index].hit_addr = trap_addr;
+ return Status();
+ }
+ }
+
+ bp_index = LLDB_INVALID_INDEX32;
+ return Status();
+}
+
+Status NativeRegisterContextDBReg_arm64::ClearAllHardwareBreakpoints() {
+ Log *log = GetLog(LLDBLog::Breakpoints);
+
+ LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__);
+
+ // Read hardware breakpoint and watchpoint information.
+ llvm::Error error = ReadHardwareDebugInfo();
+ if (error)
+ return Status(std::move(error));
+
+ for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
+ if (BreakpointIsEnabled(i)) {
+ // Create a backup we can revert to in case of failure.
+ lldb::addr_t tempAddr = m_hbp_regs[i].address;
+ uint32_t tempControl = m_hbp_regs[i].control;
+
+ // Clear watchpoints in local cache
+ m_hbp_regs[i].control &= ~g_enable_bit;
+ m_hbp_regs[i].address = 0;
+
+ // Ptrace call to update hardware debug registers
+ error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+ if (error) {
+ m_hbp_regs[i].control = tempControl;
+ m_hbp_regs[i].address = tempAddr;
+
+ return Status(std::move(error));
+ }
+ }
+ }
+
+ return Status();
+}
+
+bool NativeRegisterContextDBReg_arm64::BreakpointIsEnabled(uint32_t bp_index) {
+ if ((m_hbp_regs[bp_index].control & g_enable_bit) != 0)
+ return true;
+ else
+ return false;
+}
+
+uint32_t NativeRegisterContextDBReg_arm64::NumSupportedHardwareWatchpoints() {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ llvm::Error error = ReadHardwareDebugInfo();
+ if (error) {
+ LLDB_LOG_ERROR(log, std::move(error),
+ "failed to read debug registers: {0}");
+ return 0;
+ }
+
+ return m_max_hwp_supported;
+}
+
+uint32_t NativeRegisterContextDBReg_arm64::SetHardwareWatchpoint(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
+ watch_flags);
+
+ // Read hardware breakpoint and watchpoint information.
+ llvm::Error error = ReadHardwareDebugInfo();
+ if (error) {
+ LLDB_LOG_ERROR(
+ log, std::move(error),
+ "unable to set watchpoint: failed to read debug registers: {0}");
+ return LLDB_INVALID_INDEX32;
+ }
+
+ uint32_t control_value = 0, wp_index = 0;
+ lldb::addr_t real_addr = addr;
+
+ // 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. Below is a
+ // hack to recalculate address and size in order to make sure we can watch
+ // non 8-byte aligned addresses as well.
+ if (addr & 0x07) {
+ uint8_t watch_mask = (addr & 0x07) + size;
+
+ if (watch_mask > 0x08)
+ return LLDB_INVALID_INDEX32;
+ else if (watch_mask <= 0x02)
+ size = 2;
+ else if (watch_mask <= 0x04)
+ size = 4;
+ else
+ size = 8;
+
+ addr = addr & (~0x07);
+ }
+
+ // Setup control value
+ control_value = g_enable_bit | g_pac_bits | GetSizeBits(size);
+ control_value |= watch_flags << 3;
+
+ // Iterate over stored watchpoints and find a free wp_index
+ wp_index = LLDB_INVALID_INDEX32;
+ for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
+ if (!WatchpointIsEnabled(i))
+ wp_index = i; // Mark last free slot
+ else if (m_hwp_regs[i].address == addr) {
+ return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
+ }
+ }
+
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return LLDB_INVALID_INDEX32;
+
+ // Update watchpoint in local cache
+ m_hwp_regs[wp_index].real_addr = real_addr;
+ m_hwp_regs[wp_index].address = addr;
+ m_hwp_regs[wp_index].control = control_value;
+
+ // PTRACE call to set corresponding watchpoint register.
+ error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+ if (error) {
+ m_hwp_regs[wp_index].address = 0;
+ m_hwp_regs[wp_index].control &= ~g_enable_bit;
+
+ LLDB_LOG_ERROR(
+ log, std::move(error),
+ "unable to set watchpoint: failed to write debug registers: {0}");
+ return LLDB_INVALID_INDEX32;
+ }
+
+ return wp_index;
+}
+
+bool NativeRegisterContextDBReg_arm64::ClearHardwareWatchpoint(
+ uint32_t wp_index) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ // Read hardware breakpoint and watchpoint information.
+ llvm::Error error = ReadHardwareDebugInfo();
+ if (error) {
+ LLDB_LOG_ERROR(
+ log, std::move(error),
+ "unable to clear watchpoint: failed to read debug registers: {0}");
+ return false;
+ }
+
+ if (wp_index >= m_max_hwp_supported)
+ return false;
+
+ // 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;
+
+ // Update watchpoint in local cache
+ m_hwp_regs[wp_index].control &= ~g_enable_bit;
+ m_hwp_regs[wp_index].address = 0;
+
+ // Ptrace call to update hardware debug registers
+ error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+ if (error) {
+ m_hwp_regs[wp_index].control = tempControl;
+ m_hwp_regs[wp_index].address = tempAddr;
+
+ LLDB_LOG_ERROR(
+ log, std::move(error),
+ "unable to clear watchpoint: failed to write debug registers: {0}");
+ return false;
+ }
+
+ return true;
+}
+
+Status NativeRegisterContextDBReg_arm64::ClearAllHardwareWatchpoints() {
+ // Read hardware breakpoint and watchpoint information.
+ llvm::Error error = ReadHardwareDebugInfo();
+ if (error)
+ return Status(std::move(error));
+
+ for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
+ if (WatchpointIsEnabled(i)) {
+ // Create a backup we can revert to in case of failure.
+ lldb::addr_t tempAddr = m_hwp_regs[i].address;
+ uint32_t tempControl = m_hwp_regs[i].control;
+
+ // Clear watchpoints in local cache
+ m_hwp_regs[i].control &= ~g_enable_bit;
+ m_hwp_regs[i].address = 0;
+
+ // Ptrace call to update hardware debug registers
+ error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+ if (error) {
+ m_hwp_regs[i].control = tempControl;
+ m_hwp_regs[i].address = tempAddr;
+
+ return Status(std::move(error));
+ }
+ }
+ }
+
+ return Status();
+}
+
+uint32_t
+NativeRegisterContextDBReg_arm64::GetWatchpointSize(uint32_t wp_index) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ 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 NativeRegisterContextDBReg_arm64::WatchpointIsEnabled(uint32_t wp_index) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ if ((m_hwp_regs[wp_index].control & g_enable_bit) != 0)
+ return true;
+ else
+ return false;
+}
+
+Status NativeRegisterContextDBReg_arm64::GetWatchpointHitIndex(
+ uint32_t &wp_index, lldb::addr_t trap_addr) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
+
+ // Read hardware breakpoint and watchpoint information.
+ llvm::Error error = ReadHardwareDebugInfo();
+ if (error)
+ return Status(std::move(error));
+
+ // Mask off ignored bits from watchpoint trap address.
+ trap_addr = FixWatchpointHitAddress(trap_addr);
+
+ 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 (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
+ trap_addr < watch_addr + watch_size) {
+ m_hwp_regs[wp_index].hit_addr = trap_addr;
+ return Status();
+ }
+ }
+
+ wp_index = LLDB_INVALID_INDEX32;
+ return Status();
+}
+
+lldb::addr_t
+NativeRegisterContextDBReg_arm64::GetWatchpointAddress(uint32_t wp_index) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ if (wp_index >= m_max_hwp_supported)
+ return LLDB_INVALID_ADDRESS;
+
+ if (WatchpointIsEnabled(wp_index))
+ return m_hwp_regs[wp_index].real_addr;
+ return LLDB_INVALID_ADDRESS;
+}
+
+lldb::addr_t
+NativeRegisterContextDBReg_arm64::GetWatchpointHitAddress(uint32_t wp_index) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ if (wp_index >= m_max_hwp_supported)
+ return LLDB_INVALID_ADDRESS;
+
+ if (WatchpointIsEnabled(wp_index))
+ return m_hwp_regs[wp_index].hit_addr;
+ return LLDB_INVALID_ADDRESS;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
new file mode 100644
index 000000000000..f8246ff4d718
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
@@ -0,0 +1,89 @@
+//===-- NativeRegisterContextDBReg_arm64.h ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextDBReg_arm64_h
+#define lldb_NativeRegisterContextDBReg_arm64_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+#include <array>
+
+namespace lldb_private {
+
+class NativeRegisterContextDBReg_arm64
+ : public virtual NativeRegisterContextRegisterInfo {
+public:
+ uint32_t NumSupportedHardwareBreakpoints() override;
+
+ uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+ bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
+
+ Status ClearAllHardwareBreakpoints() override;
+
+ Status GetHardwareBreakHitIndex(uint32_t &bp_index,
+ lldb::addr_t trap_addr) override;
+
+ bool BreakpointIsEnabled(uint32_t bp_index);
+
+ 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;
+
+ Status ClearAllHardwareWatchpoints() override;
+
+ Status GetWatchpointHitIndex(uint32_t &wp_index,
+ lldb::addr_t trap_addr) override;
+
+ lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) 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:
+ /// Debug register info for hardware breakpoints and watchpoints management.
+ /// Watchpoints: For a user requested size 4 at addr 0x1004, where BAS
+ /// watchpoints are at doubleword (8-byte) alignment.
+ /// \a real_addr is 0x1004
+ /// \a address is 0x1000
+ /// size is 8
+ /// If a one-byte write to 0x1006 is the most recent watchpoint trap,
+ /// \a hit_addr is 0x1006
+ struct DREG {
+ lldb::addr_t address; // Breakpoint/watchpoint address value.
+ lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception
+ // occurred.
+ lldb::addr_t real_addr; // Address value that should cause target to stop.
+ uint32_t control; // Breakpoint/watchpoint control value.
+ };
+
+ std::array<struct DREG, 16> m_hbp_regs; // hardware breakpoints
+ std::array<struct DREG, 16> m_hwp_regs; // hardware watchpoints
+
+ uint32_t m_max_hbp_supported;
+ uint32_t m_max_hwp_supported;
+
+ virtual llvm::Error ReadHardwareDebugInfo() = 0;
+ virtual llvm::Error WriteHardwareDebugRegs(DREGType hwbType) = 0;
+ virtual lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) {
+ return hit_addr;
+ }
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextDBReg_arm64_h
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.cpp
new file mode 100644
index 000000000000..f5525e3e3cb3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.cpp
@@ -0,0 +1,276 @@
+//===-- NativeRegisterContextDBReg_x86.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextDBReg_x86.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+using namespace lldb_private;
+
+// Returns mask/value for status bit of wp_index in DR6
+static inline uint64_t GetStatusBit(uint32_t wp_index) {
+ // DR6: ...BBBB
+ // 3210 <- status bits for bp./wp. i; 1 if hit
+ return 1ULL << wp_index;
+}
+
+// Returns mask/value for global enable bit of wp_index in DR7
+static inline uint64_t GetEnableBit(uint32_t wp_index) {
+ // DR7: ...GLGLGLGL
+ // 33221100 <- global/local enable for bp./wp.; 1 if enabled
+ // we use global bits because NetBSD kernel does not preserve local
+ // bits reliably; Linux seems fine with either
+ return 1ULL << (2 * wp_index + 1);
+}
+
+// Returns mask for both enable bits of wp_index in DR7
+static inline uint64_t GetBothEnableBitMask(uint32_t wp_index) {
+ // DR7: ...GLGLGLGL
+ // 33221100 <- global/local enable for bp./wp.; 1 if enabled
+ return 3ULL << (2 * wp_index + 1);
+}
+
+// Returns value for type bits of wp_index in DR7
+static inline uint64_t GetWatchTypeBits(uint32_t watch_flags,
+ uint32_t wp_index) {
+ // DR7:
+ // bit: 3322222222221111...
+ // 1098765432109876...
+ // val: SSTTSSTTSSTTSSTT...
+ // wp.: 3333222211110000...
+ //
+ // where T - type is 01 for write, 11 for r/w
+ return static_cast<uint64_t>(watch_flags) << (16 + 4 * wp_index);
+}
+
+// Returns value for size bits of wp_index in DR7
+static inline uint64_t GetWatchSizeBits(uint32_t size, uint32_t wp_index) {
+ // DR7:
+ // bit: 3322222222221111...
+ // 1098765432109876...
+ // val: SSTTSSTTSSTTSSTT...
+ // wp.: 3333222211110000...
+ //
+ // where S - size is:
+ // 00 for 1 byte
+ // 01 for 2 bytes
+ // 10 for 8 bytes
+ // 11 for 4 bytes
+ return static_cast<uint64_t>(size == 8 ? 0x2 : size - 1)
+ << (18 + 4 * wp_index);
+}
+
+// Returns bitmask for all bits controlling wp_index in DR7
+static inline uint64_t GetWatchControlBitmask(uint32_t wp_index) {
+ // DR7:
+ // bit: 33222222222211111111110000000000
+ // 10987654321098765432109876543210
+ // val: SSTTSSTTSSTTSSTTxxxxxxGLGLGLGLGL
+ // wp.: 3333222211110000xxxxxxEE33221100
+ return GetBothEnableBitMask(wp_index) | (0xF << (16 + 4 * wp_index));
+}
+
+// Bit mask for control bits regarding all watchpoints.
+static constexpr uint64_t watchpoint_all_control_bit_mask = 0xFFFF00FF;
+
+const RegisterInfo *NativeRegisterContextDBReg_x86::GetDR(int num) const {
+ assert(num >= 0 && num <= 7);
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ return GetRegisterInfoAtIndex(lldb_dr0_i386 + num);
+ case llvm::Triple::x86_64:
+ return GetRegisterInfoAtIndex(lldb_dr0_x86_64 + num);
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+}
+
+Status NativeRegisterContextDBReg_x86::IsWatchpointHit(uint32_t wp_index,
+ bool &is_hit) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("Watchpoint index out of range");
+
+ RegisterValue dr6;
+ Status error = ReadRegister(GetDR(6), dr6);
+ if (error.Fail())
+ is_hit = false;
+ else
+ is_hit = dr6.GetAsUInt64() & GetStatusBit(wp_index);
+
+ return error;
+}
+
+Status
+NativeRegisterContextDBReg_x86::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;
+ Status 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 Status();
+}
+
+Status NativeRegisterContextDBReg_x86::IsWatchpointVacant(uint32_t wp_index,
+ bool &is_vacant) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("Watchpoint index out of range");
+
+ RegisterValue dr7;
+ Status error = ReadRegister(GetDR(7), dr7);
+ if (error.Fail())
+ is_vacant = false;
+ else
+ is_vacant = !(dr7.GetAsUInt64() & GetEnableBit(wp_index));
+
+ return error;
+}
+
+Status NativeRegisterContextDBReg_x86::SetHardwareWatchpointWithIndex(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
+
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("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 == 2)
+ watch_flags = 3;
+
+ if (watch_flags != 1 && watch_flags != 3)
+ return Status("Invalid read/write bits for watchpoint");
+ if (size != 1 && size != 2 && size != 4 && size != 8)
+ return Status("Invalid size for watchpoint");
+
+ bool is_vacant;
+ Status error = IsWatchpointVacant(wp_index, is_vacant);
+ if (error.Fail())
+ return error;
+ if (!is_vacant)
+ return Status("Watchpoint index not vacant");
+
+ RegisterValue dr7, drN;
+ error = ReadRegister(GetDR(7), dr7);
+ if (error.Fail())
+ return error;
+ error = ReadRegister(GetDR(wp_index), drN);
+ if (error.Fail())
+ return error;
+
+ uint64_t control_bits = dr7.GetAsUInt64() & ~GetWatchControlBitmask(wp_index);
+ control_bits |= GetEnableBit(wp_index) |
+ GetWatchTypeBits(watch_flags, wp_index) |
+ GetWatchSizeBits(size, wp_index);
+
+ // Clear dr6 if address or bits changed (i.e. we're not reenabling the same
+ // watchpoint). This can not be done when clearing watchpoints since
+ // the gdb-remote protocol repeatedly clears and readds watchpoints on all
+ // program threads, effectively clearing pending events on NetBSD.
+ // NB: enable bits in dr7 are always 0 here since we're (re)adding it
+ if (drN.GetAsUInt64() != addr ||
+ (dr7.GetAsUInt64() & GetWatchControlBitmask(wp_index)) !=
+ (GetWatchTypeBits(watch_flags, wp_index) |
+ GetWatchSizeBits(size, wp_index))) {
+ ClearWatchpointHit(wp_index);
+
+ // We skip update to drN if neither address nor mode changed.
+ error = WriteRegister(GetDR(wp_index), RegisterValue(addr));
+ if (error.Fail())
+ return error;
+ }
+
+ error = WriteRegister(GetDR(7), RegisterValue(control_bits));
+ if (error.Fail())
+ return error;
+
+ return error;
+}
+
+bool NativeRegisterContextDBReg_x86::ClearHardwareWatchpoint(
+ uint32_t wp_index) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return false;
+
+ RegisterValue dr7;
+ Status error = ReadRegister(GetDR(7), dr7);
+ if (error.Fail())
+ return false;
+
+ return WriteRegister(GetDR(7), RegisterValue(dr7.GetAsUInt64() &
+ ~GetBothEnableBitMask(wp_index)))
+ .Success();
+}
+
+Status NativeRegisterContextDBReg_x86::ClearWatchpointHit(uint32_t wp_index) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("Watchpoint index out of range");
+
+ RegisterValue dr6;
+ Status error = ReadRegister(GetDR(6), dr6);
+ if (error.Fail())
+ return error;
+
+ return WriteRegister(
+ GetDR(6), RegisterValue(dr6.GetAsUInt64() & ~GetStatusBit(wp_index)));
+}
+
+Status NativeRegisterContextDBReg_x86::ClearAllHardwareWatchpoints() {
+ RegisterValue dr7;
+ Status error = ReadRegister(GetDR(7), dr7);
+ if (error.Fail())
+ return error;
+ return WriteRegister(
+ GetDR(7),
+ RegisterValue(dr7.GetAsUInt64() & ~watchpoint_all_control_bit_mask));
+}
+
+uint32_t NativeRegisterContextDBReg_x86::SetHardwareWatchpoint(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
+ bool is_vacant;
+ Status 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) {
+ LLDB_LOGF(log, "NativeRegisterContextDBReg_x86::%s Error: %s",
+ __FUNCTION__, error.AsCString());
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+lldb::addr_t
+NativeRegisterContextDBReg_x86::GetWatchpointAddress(uint32_t wp_index) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return LLDB_INVALID_ADDRESS;
+ RegisterValue drN;
+ if (ReadRegister(GetDR(wp_index), drN).Fail())
+ return LLDB_INVALID_ADDRESS;
+ return drN.GetAsUInt64();
+}
+
+uint32_t NativeRegisterContextDBReg_x86::NumSupportedHardwareWatchpoints() {
+ // Available debug address registers: dr0, dr1, dr2, dr3
+ return 4;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h
new file mode 100644
index 000000000000..4ca288d9dff7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h
@@ -0,0 +1,54 @@
+//===-- NativeRegisterContextDBReg_x86.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextDBReg_x86_h
+#define lldb_NativeRegisterContextDBReg_x86_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+namespace lldb_private {
+
+class NativeRegisterContextDBReg_x86
+ : public virtual NativeRegisterContextRegisterInfo {
+public:
+ // NB: This constructor is here only because gcc<=6.5 requires a virtual base
+ // class initializer on abstract class (even though it is never used). It can
+ // be deleted once we move to gcc>=7.0.
+ NativeRegisterContextDBReg_x86(NativeThreadProtocol &thread)
+ : NativeRegisterContextRegisterInfo(thread, nullptr) {}
+
+ Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
+
+ Status GetWatchpointHitIndex(uint32_t &wp_index,
+ lldb::addr_t trap_addr) override;
+
+ Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
+
+ bool ClearHardwareWatchpoint(uint32_t wp_index) override;
+
+ Status ClearWatchpointHit(uint32_t wp_index) override;
+
+ Status ClearAllHardwareWatchpoints() override;
+
+ Status 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;
+
+ virtual const RegisterInfo *GetDR(int num) const;
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextDBReg_x86_h
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp
new file mode 100644
index 000000000000..3a875f7bb39b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp
@@ -0,0 +1,42 @@
+//===-- NativeRegisterContextRegisterInfo.cpp -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextRegisterInfo.h"
+#include "lldb/lldb-private-forward.h"
+#include "lldb/lldb-types.h"
+
+using namespace lldb_private;
+
+NativeRegisterContextRegisterInfo::NativeRegisterContextRegisterInfo(
+ NativeThreadProtocol &thread,
+ RegisterInfoInterface *register_info_interface)
+ : NativeRegisterContext(thread),
+ m_register_info_interface_up(register_info_interface) {
+ assert(register_info_interface && "null register_info_interface");
+}
+
+uint32_t NativeRegisterContextRegisterInfo::GetRegisterCount() const {
+ return m_register_info_interface_up->GetRegisterCount();
+}
+
+uint32_t NativeRegisterContextRegisterInfo::GetUserRegisterCount() const {
+ return m_register_info_interface_up->GetUserRegisterCount();
+}
+
+const RegisterInfo *NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex(
+ uint32_t reg_index) const {
+ if (reg_index <= GetRegisterCount())
+ return m_register_info_interface_up->GetRegisterInfo() + reg_index;
+ else
+ return nullptr;
+}
+
+const RegisterInfoInterface &
+NativeRegisterContextRegisterInfo::GetRegisterInfoInterface() const {
+ return *m_register_info_interface_up;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h
new file mode 100644
index 000000000000..0e96841fd909
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h
@@ -0,0 +1,40 @@
+//===-- NativeRegisterContextRegisterInfo.h ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NATIVEREGISTERCONTEXTREGISTERINFO_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NATIVEREGISTERCONTEXTREGISTERINFO_H
+
+#include <memory>
+
+#include "RegisterInfoInterface.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+
+namespace lldb_private {
+class NativeRegisterContextRegisterInfo : public NativeRegisterContext {
+public:
+ ///
+ /// Construct a NativeRegisterContextRegisterInfo, taking ownership
+ /// of the register_info_interface pointer.
+ ///
+ NativeRegisterContextRegisterInfo(
+ NativeThreadProtocol &thread,
+ RegisterInfoInterface *register_info_interface);
+
+ uint32_t GetRegisterCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+
+ const RegisterInfo *GetRegisterInfoAtIndex(uint32_t reg_index) const override;
+
+ const RegisterInfoInterface &GetRegisterInfoInterface() const;
+
+protected:
+ std::unique_ptr<RegisterInfoInterface> m_register_info_interface_up;
+};
+}
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp
new file mode 100644
index 000000000000..6e4e5038566b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp
@@ -0,0 +1,99 @@
+//===-- NetBSDSignals.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NetBSDSignals.h"
+
+#ifdef __NetBSD__
+#include <csignal>
+
+#define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \
+ static_assert(signal_name == signal_value, \
+ "Value mismatch for signal number " #signal_name); \
+ static_assert(code_name == code_value, \
+ "Value mismatch for signal code " #code_name); \
+ AddSignalCode(signal_value, code_value, __VA_ARGS__)
+#else
+#define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \
+ AddSignalCode(signal_value, code_value, __VA_ARGS__)
+#endif /* ifdef __NetBSD */
+
+using namespace lldb_private;
+
+NetBSDSignals::NetBSDSignals() : UnixSignals() { Reset(); }
+
+void NetBSDSignals::Reset() {
+ UnixSignals::Reset();
+
+ // clang-format off
+ // SIGILL
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLOPC, 1, "illegal opcode");
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLOPN, 2, "illegal operand");
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLADR, 3, "illegal addressing mode");
+ ADD_SIGCODE(SIGILL, 4, ILL_ILLTRP, 4, "illegal trap");
+ ADD_SIGCODE(SIGILL, 4, ILL_PRVOPC, 5, "privileged opcode");
+ ADD_SIGCODE(SIGILL, 4, ILL_PRVREG, 6, "privileged register");
+ ADD_SIGCODE(SIGILL, 4, ILL_COPROC, 7, "coprocessor error");
+ ADD_SIGCODE(SIGILL, 4, ILL_BADSTK, 8, "internal stack error");
+
+ // SIGFPE
+ ADD_SIGCODE(SIGFPE, 8, FPE_INTDIV, 1, "integer divide by zero");
+ ADD_SIGCODE(SIGFPE, 8, FPE_INTOVF, 2, "integer overflow");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTDIV, 3, "floating point divide by zero");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTOVF, 4, "floating point overflow");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTUND, 5, "floating point underflow");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTRES, 6, "floating point inexact result");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTINV, 7, "invalid floating point operation");
+ ADD_SIGCODE(SIGFPE, 8, FPE_FLTSUB, 8, "subscript out of range");
+
+ // SIGBUS
+ ADD_SIGCODE(SIGBUS, 10, BUS_ADRALN, 1, "invalid address alignment");
+ ADD_SIGCODE(SIGBUS, 10, BUS_ADRERR, 2, "non-existent physical address");
+ ADD_SIGCODE(SIGBUS, 10, BUS_OBJERR, 3, "object specific hardware error");
+
+ // SIGSEGV
+ ADD_SIGCODE(SIGSEGV, 11, SEGV_MAPERR, 1, "address not mapped to object",
+ SignalCodePrintOption::Address);
+ ADD_SIGCODE(SIGSEGV, 11, SEGV_ACCERR, 2, "invalid permissions for mapped object",
+ SignalCodePrintOption::Address);
+
+ // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION
+ // ===== ============== ======== ====== ====== ========================
+ AddSignal(32, "SIGPWR", false, true, true, "power fail/restart (not reset when caught)");
+ AddSignal(33, "SIGRTMIN", false, false, false, "real time signal 0");
+ AddSignal(34, "SIGRTMIN+1", false, false, false, "real time signal 1");
+ AddSignal(35, "SIGRTMIN+2", false, false, false, "real time signal 2");
+ AddSignal(36, "SIGRTMIN+3", false, false, false, "real time signal 3");
+ AddSignal(37, "SIGRTMIN+4", false, false, false, "real time signal 4");
+ AddSignal(38, "SIGRTMIN+5", false, false, false, "real time signal 5");
+ AddSignal(39, "SIGRTMIN+6", false, false, false, "real time signal 6");
+ AddSignal(40, "SIGRTMIN+7", false, false, false, "real time signal 7");
+ AddSignal(41, "SIGRTMIN+8", false, false, false, "real time signal 8");
+ AddSignal(42, "SIGRTMIN+9", false, false, false, "real time signal 9");
+ AddSignal(43, "SIGRTMIN+10", false, false, false, "real time signal 10");
+ AddSignal(44, "SIGRTMIN+11", false, false, false, "real time signal 11");
+ AddSignal(45, "SIGRTMIN+12", false, false, false, "real time signal 12");
+ AddSignal(46, "SIGRTMIN+13", false, false, false, "real time signal 13");
+ AddSignal(47, "SIGRTMIN+14", false, false, false, "real time signal 14");
+ AddSignal(48, "SIGRTMIN+15", false, false, false, "real time signal 15");
+ AddSignal(49, "SIGRTMIN-14", false, false, false, "real time signal 16");
+ AddSignal(50, "SIGRTMAX-13", false, false, false, "real time signal 17");
+ AddSignal(51, "SIGRTMAX-12", false, false, false, "real time signal 18");
+ AddSignal(52, "SIGRTMAX-11", false, false, false, "real time signal 19");
+ AddSignal(53, "SIGRTMAX-10", false, false, false, "real time signal 20");
+ AddSignal(54, "SIGRTMAX-9", false, false, false, "real time signal 21");
+ AddSignal(55, "SIGRTMAX-8", false, false, false, "real time signal 22");
+ AddSignal(56, "SIGRTMAX-7", false, false, false, "real time signal 23");
+ AddSignal(57, "SIGRTMAX-6", false, false, false, "real time signal 24");
+ AddSignal(58, "SIGRTMAX-5", false, false, false, "real time signal 25");
+ AddSignal(59, "SIGRTMAX-4", false, false, false, "real time signal 26");
+ AddSignal(60, "SIGRTMAX-3", false, false, false, "real time signal 27");
+ AddSignal(61, "SIGRTMAX-2", false, false, false, "real time signal 28");
+ AddSignal(62, "SIGRTMAX-1", false, false, false, "real time signal 29");
+ AddSignal(63, "SIGRTMAX", false, false, false, "real time signal 30");
+ // clang-format on
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.h
new file mode 100644
index 000000000000..94bad7c19a49
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NetBSDSignals.h
@@ -0,0 +1,27 @@
+//===-- NetBSDSignals.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NETBSDSIGNALS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NETBSDSIGNALS_H
+
+#include "lldb/Target/UnixSignals.h"
+
+namespace lldb_private {
+
+/// NetBSD specific set of Unix signals.
+class NetBSDSignals : public UnixSignals {
+public:
+ NetBSDSignals();
+
+private:
+ void Reset() override;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NETBSDSIGNALS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h
new file mode 100644
index 000000000000..21582df91fb0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwinConstants.h
@@ -0,0 +1,25 @@
+//===-- RegisterContextDarwinConstants.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWINCONSTANTS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWINCONSTANTS_H
+
+namespace lldb_private {
+
+/// Constants returned by various RegisterContextDarwin_*** functions.
+#ifndef KERN_SUCCESS
+#define KERN_SUCCESS 0
+#endif
+
+#ifndef KERN_INVALID_ARGUMENT
+#define KERN_INVALID_ARGUMENT 4
+#endif
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWINCONSTANTS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
new file mode 100644
index 000000000000..c23e82a741a0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
@@ -0,0 +1,1745 @@
+//===-- RegisterContextDarwin_arm.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextDarwin_arm.h"
+#include "RegisterContextDarwinConstants.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+#include <memory>
+
+#include "Utility/ARM_DWARF_Registers.h"
+#include "Utility/ARM_ehframe_Registers.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum {
+ gpr_r0 = 0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_sp = gpr_r13,
+ gpr_r14,
+ gpr_lr = gpr_r14,
+ gpr_r15,
+ gpr_pc = gpr_r15,
+ gpr_cpsr,
+
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+
+ exc_exception,
+ exc_fsr,
+ exc_far,
+
+ dbg_bvr0,
+ dbg_bvr1,
+ dbg_bvr2,
+ dbg_bvr3,
+ dbg_bvr4,
+ dbg_bvr5,
+ dbg_bvr6,
+ dbg_bvr7,
+ dbg_bvr8,
+ dbg_bvr9,
+ dbg_bvr10,
+ dbg_bvr11,
+ dbg_bvr12,
+ dbg_bvr13,
+ dbg_bvr14,
+ dbg_bvr15,
+
+ dbg_bcr0,
+ dbg_bcr1,
+ dbg_bcr2,
+ dbg_bcr3,
+ dbg_bcr4,
+ dbg_bcr5,
+ dbg_bcr6,
+ dbg_bcr7,
+ dbg_bcr8,
+ dbg_bcr9,
+ dbg_bcr10,
+ dbg_bcr11,
+ dbg_bcr12,
+ dbg_bcr13,
+ dbg_bcr14,
+ dbg_bcr15,
+
+ dbg_wvr0,
+ dbg_wvr1,
+ dbg_wvr2,
+ dbg_wvr3,
+ dbg_wvr4,
+ dbg_wvr5,
+ dbg_wvr6,
+ dbg_wvr7,
+ dbg_wvr8,
+ dbg_wvr9,
+ dbg_wvr10,
+ dbg_wvr11,
+ dbg_wvr12,
+ dbg_wvr13,
+ dbg_wvr14,
+ dbg_wvr15,
+
+ dbg_wcr0,
+ dbg_wcr1,
+ dbg_wcr2,
+ dbg_wcr3,
+ dbg_wcr4,
+ dbg_wcr5,
+ dbg_wcr6,
+ dbg_wcr7,
+ dbg_wcr8,
+ dbg_wcr9,
+ dbg_wcr10,
+ dbg_wcr11,
+ dbg_wcr12,
+ dbg_wcr13,
+ dbg_wcr14,
+ dbg_wcr15,
+
+ k_num_registers
+};
+
+#define GPR_OFFSET(idx) ((idx)*4)
+#define FPU_OFFSET(idx) ((idx)*4 + sizeof(RegisterContextDarwin_arm::GPR))
+#define EXC_OFFSET(idx) \
+ ((idx)*4 + sizeof(RegisterContextDarwin_arm::GPR) + \
+ sizeof(RegisterContextDarwin_arm::FPU))
+#define DBG_OFFSET(reg) \
+ ((LLVM_EXTENSION offsetof(RegisterContextDarwin_arm::DBG, reg) + \
+ sizeof(RegisterContextDarwin_arm::GPR) + \
+ sizeof(RegisterContextDarwin_arm::FPU) + \
+ sizeof(RegisterContextDarwin_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) \
+ #reg, NULL, sizeof(((RegisterContextDarwin_arm::DBG *) NULL)->reg[i]), \
+ DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM }, \
+ nullptr, nullptr, nullptr,
+#define REG_CONTEXT_SIZE \
+ (sizeof(RegisterContextDarwin_arm::GPR) + \
+ sizeof(RegisterContextDarwin_arm::FPU) + \
+ sizeof(RegisterContextDarwin_arm::EXC))
+
+static RegisterInfo g_register_infos[] = {
+ // General purpose registers
+ // NAME ALT SZ OFFSET ENCODING FORMAT
+ // EH_FRAME DWARF GENERIC
+ // PROCESS PLUGIN LLDB NATIVE
+ // ====== ======= == ============= ============= ============
+ // =============== =============== =========================
+ // ===================== =============
+ {"r0",
+ nullptr,
+ 4,
+ GPR_OFFSET(0),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r0, dwarf_r0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r0},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r1",
+ nullptr,
+ 4,
+ GPR_OFFSET(1),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r1, dwarf_r1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r1},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r2",
+ nullptr,
+ 4,
+ GPR_OFFSET(2),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r2},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r3",
+ nullptr,
+ 4,
+ GPR_OFFSET(3),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r3},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r4",
+ nullptr,
+ 4,
+ GPR_OFFSET(4),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r4, dwarf_r4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r4},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r5",
+ nullptr,
+ 4,
+ GPR_OFFSET(5),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r5, dwarf_r5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r5},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r6",
+ nullptr,
+ 4,
+ GPR_OFFSET(6),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r6, dwarf_r6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r6},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r7",
+ nullptr,
+ 4,
+ GPR_OFFSET(7),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM,
+ gpr_r7},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r8",
+ nullptr,
+ 4,
+ GPR_OFFSET(8),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r8, dwarf_r8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r8},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r9",
+ nullptr,
+ 4,
+ GPR_OFFSET(9),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r9, dwarf_r9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r9},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r10",
+ nullptr,
+ 4,
+ GPR_OFFSET(10),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r10},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r11",
+ nullptr,
+ 4,
+ GPR_OFFSET(11),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r11, dwarf_r11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r11},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"r12",
+ nullptr,
+ 4,
+ GPR_OFFSET(12),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r12},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"sp",
+ "r13",
+ 4,
+ GPR_OFFSET(13),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM,
+ gpr_sp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"lr",
+ "r14",
+ 4,
+ GPR_OFFSET(14),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM,
+ gpr_lr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"pc",
+ "r15",
+ 4,
+ GPR_OFFSET(15),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM,
+ gpr_pc},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"cpsr",
+ "psr",
+ 4,
+ GPR_OFFSET(16),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM,
+ gpr_cpsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+
+ {"s0",
+ nullptr,
+ 4,
+ FPU_OFFSET(0),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s0},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s1",
+ nullptr,
+ 4,
+ FPU_OFFSET(1),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s1},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s2",
+ nullptr,
+ 4,
+ FPU_OFFSET(2),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s2},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s3",
+ nullptr,
+ 4,
+ FPU_OFFSET(3),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s3},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s4",
+ nullptr,
+ 4,
+ FPU_OFFSET(4),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s4},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s5",
+ nullptr,
+ 4,
+ FPU_OFFSET(5),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s5},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s6",
+ nullptr,
+ 4,
+ FPU_OFFSET(6),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s6},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s7",
+ nullptr,
+ 4,
+ FPU_OFFSET(7),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s7},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s8",
+ nullptr,
+ 4,
+ FPU_OFFSET(8),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s8},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s9",
+ nullptr,
+ 4,
+ FPU_OFFSET(9),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s9},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s10",
+ nullptr,
+ 4,
+ FPU_OFFSET(10),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s10},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s11",
+ nullptr,
+ 4,
+ FPU_OFFSET(11),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s11},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s12",
+ nullptr,
+ 4,
+ FPU_OFFSET(12),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s12},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s13",
+ nullptr,
+ 4,
+ FPU_OFFSET(13),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s13},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s14",
+ nullptr,
+ 4,
+ FPU_OFFSET(14),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s14},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s15",
+ nullptr,
+ 4,
+ FPU_OFFSET(15),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s15},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s16",
+ nullptr,
+ 4,
+ FPU_OFFSET(16),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s16},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s17",
+ nullptr,
+ 4,
+ FPU_OFFSET(17),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s17},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s18",
+ nullptr,
+ 4,
+ FPU_OFFSET(18),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s18},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s19",
+ nullptr,
+ 4,
+ FPU_OFFSET(19),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s19},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s20",
+ nullptr,
+ 4,
+ FPU_OFFSET(20),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s20},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s21",
+ nullptr,
+ 4,
+ FPU_OFFSET(21),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s21},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s22",
+ nullptr,
+ 4,
+ FPU_OFFSET(22),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s22},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s23",
+ nullptr,
+ 4,
+ FPU_OFFSET(23),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s23},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s24",
+ nullptr,
+ 4,
+ FPU_OFFSET(24),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s24},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s25",
+ nullptr,
+ 4,
+ FPU_OFFSET(25),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s25},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s26",
+ nullptr,
+ 4,
+ FPU_OFFSET(26),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s26},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s27",
+ nullptr,
+ 4,
+ FPU_OFFSET(27),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s27},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s28",
+ nullptr,
+ 4,
+ FPU_OFFSET(28),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s28},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s29",
+ nullptr,
+ 4,
+ FPU_OFFSET(29),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s29},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s30",
+ nullptr,
+ 4,
+ FPU_OFFSET(30),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s30},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"s31",
+ nullptr,
+ 4,
+ FPU_OFFSET(31),
+ eEncodingIEEE754,
+ eFormatFloat,
+ {LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s31},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"fpscr",
+ nullptr,
+ 4,
+ FPU_OFFSET(32),
+ eEncodingUint,
+ eFormatHex,
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_fpscr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+
+ {"exception",
+ nullptr,
+ 4,
+ EXC_OFFSET(0),
+ eEncodingUint,
+ eFormatHex,
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_exception},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"fsr",
+ nullptr,
+ 4,
+ EXC_OFFSET(1),
+ eEncodingUint,
+ eFormatHex,
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_fsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"far",
+ nullptr,
+ 4,
+ EXC_OFFSET(2),
+ eEncodingUint,
+ eFormatHex,
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_far},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+
+ {DEFINE_DBG(bvr, 0)},
+ {DEFINE_DBG(bvr, 1)},
+ {DEFINE_DBG(bvr, 2)},
+ {DEFINE_DBG(bvr, 3)},
+ {DEFINE_DBG(bvr, 4)},
+ {DEFINE_DBG(bvr, 5)},
+ {DEFINE_DBG(bvr, 6)},
+ {DEFINE_DBG(bvr, 7)},
+ {DEFINE_DBG(bvr, 8)},
+ {DEFINE_DBG(bvr, 9)},
+ {DEFINE_DBG(bvr, 10)},
+ {DEFINE_DBG(bvr, 11)},
+ {DEFINE_DBG(bvr, 12)},
+ {DEFINE_DBG(bvr, 13)},
+ {DEFINE_DBG(bvr, 14)},
+ {DEFINE_DBG(bvr, 15)},
+
+ {DEFINE_DBG(bcr, 0)},
+ {DEFINE_DBG(bcr, 1)},
+ {DEFINE_DBG(bcr, 2)},
+ {DEFINE_DBG(bcr, 3)},
+ {DEFINE_DBG(bcr, 4)},
+ {DEFINE_DBG(bcr, 5)},
+ {DEFINE_DBG(bcr, 6)},
+ {DEFINE_DBG(bcr, 7)},
+ {DEFINE_DBG(bcr, 8)},
+ {DEFINE_DBG(bcr, 9)},
+ {DEFINE_DBG(bcr, 10)},
+ {DEFINE_DBG(bcr, 11)},
+ {DEFINE_DBG(bcr, 12)},
+ {DEFINE_DBG(bcr, 13)},
+ {DEFINE_DBG(bcr, 14)},
+ {DEFINE_DBG(bcr, 15)},
+
+ {DEFINE_DBG(wvr, 0)},
+ {DEFINE_DBG(wvr, 1)},
+ {DEFINE_DBG(wvr, 2)},
+ {DEFINE_DBG(wvr, 3)},
+ {DEFINE_DBG(wvr, 4)},
+ {DEFINE_DBG(wvr, 5)},
+ {DEFINE_DBG(wvr, 6)},
+ {DEFINE_DBG(wvr, 7)},
+ {DEFINE_DBG(wvr, 8)},
+ {DEFINE_DBG(wvr, 9)},
+ {DEFINE_DBG(wvr, 10)},
+ {DEFINE_DBG(wvr, 11)},
+ {DEFINE_DBG(wvr, 12)},
+ {DEFINE_DBG(wvr, 13)},
+ {DEFINE_DBG(wvr, 14)},
+ {DEFINE_DBG(wvr, 15)},
+
+ {DEFINE_DBG(wcr, 0)},
+ {DEFINE_DBG(wcr, 1)},
+ {DEFINE_DBG(wcr, 2)},
+ {DEFINE_DBG(wcr, 3)},
+ {DEFINE_DBG(wcr, 4)},
+ {DEFINE_DBG(wcr, 5)},
+ {DEFINE_DBG(wcr, 6)},
+ {DEFINE_DBG(wcr, 7)},
+ {DEFINE_DBG(wcr, 8)},
+ {DEFINE_DBG(wcr, 9)},
+ {DEFINE_DBG(wcr, 10)},
+ {DEFINE_DBG(wcr, 11)},
+ {DEFINE_DBG(wcr, 12)},
+ {DEFINE_DBG(wcr, 13)},
+ {DEFINE_DBG(wcr, 14)},
+ {DEFINE_DBG(wcr, 15)}};
+
+// General purpose registers
+static uint32_t g_gpr_regnums[] = {
+ gpr_r0, gpr_r1, gpr_r2, gpr_r3, gpr_r4, gpr_r5, gpr_r6, gpr_r7, gpr_r8,
+ gpr_r9, gpr_r10, gpr_r11, gpr_r12, gpr_sp, gpr_lr, gpr_pc, gpr_cpsr};
+
+// Floating point registers
+static uint32_t g_fpu_regnums[] = {
+ fpu_s0, fpu_s1, fpu_s2, fpu_s3, fpu_s4, fpu_s5, fpu_s6,
+ fpu_s7, fpu_s8, fpu_s9, fpu_s10, fpu_s11, fpu_s12, fpu_s13,
+ fpu_s14, fpu_s15, fpu_s16, fpu_s17, fpu_s18, fpu_s19, fpu_s20,
+ fpu_s21, fpu_s22, fpu_s23, fpu_s24, fpu_s25, fpu_s26, fpu_s27,
+ fpu_s28, fpu_s29, fpu_s30, fpu_s31, fpu_fpscr,
+};
+
+// Exception registers
+
+static uint32_t g_exc_regnums[] = {
+ exc_exception, exc_fsr, exc_far,
+};
+
+static size_t k_num_register_infos = std::size(g_register_infos);
+
+RegisterContextDarwin_arm::RegisterContextDarwin_arm(
+ Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc() {
+ uint32_t i;
+ for (i = 0; i < kNumErrors; i++) {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_arm::~RegisterContextDarwin_arm() = default;
+
+void RegisterContextDarwin_arm::InvalidateAllRegisters() {
+ InvalidateAllRegisterStates();
+}
+
+size_t RegisterContextDarwin_arm::GetRegisterCount() {
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm::GetRegisterInfoAtIndex(size_t reg) {
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return nullptr;
+}
+
+size_t RegisterContextDarwin_arm::GetRegisterInfosCount() {
+ return k_num_register_infos;
+}
+
+const RegisterInfo *RegisterContextDarwin_arm::GetRegisterInfos() {
+ return g_register_infos;
+}
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = std::size(g_gpr_regnums);
+const size_t k_num_fpu_registers = std::size(g_fpu_regnums);
+const size_t k_num_exc_registers = std::size(g_exc_regnums);
+
+// Register set definitions. The first definitions at register set index of
+// zero is for all registers, followed by other registers sets. The register
+// information for the all register set need not be filled in.
+static const RegisterSet g_reg_sets[] = {
+ {
+ "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums,
+ },
+ {"Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums},
+ {"Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums}};
+
+const size_t k_num_regsets = std::size(g_reg_sets);
+
+size_t RegisterContextDarwin_arm::GetRegisterSetCount() {
+ return k_num_regsets;
+}
+
+const RegisterSet *RegisterContextDarwin_arm::GetRegisterSet(size_t reg_set) {
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return nullptr;
+}
+
+// Register information definitions for 32 bit i386.
+int RegisterContextDarwin_arm::GetSetForNativeRegNum(int reg) {
+ if (reg < fpu_s0)
+ return GPRRegSet;
+ else if (reg < exc_exception)
+ return FPURegSet;
+ else if (reg < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+int RegisterContextDarwin_arm::ReadGPR(bool force) {
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int RegisterContextDarwin_arm::ReadFPU(bool force) {
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int RegisterContextDarwin_arm::ReadEXC(bool force) {
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int RegisterContextDarwin_arm::ReadDBG(bool force) {
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+int RegisterContextDarwin_arm::WriteGPR() {
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError(set, Read, -1);
+ return GetError(GPRRegSet, Write);
+}
+
+int RegisterContextDarwin_arm::WriteFPU() {
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError(set, Read, -1);
+ return GetError(FPURegSet, Write);
+}
+
+int RegisterContextDarwin_arm::WriteEXC() {
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError(set, Read, -1);
+ return GetError(EXCRegSet, Write);
+}
+
+int RegisterContextDarwin_arm::WriteDBG() {
+ int set = DBGRegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(set, Write, DoWriteDBG(GetThreadID(), set, dbg));
+ SetError(set, Read, -1);
+ return GetError(DBGRegSet, Write);
+}
+
+int RegisterContextDarwin_arm::ReadRegisterSet(uint32_t set, bool force) {
+ switch (set) {
+ case GPRRegSet:
+ return ReadGPR(force);
+ case GPRAltRegSet:
+ return ReadGPR(force);
+ case FPURegSet:
+ return ReadFPU(force);
+ case EXCRegSet:
+ return ReadEXC(force);
+ case DBGRegSet:
+ return ReadDBG(force);
+ default:
+ break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+int RegisterContextDarwin_arm::WriteRegisterSet(uint32_t set) {
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set)) {
+ switch (set) {
+ case GPRRegSet:
+ return WriteGPR();
+ case GPRAltRegSet:
+ return WriteGPR();
+ case FPURegSet:
+ return WriteFPU();
+ case EXCRegSet:
+ return WriteEXC();
+ case DBGRegSet:
+ return WriteDBG();
+ default:
+ break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+void RegisterContextDarwin_arm::LogDBGRegisters(Log *log, const DBG &dbg) {
+ if (log) {
+ for (uint32_t i = 0; i < 16; i++)
+ LLDB_LOGF(log,
+ "BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } WVR%-2u/WCR%-2u = { "
+ "0x%8.8x, 0x%8.8x }",
+ i, i, dbg.bvr[i], dbg.bcr[i], i, i, dbg.wvr[i], dbg.wcr[i]);
+ }
+}
+
+bool RegisterContextDarwin_arm::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_arm::GetSetForNativeRegNum(reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg) {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ value.SetUInt32(gpr.r[reg - gpr_r0]);
+ break;
+ case gpr_cpsr:
+ value.SetUInt32(gpr.cpsr);
+ break;
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ value.SetUInt32(fpu.floats.s[reg], RegisterValue::eTypeFloat);
+ break;
+
+ case fpu_fpscr:
+ value.SetUInt32(fpu.fpscr);
+ break;
+
+ case exc_exception:
+ value.SetUInt32(exc.exception);
+ break;
+ case exc_fsr:
+ value.SetUInt32(exc.fsr);
+ break;
+ case exc_far:
+ value.SetUInt32(exc.far);
+ break;
+
+ default:
+ value.SetValueToInvalid();
+ return false;
+ }
+ return true;
+}
+
+bool RegisterContextDarwin_arm::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum(reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg) {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ gpr.r[reg - gpr_r0] = value.GetAsUInt32();
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ fpu.floats.s[reg] = value.GetAsUInt32();
+ break;
+
+ case fpu_fpscr:
+ fpu.fpscr = value.GetAsUInt32();
+ break;
+
+ case exc_exception:
+ exc.exception = value.GetAsUInt32();
+ break;
+ case exc_fsr:
+ exc.fsr = value.GetAsUInt32();
+ break;
+ case exc_far:
+ exc.far = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool RegisterContextDarwin_arm::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ data_sp = std::make_shared<DataBufferHeap>(REG_CONTEXT_SIZE, 0);
+ if (data_sp && ReadGPR(false) == KERN_SUCCESS &&
+ ReadFPU(false) == KERN_SUCCESS && ReadEXC(false) == KERN_SUCCESS) {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy(dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy(dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool RegisterContextDarwin_arm::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy(&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy(&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy(&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+uint32_t RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t reg) {
+ if (kind == eRegisterKindGeneric) {
+ switch (reg) {
+ case LLDB_REGNUM_GENERIC_PC:
+ return gpr_pc;
+ case LLDB_REGNUM_GENERIC_SP:
+ return gpr_sp;
+ case LLDB_REGNUM_GENERIC_FP:
+ return gpr_r7;
+ case LLDB_REGNUM_GENERIC_RA:
+ return gpr_lr;
+ case LLDB_REGNUM_GENERIC_FLAGS:
+ return gpr_cpsr;
+ default:
+ break;
+ }
+ } else if (kind == eRegisterKindDWARF) {
+ switch (reg) {
+ case dwarf_r0:
+ return gpr_r0;
+ case dwarf_r1:
+ return gpr_r1;
+ case dwarf_r2:
+ return gpr_r2;
+ case dwarf_r3:
+ return gpr_r3;
+ case dwarf_r4:
+ return gpr_r4;
+ case dwarf_r5:
+ return gpr_r5;
+ case dwarf_r6:
+ return gpr_r6;
+ case dwarf_r7:
+ return gpr_r7;
+ case dwarf_r8:
+ return gpr_r8;
+ case dwarf_r9:
+ return gpr_r9;
+ case dwarf_r10:
+ return gpr_r10;
+ case dwarf_r11:
+ return gpr_r11;
+ case dwarf_r12:
+ return gpr_r12;
+ case dwarf_sp:
+ return gpr_sp;
+ case dwarf_lr:
+ return gpr_lr;
+ case dwarf_pc:
+ return gpr_pc;
+ case dwarf_spsr:
+ return gpr_cpsr;
+
+ case dwarf_s0:
+ return fpu_s0;
+ case dwarf_s1:
+ return fpu_s1;
+ case dwarf_s2:
+ return fpu_s2;
+ case dwarf_s3:
+ return fpu_s3;
+ case dwarf_s4:
+ return fpu_s4;
+ case dwarf_s5:
+ return fpu_s5;
+ case dwarf_s6:
+ return fpu_s6;
+ case dwarf_s7:
+ return fpu_s7;
+ case dwarf_s8:
+ return fpu_s8;
+ case dwarf_s9:
+ return fpu_s9;
+ case dwarf_s10:
+ return fpu_s10;
+ case dwarf_s11:
+ return fpu_s11;
+ case dwarf_s12:
+ return fpu_s12;
+ case dwarf_s13:
+ return fpu_s13;
+ case dwarf_s14:
+ return fpu_s14;
+ case dwarf_s15:
+ return fpu_s15;
+ case dwarf_s16:
+ return fpu_s16;
+ case dwarf_s17:
+ return fpu_s17;
+ case dwarf_s18:
+ return fpu_s18;
+ case dwarf_s19:
+ return fpu_s19;
+ case dwarf_s20:
+ return fpu_s20;
+ case dwarf_s21:
+ return fpu_s21;
+ case dwarf_s22:
+ return fpu_s22;
+ case dwarf_s23:
+ return fpu_s23;
+ case dwarf_s24:
+ return fpu_s24;
+ case dwarf_s25:
+ return fpu_s25;
+ case dwarf_s26:
+ return fpu_s26;
+ case dwarf_s27:
+ return fpu_s27;
+ case dwarf_s28:
+ return fpu_s28;
+ case dwarf_s29:
+ return fpu_s29;
+ case dwarf_s30:
+ return fpu_s30;
+ case dwarf_s31:
+ return fpu_s31;
+
+ default:
+ break;
+ }
+ } else if (kind == eRegisterKindEHFrame) {
+ switch (reg) {
+ case ehframe_r0:
+ return gpr_r0;
+ case ehframe_r1:
+ return gpr_r1;
+ case ehframe_r2:
+ return gpr_r2;
+ case ehframe_r3:
+ return gpr_r3;
+ case ehframe_r4:
+ return gpr_r4;
+ case ehframe_r5:
+ return gpr_r5;
+ case ehframe_r6:
+ return gpr_r6;
+ case ehframe_r7:
+ return gpr_r7;
+ case ehframe_r8:
+ return gpr_r8;
+ case ehframe_r9:
+ return gpr_r9;
+ case ehframe_r10:
+ return gpr_r10;
+ case ehframe_r11:
+ return gpr_r11;
+ case ehframe_r12:
+ return gpr_r12;
+ case ehframe_sp:
+ return gpr_sp;
+ case ehframe_lr:
+ return gpr_lr;
+ case ehframe_pc:
+ return gpr_pc;
+ case ehframe_cpsr:
+ return gpr_cpsr;
+ }
+ } else if (kind == eRegisterKindLLDB) {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+uint32_t RegisterContextDarwin_arm::NumSupportedHardwareBreakpoints() {
+#if defined(__APPLE__) && defined(__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many breakpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_breakpoints = UINT32_MAX;
+ if (g_num_supported_hw_breakpoints == UINT32_MAX) {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_breakpoints = 0;
+
+ uint32_t register_DBGDIDR;
+
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR));
+ g_num_supported_hw_breakpoints = Bits32(register_DBGDIDR, 27, 24);
+ // Zero is reserved for the BRP count, so don't increment it if it is zero
+ if (g_num_supported_hw_breakpoints > 0)
+ g_num_supported_hw_breakpoints++;
+ }
+ return g_num_supported_hw_breakpoints;
+#else
+ // TODO: figure out remote case here!
+ return 6;
+#endif
+}
+
+uint32_t RegisterContextDarwin_arm::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ // Make sure our address isn't bogus
+ if (addr & 1)
+ return LLDB_INVALID_INDEX32;
+
+ int kret = ReadDBG(false);
+
+ if (kret == KERN_SUCCESS) {
+ const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints();
+ uint32_t i;
+ for (i = 0; i < num_hw_breakpoints; ++i) {
+ if ((dbg.bcr[i] & BCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_breakpoints) {
+ // Make sure bits 1:0 are clear in our address
+ dbg.bvr[i] = addr & ~((lldb::addr_t)3);
+
+ if (size == 2 || addr & 2) {
+ uint32_t byte_addr_select = (addr & 2) ? BAS_IMVA_2_3 : BAS_IMVA_0_1;
+
+ // We have a thumb breakpoint
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address match
+ byte_addr_select | // Set the correct byte address select
+ // so we only trigger on the correct
+ // opcode
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm::EnableHardwareBreakpoint(
+ // addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x /
+ // 0x%8.8x (Thumb)",
+ // addr,
+ // size,
+ // i,
+ // i,
+ // dbg.bvr[i],
+ // dbg.bcr[i]);
+ } else if (size == 4) {
+ // We have an ARM breakpoint
+ dbg.bcr[i] =
+ BCR_M_IMVA_MATCH | // Stop on address match
+ BAS_IMVA_ALL | // Stop on any of the four bytes following the IMVA
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm::EnableHardwareBreakpoint(
+ // addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x /
+ // 0x%8.8x (ARM)",
+ // addr,
+ // size,
+ // i,
+ // i,
+ // dbg.bvr[i],
+ // dbg.bcr[i]);
+ }
+
+ kret = WriteDBG();
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm::EnableHardwareBreakpoint()
+ // WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ // else
+ // {
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm::EnableHardwareBreakpoint(addr =
+ // %8.8p, size = %u) => all hardware breakpoint resources are
+ // being used.", addr, size);
+ // }
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool RegisterContextDarwin_arm::ClearHardwareBreakpoint(uint32_t hw_index) {
+ int kret = ReadDBG(false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareBreakpoints();
+ if (kret == KERN_SUCCESS) {
+ if (hw_index < num_hw_points) {
+ dbg.bcr[hw_index] = 0;
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm::SetHardwareBreakpoint( %u ) -
+ // BVR%u = 0x%8.8x BCR%u = 0x%8.8x",
+ // hw_index,
+ // hw_index,
+ // dbg.bvr[hw_index],
+ // hw_index,
+ // dbg.bcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t RegisterContextDarwin_arm::NumSupportedHardwareWatchpoints() {
+#if defined(__APPLE__) && defined(__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many watchpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX;
+ if (g_num_supported_hw_watchpoints == UINT32_MAX) {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_watchpoints = 0;
+
+ uint32_t register_DBGDIDR;
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR));
+ g_num_supported_hw_watchpoints = Bits32(register_DBGDIDR, 31, 28) + 1;
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+uint32_t RegisterContextDarwin_arm::SetHardwareWatchpoint(lldb::addr_t addr,
+ size_t size,
+ bool read,
+ bool write) {
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ // Can't watch zero bytes
+ if (size == 0)
+ return LLDB_INVALID_INDEX32;
+
+ // We must watch for either read or write
+ if (!read && !write)
+ return LLDB_INVALID_INDEX32;
+
+ // Can't watch more than 4 bytes per WVR/WCR pair
+ if (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. Since we have at most so we can only watch
+ // until the next 4 byte boundary and we need to make sure we can properly
+ // encode this.
+ uint32_t addr_word_offset = addr % 4;
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() -
+ // addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - byte_mask =
+ // 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Read the debug state
+ int kret = ReadDBG(false);
+
+ if (kret == KERN_SUCCESS) {
+ // Check to make sure we have the needed hardware support
+ uint32_t i = 0;
+
+ for (i = 0; i < num_hw_watchpoints; ++i) {
+ if ((dbg.wcr[i] & WCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_watchpoints) {
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t byte_address_select = byte_mask << 5;
+ // Make sure bits 1:0 are clear in our address
+ dbg.wvr[i] = addr & ~((lldb::addr_t)3);
+ dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA
+ // that we will watch
+ S_USER | // Stop only in user mode
+ (read ? WCR_LOAD : 0) | // Stop on read access?
+ (write ? WCR_STORE : 0) | // Stop on write access?
+ WCR_ENABLE; // Enable this watchpoint;
+
+ kret = WriteDBG();
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm::EnableHardwareWatchpoint()
+ // WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ } else {
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(): All
+ // hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool RegisterContextDarwin_arm::ClearHardwareWatchpoint(uint32_t hw_index) {
+ int kret = ReadDBG(false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
+ if (kret == KERN_SUCCESS) {
+ if (hw_index < num_hw_points) {
+ dbg.wcr[hw_index] = 0;
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm::ClearHardwareWatchpoint( %u ) -
+ // WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
+ // hw_index,
+ // hw_index,
+ // dbg.wvr[hw_index],
+ // hw_index,
+ // dbg.wcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
new file mode 100644
index 000000000000..7ff1bded81f4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
@@ -0,0 +1,264 @@
+//===-- RegisterContextDarwin_arm.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM_H
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+
+// BCR address match type
+#define BCR_M_IMVA_MATCH ((uint32_t)(0u << 21))
+#define BCR_M_CONTEXT_ID_MATCH ((uint32_t)(1u << 21))
+#define BCR_M_IMVA_MISMATCH ((uint32_t)(2u << 21))
+#define BCR_M_RESERVED ((uint32_t)(3u << 21))
+
+// Link a BVR/BCR or WVR/WCR pair to another
+#define E_ENABLE_LINKING ((uint32_t)(1u << 20))
+
+// Byte Address Select
+#define BAS_IMVA_PLUS_0 ((uint32_t)(1u << 5))
+#define BAS_IMVA_PLUS_1 ((uint32_t)(1u << 6))
+#define BAS_IMVA_PLUS_2 ((uint32_t)(1u << 7))
+#define BAS_IMVA_PLUS_3 ((uint32_t)(1u << 8))
+#define BAS_IMVA_0_1 ((uint32_t)(3u << 5))
+#define BAS_IMVA_2_3 ((uint32_t)(3u << 7))
+#define BAS_IMVA_ALL ((uint32_t)(0xfu << 5))
+
+// Break only in privileged or user mode
+#define S_RSVD ((uint32_t)(0u << 1))
+#define S_PRIV ((uint32_t)(1u << 1))
+#define S_USER ((uint32_t)(2u << 1))
+#define S_PRIV_USER ((S_PRIV) | (S_USER))
+
+#define BCR_ENABLE ((uint32_t)(1u))
+#define WCR_ENABLE ((uint32_t)(1u))
+
+// Watchpoint load/store
+#define WCR_LOAD ((uint32_t)(1u << 3))
+#define WCR_STORE ((uint32_t)(1u << 4))
+
+class RegisterContextDarwin_arm : public lldb_private::RegisterContext {
+public:
+ RegisterContextDarwin_arm(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ ~RegisterContextDarwin_arm() override;
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ 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;
+
+ struct GPR {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+ 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;
+ };
+
+ // struct NeonReg
+ // {
+ // uint8_t bytes[16];
+ // };
+ //
+ // struct VFPv3
+ // {
+ // union {
+ // uint32_t s[32];
+ // uint64_t d[32];
+ // NeonReg q[16];
+ // } v3;
+ // uint32_t fpscr;
+ // };
+
+ struct EXC {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ static void LogDBGRegisters(lldb_private::Log *log, const DBG &dbg);
+
+protected:
+ enum {
+ GPRRegSet = 1, // ARM_THREAD_STATE
+ GPRAltRegSet = 9, // ARM_THREAD_STATE32
+ FPURegSet = 2, // ARM_VFP_STATE
+ EXCRegSet = 3, // ARM_EXCEPTION_STATE
+ DBGRegSet = 4 // ARM_DEBUG_STATE
+ };
+
+ enum {
+ GPRWordCount = sizeof(GPR) / sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU) / sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC) / sizeof(uint32_t),
+ DBGWordCount = sizeof(DBG) / sizeof(uint32_t)
+ };
+
+ enum { Read = 0, Write = 1, kNumErrors = 2 };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ DBG dbg;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+ int dbg_errs[2]; // Read/Write errors
+
+ void InvalidateAllRegisterStates() {
+ SetError(GPRRegSet, Read, -1);
+ SetError(FPURegSet, Read, -1);
+ SetError(EXCRegSet, Read, -1);
+ }
+
+ int GetError(int flavor, uint32_t err_idx) const {
+ if (err_idx < kNumErrors) {
+ switch (flavor) {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet:
+ return gpr_errs[err_idx];
+ case FPURegSet:
+ return fpu_errs[err_idx];
+ case EXCRegSet:
+ return exc_errs[err_idx];
+ case DBGRegSet:
+ return dbg_errs[err_idx];
+ default:
+ break;
+ }
+ }
+ return -1;
+ }
+
+ bool SetError(int flavor, uint32_t err_idx, int err) {
+ if (err_idx < kNumErrors) {
+ switch (flavor) {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ case DBGRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default:
+ break;
+ }
+ }
+ return false;
+ }
+
+ bool RegisterSetIsCached(int set) const { return GetError(set, Read) == 0; }
+
+ int ReadGPR(bool force);
+
+ int ReadFPU(bool force);
+
+ int ReadEXC(bool force);
+
+ int ReadDBG(bool force);
+
+ int WriteGPR();
+
+ int WriteFPU();
+
+ int WriteEXC();
+
+ int WriteDBG();
+
+ // Subclasses override these to do the actual reading.
+ virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { return -1; }
+
+ virtual int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) = 0;
+
+ virtual int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ virtual int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) = 0;
+
+ int ReadRegisterSet(uint32_t set, bool force);
+
+ int WriteRegisterSet(uint32_t set);
+
+ static uint32_t GetRegisterNumber(uint32_t reg_kind, uint32_t reg_num);
+
+ static int GetSetForNativeRegNum(int reg_num);
+
+ static size_t GetRegisterInfosCount();
+
+ static const lldb_private::RegisterInfo *GetRegisterInfos();
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
new file mode 100644
index 000000000000..3bcd9a28e3f1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
@@ -0,0 +1,1041 @@
+//===-- RegisterContextDarwin_arm64.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextDarwin_arm64.h"
+#include "RegisterContextDarwinConstants.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+#include <memory>
+
+#if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__))
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
+#include "Utility/ARM64_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define GPR_OFFSET(idx) ((idx)*8)
+#define GPR_OFFSET_NAME(reg) \
+ (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::GPR, reg))
+
+#define FPU_OFFSET(idx) ((idx)*16 + sizeof(RegisterContextDarwin_arm64::GPR))
+#define FPU_OFFSET_NAME(reg) \
+ (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::FPU, reg))
+
+#define EXC_OFFSET_NAME(reg) \
+ (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::EXC, reg) + \
+ sizeof(RegisterContextDarwin_arm64::GPR) + \
+ sizeof(RegisterContextDarwin_arm64::FPU))
+#define DBG_OFFSET_NAME(reg) \
+ (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::DBG, reg) + \
+ sizeof(RegisterContextDarwin_arm64::GPR) + \
+ sizeof(RegisterContextDarwin_arm64::FPU) + \
+ sizeof(RegisterContextDarwin_arm64::EXC))
+
+#define DEFINE_DBG(reg, i) \
+ #reg, NULL, \
+ sizeof(((RegisterContextDarwin_arm64::DBG *) NULL)->reg[i]), \
+ DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM }, \
+ NULL, NULL, NULL
+#define REG_CONTEXT_SIZE \
+ (sizeof(RegisterContextDarwin_arm64::GPR) + \
+ sizeof(RegisterContextDarwin_arm64::FPU) + \
+ sizeof(RegisterContextDarwin_arm64::EXC))
+
+// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure.
+#define DECLARE_REGISTER_INFOS_ARM64_STRUCT
+#include "RegisterInfos_arm64.h"
+#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+// General purpose registers
+static uint32_t g_gpr_regnums[] = {
+ gpr_x0, gpr_x1, gpr_x2, gpr_x3, gpr_x4, gpr_x5, gpr_x6,
+ gpr_x7, gpr_x8, gpr_x9, gpr_x10, gpr_x11, gpr_x12, gpr_x13,
+ gpr_x14, gpr_x15, gpr_x16, gpr_x17, gpr_x18, gpr_x19, gpr_x20,
+ gpr_x21, gpr_x22, gpr_x23, gpr_x24, gpr_x25, gpr_x26, gpr_x27,
+ gpr_x28, gpr_fp, gpr_lr, gpr_sp, gpr_pc, gpr_cpsr};
+
+// Floating point registers
+static uint32_t g_fpu_regnums[] = {
+ fpu_v0, fpu_v1, fpu_v2, fpu_v3, fpu_v4, fpu_v5, fpu_v6,
+ fpu_v7, fpu_v8, fpu_v9, fpu_v10, fpu_v11, fpu_v12, fpu_v13,
+ fpu_v14, fpu_v15, fpu_v16, fpu_v17, fpu_v18, fpu_v19, fpu_v20,
+ fpu_v21, fpu_v22, fpu_v23, fpu_v24, fpu_v25, fpu_v26, fpu_v27,
+ fpu_v28, fpu_v29, fpu_v30, fpu_v31, fpu_fpsr, fpu_fpcr};
+
+// Exception registers
+
+static uint32_t g_exc_regnums[] = {exc_far, exc_esr, exc_exception};
+
+static size_t k_num_register_infos = std::size(g_register_infos_arm64_le);
+
+RegisterContextDarwin_arm64::RegisterContextDarwin_arm64(
+ Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc(), dbg() {
+ uint32_t i;
+ for (i = 0; i < kNumErrors; i++) {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64() = default;
+
+void RegisterContextDarwin_arm64::InvalidateAllRegisters() {
+ InvalidateAllRegisterStates();
+}
+
+size_t RegisterContextDarwin_arm64::GetRegisterCount() {
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm64::GetRegisterInfoAtIndex(size_t reg) {
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos_arm64_le[reg];
+ return nullptr;
+}
+
+size_t RegisterContextDarwin_arm64::GetRegisterInfosCount() {
+ return k_num_register_infos;
+}
+
+const RegisterInfo *RegisterContextDarwin_arm64::GetRegisterInfos() {
+ return g_register_infos_arm64_le;
+}
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = std::size(g_gpr_regnums);
+const size_t k_num_fpu_registers = std::size(g_fpu_regnums);
+const size_t k_num_exc_registers = std::size(g_exc_regnums);
+
+// Register set definitions. The first definitions at register set index of
+// zero is for all registers, followed by other registers sets. The register
+// information for the all register set need not be filled in.
+static const RegisterSet g_reg_sets[] = {
+ {
+ "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums,
+ },
+ {"Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums},
+ {"Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums}};
+
+const size_t k_num_regsets = std::size(g_reg_sets);
+
+size_t RegisterContextDarwin_arm64::GetRegisterSetCount() {
+ return k_num_regsets;
+}
+
+const RegisterSet *RegisterContextDarwin_arm64::GetRegisterSet(size_t reg_set) {
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return nullptr;
+}
+
+// Register information definitions for arm64
+int RegisterContextDarwin_arm64::GetSetForNativeRegNum(int reg) {
+ if (reg < fpu_v0)
+ return GPRRegSet;
+ else if (reg < exc_far)
+ return FPURegSet;
+ else if (reg < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+int RegisterContextDarwin_arm64::ReadGPR(bool force) {
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int RegisterContextDarwin_arm64::ReadFPU(bool force) {
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int RegisterContextDarwin_arm64::ReadEXC(bool force) {
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int RegisterContextDarwin_arm64::ReadDBG(bool force) {
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+int RegisterContextDarwin_arm64::WriteGPR() {
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError(set, Read, -1);
+ return GetError(GPRRegSet, Write);
+}
+
+int RegisterContextDarwin_arm64::WriteFPU() {
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError(set, Read, -1);
+ return GetError(FPURegSet, Write);
+}
+
+int RegisterContextDarwin_arm64::WriteEXC() {
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError(set, Read, -1);
+ return GetError(EXCRegSet, Write);
+}
+
+int RegisterContextDarwin_arm64::WriteDBG() {
+ int set = DBGRegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError(set, Write, DoWriteDBG(GetThreadID(), set, dbg));
+ SetError(set, Read, -1);
+ return GetError(DBGRegSet, Write);
+}
+
+int RegisterContextDarwin_arm64::ReadRegisterSet(uint32_t set, bool force) {
+ switch (set) {
+ case GPRRegSet:
+ return ReadGPR(force);
+ case FPURegSet:
+ return ReadFPU(force);
+ case EXCRegSet:
+ return ReadEXC(force);
+ case DBGRegSet:
+ return ReadDBG(force);
+ default:
+ break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+int RegisterContextDarwin_arm64::WriteRegisterSet(uint32_t set) {
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set)) {
+ switch (set) {
+ case GPRRegSet:
+ return WriteGPR();
+ case FPURegSet:
+ return WriteFPU();
+ case EXCRegSet:
+ return WriteEXC();
+ case DBGRegSet:
+ return WriteDBG();
+ default:
+ break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+void RegisterContextDarwin_arm64::LogDBGRegisters(Log *log, const DBG &dbg) {
+ if (log) {
+ for (uint32_t i = 0; i < 16; i++)
+ LLDB_LOGF(log,
+ "BVR%-2u/BCR%-2u = { 0x%8.8" PRIu64 ", 0x%8.8" PRIu64
+ " } WVR%-2u/WCR%-2u "
+ "= { 0x%8.8" PRIu64 ", 0x%8.8" PRIu64 " }",
+ i, i, dbg.bvr[i], dbg.bcr[i], i, i, dbg.wvr[i], dbg.wcr[i]);
+ }
+}
+
+bool RegisterContextDarwin_arm64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_arm64::GetSetForNativeRegNum(reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg) {
+ case gpr_x0:
+ case gpr_x1:
+ case gpr_x2:
+ case gpr_x3:
+ case gpr_x4:
+ case gpr_x5:
+ case gpr_x6:
+ case gpr_x7:
+ case gpr_x8:
+ case gpr_x9:
+ case gpr_x10:
+ case gpr_x11:
+ case gpr_x12:
+ case gpr_x13:
+ case gpr_x14:
+ case gpr_x15:
+ case gpr_x16:
+ case gpr_x17:
+ case gpr_x18:
+ case gpr_x19:
+ case gpr_x20:
+ case gpr_x21:
+ case gpr_x22:
+ case gpr_x23:
+ case gpr_x24:
+ case gpr_x25:
+ case gpr_x26:
+ case gpr_x27:
+ case gpr_x28:
+ value.SetUInt64(gpr.x[reg - gpr_x0]);
+ break;
+ case gpr_fp:
+ value.SetUInt64(gpr.fp);
+ break;
+ case gpr_sp:
+ value.SetUInt64(gpr.sp);
+ break;
+ case gpr_lr:
+ value.SetUInt64(gpr.lr);
+ break;
+ case gpr_pc:
+ value.SetUInt64(gpr.pc);
+ break;
+ case gpr_cpsr:
+ value.SetUInt64(gpr.cpsr);
+ break;
+
+ case gpr_w0:
+ case gpr_w1:
+ case gpr_w2:
+ case gpr_w3:
+ case gpr_w4:
+ case gpr_w5:
+ case gpr_w6:
+ case gpr_w7:
+ case gpr_w8:
+ case gpr_w9:
+ case gpr_w10:
+ case gpr_w11:
+ case gpr_w12:
+ case gpr_w13:
+ case gpr_w14:
+ case gpr_w15:
+ case gpr_w16:
+ case gpr_w17:
+ case gpr_w18:
+ case gpr_w19:
+ case gpr_w20:
+ case gpr_w21:
+ case gpr_w22:
+ case gpr_w23:
+ case gpr_w24:
+ case gpr_w25:
+ case gpr_w26:
+ case gpr_w27:
+ case gpr_w28: {
+ ProcessSP process_sp(m_thread.GetProcess());
+ if (process_sp.get()) {
+ DataExtractor regdata(&gpr.x[reg - gpr_w0], 8, process_sp->GetByteOrder(),
+ process_sp->GetAddressByteSize());
+ offset_t offset = 0;
+ uint64_t retval = regdata.GetMaxU64(&offset, 8);
+ uint32_t retval_lower32 = static_cast<uint32_t>(retval & 0xffffffff);
+ value.SetUInt32(retval_lower32);
+ }
+ } break;
+
+ case fpu_v0:
+ case fpu_v1:
+ case fpu_v2:
+ case fpu_v3:
+ case fpu_v4:
+ case fpu_v5:
+ case fpu_v6:
+ case fpu_v7:
+ case fpu_v8:
+ case fpu_v9:
+ case fpu_v10:
+ case fpu_v11:
+ case fpu_v12:
+ case fpu_v13:
+ case fpu_v14:
+ case fpu_v15:
+ case fpu_v16:
+ case fpu_v17:
+ case fpu_v18:
+ case fpu_v19:
+ case fpu_v20:
+ case fpu_v21:
+ case fpu_v22:
+ case fpu_v23:
+ case fpu_v24:
+ case fpu_v25:
+ case fpu_v26:
+ case fpu_v27:
+ case fpu_v28:
+ case fpu_v29:
+ case fpu_v30:
+ case fpu_v31:
+ value.SetBytes(fpu.v[reg - fpu_v0].bytes, reg_info->byte_size,
+ endian::InlHostByteOrder());
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31: {
+ ProcessSP process_sp(m_thread.GetProcess());
+ if (process_sp.get()) {
+ DataExtractor regdata(&fpu.v[reg - fpu_s0], 4, process_sp->GetByteOrder(),
+ process_sp->GetAddressByteSize());
+ offset_t offset = 0;
+ value.SetFloat(regdata.GetFloat(&offset));
+ }
+ } break;
+
+ case fpu_d0:
+ case fpu_d1:
+ case fpu_d2:
+ case fpu_d3:
+ case fpu_d4:
+ case fpu_d5:
+ case fpu_d6:
+ case fpu_d7:
+ case fpu_d8:
+ case fpu_d9:
+ case fpu_d10:
+ case fpu_d11:
+ case fpu_d12:
+ case fpu_d13:
+ case fpu_d14:
+ case fpu_d15:
+ case fpu_d16:
+ case fpu_d17:
+ case fpu_d18:
+ case fpu_d19:
+ case fpu_d20:
+ case fpu_d21:
+ case fpu_d22:
+ case fpu_d23:
+ case fpu_d24:
+ case fpu_d25:
+ case fpu_d26:
+ case fpu_d27:
+ case fpu_d28:
+ case fpu_d29:
+ case fpu_d30:
+ case fpu_d31: {
+ ProcessSP process_sp(m_thread.GetProcess());
+ if (process_sp.get()) {
+ DataExtractor regdata(&fpu.v[reg - fpu_d0], 8, process_sp->GetByteOrder(),
+ process_sp->GetAddressByteSize());
+ offset_t offset = 0;
+ value.SetDouble(regdata.GetDouble(&offset));
+ }
+ } break;
+
+ case fpu_fpsr:
+ value.SetUInt32(fpu.fpsr);
+ break;
+
+ case fpu_fpcr:
+ value.SetUInt32(fpu.fpcr);
+ break;
+
+ case exc_exception:
+ value.SetUInt32(exc.exception);
+ break;
+ case exc_esr:
+ value.SetUInt32(exc.esr);
+ break;
+ case exc_far:
+ value.SetUInt64(exc.far);
+ break;
+
+ default:
+ value.SetValueToInvalid();
+ return false;
+ }
+ return true;
+}
+
+bool RegisterContextDarwin_arm64::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum(reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg) {
+ case gpr_x0:
+ case gpr_x1:
+ case gpr_x2:
+ case gpr_x3:
+ case gpr_x4:
+ case gpr_x5:
+ case gpr_x6:
+ case gpr_x7:
+ case gpr_x8:
+ case gpr_x9:
+ case gpr_x10:
+ case gpr_x11:
+ case gpr_x12:
+ case gpr_x13:
+ case gpr_x14:
+ case gpr_x15:
+ case gpr_x16:
+ case gpr_x17:
+ case gpr_x18:
+ case gpr_x19:
+ case gpr_x20:
+ case gpr_x21:
+ case gpr_x22:
+ case gpr_x23:
+ case gpr_x24:
+ case gpr_x25:
+ case gpr_x26:
+ case gpr_x27:
+ case gpr_x28:
+ case gpr_fp:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ gpr.x[reg - gpr_x0] = value.GetAsUInt64();
+ break;
+
+ case fpu_v0:
+ case fpu_v1:
+ case fpu_v2:
+ case fpu_v3:
+ case fpu_v4:
+ case fpu_v5:
+ case fpu_v6:
+ case fpu_v7:
+ case fpu_v8:
+ case fpu_v9:
+ case fpu_v10:
+ case fpu_v11:
+ case fpu_v12:
+ case fpu_v13:
+ case fpu_v14:
+ case fpu_v15:
+ case fpu_v16:
+ case fpu_v17:
+ case fpu_v18:
+ case fpu_v19:
+ case fpu_v20:
+ case fpu_v21:
+ case fpu_v22:
+ case fpu_v23:
+ case fpu_v24:
+ case fpu_v25:
+ case fpu_v26:
+ case fpu_v27:
+ case fpu_v28:
+ case fpu_v29:
+ case fpu_v30:
+ case fpu_v31:
+ ::memcpy(fpu.v[reg - fpu_v0].bytes, value.GetBytes(),
+ value.GetByteSize());
+ break;
+
+ case fpu_fpsr:
+ fpu.fpsr = value.GetAsUInt32();
+ break;
+
+ case fpu_fpcr:
+ fpu.fpcr = value.GetAsUInt32();
+ break;
+
+ case exc_exception:
+ exc.exception = value.GetAsUInt32();
+ break;
+ case exc_esr:
+ exc.esr = value.GetAsUInt32();
+ break;
+ case exc_far:
+ exc.far = value.GetAsUInt64();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool RegisterContextDarwin_arm64::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ data_sp = std::make_shared<DataBufferHeap>(REG_CONTEXT_SIZE, 0);
+ if (ReadGPR(false) == KERN_SUCCESS && ReadFPU(false) == KERN_SUCCESS &&
+ ReadEXC(false) == KERN_SUCCESS) {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy(dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy(dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool RegisterContextDarwin_arm64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy(&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy(&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy(&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+uint32_t RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber(
+ RegisterKind kind, uint32_t reg) {
+ if (kind == eRegisterKindGeneric) {
+ switch (reg) {
+ case LLDB_REGNUM_GENERIC_PC:
+ return gpr_pc;
+ case LLDB_REGNUM_GENERIC_SP:
+ return gpr_sp;
+ case LLDB_REGNUM_GENERIC_FP:
+ return gpr_fp;
+ case LLDB_REGNUM_GENERIC_RA:
+ return gpr_lr;
+ case LLDB_REGNUM_GENERIC_FLAGS:
+ return gpr_cpsr;
+ default:
+ break;
+ }
+ } else if (kind == eRegisterKindDWARF) {
+ switch (reg) {
+ case arm64_dwarf::x0:
+ return gpr_x0;
+ case arm64_dwarf::x1:
+ return gpr_x1;
+ case arm64_dwarf::x2:
+ return gpr_x2;
+ case arm64_dwarf::x3:
+ return gpr_x3;
+ case arm64_dwarf::x4:
+ return gpr_x4;
+ case arm64_dwarf::x5:
+ return gpr_x5;
+ case arm64_dwarf::x6:
+ return gpr_x6;
+ case arm64_dwarf::x7:
+ return gpr_x7;
+ case arm64_dwarf::x8:
+ return gpr_x8;
+ case arm64_dwarf::x9:
+ return gpr_x9;
+ case arm64_dwarf::x10:
+ return gpr_x10;
+ case arm64_dwarf::x11:
+ return gpr_x11;
+ case arm64_dwarf::x12:
+ return gpr_x12;
+ case arm64_dwarf::x13:
+ return gpr_x13;
+ case arm64_dwarf::x14:
+ return gpr_x14;
+ case arm64_dwarf::x15:
+ return gpr_x15;
+ case arm64_dwarf::x16:
+ return gpr_x16;
+ case arm64_dwarf::x17:
+ return gpr_x17;
+ case arm64_dwarf::x18:
+ return gpr_x18;
+ case arm64_dwarf::x19:
+ return gpr_x19;
+ case arm64_dwarf::x20:
+ return gpr_x20;
+ case arm64_dwarf::x21:
+ return gpr_x21;
+ case arm64_dwarf::x22:
+ return gpr_x22;
+ case arm64_dwarf::x23:
+ return gpr_x23;
+ case arm64_dwarf::x24:
+ return gpr_x24;
+ case arm64_dwarf::x25:
+ return gpr_x25;
+ case arm64_dwarf::x26:
+ return gpr_x26;
+ case arm64_dwarf::x27:
+ return gpr_x27;
+ case arm64_dwarf::x28:
+ return gpr_x28;
+
+ case arm64_dwarf::fp:
+ return gpr_fp;
+ case arm64_dwarf::sp:
+ return gpr_sp;
+ case arm64_dwarf::lr:
+ return gpr_lr;
+ case arm64_dwarf::pc:
+ return gpr_pc;
+ case arm64_dwarf::cpsr:
+ return gpr_cpsr;
+
+ case arm64_dwarf::v0:
+ return fpu_v0;
+ case arm64_dwarf::v1:
+ return fpu_v1;
+ case arm64_dwarf::v2:
+ return fpu_v2;
+ case arm64_dwarf::v3:
+ return fpu_v3;
+ case arm64_dwarf::v4:
+ return fpu_v4;
+ case arm64_dwarf::v5:
+ return fpu_v5;
+ case arm64_dwarf::v6:
+ return fpu_v6;
+ case arm64_dwarf::v7:
+ return fpu_v7;
+ case arm64_dwarf::v8:
+ return fpu_v8;
+ case arm64_dwarf::v9:
+ return fpu_v9;
+ case arm64_dwarf::v10:
+ return fpu_v10;
+ case arm64_dwarf::v11:
+ return fpu_v11;
+ case arm64_dwarf::v12:
+ return fpu_v12;
+ case arm64_dwarf::v13:
+ return fpu_v13;
+ case arm64_dwarf::v14:
+ return fpu_v14;
+ case arm64_dwarf::v15:
+ return fpu_v15;
+ case arm64_dwarf::v16:
+ return fpu_v16;
+ case arm64_dwarf::v17:
+ return fpu_v17;
+ case arm64_dwarf::v18:
+ return fpu_v18;
+ case arm64_dwarf::v19:
+ return fpu_v19;
+ case arm64_dwarf::v20:
+ return fpu_v20;
+ case arm64_dwarf::v21:
+ return fpu_v21;
+ case arm64_dwarf::v22:
+ return fpu_v22;
+ case arm64_dwarf::v23:
+ return fpu_v23;
+ case arm64_dwarf::v24:
+ return fpu_v24;
+ case arm64_dwarf::v25:
+ return fpu_v25;
+ case arm64_dwarf::v26:
+ return fpu_v26;
+ case arm64_dwarf::v27:
+ return fpu_v27;
+ case arm64_dwarf::v28:
+ return fpu_v28;
+ case arm64_dwarf::v29:
+ return fpu_v29;
+ case arm64_dwarf::v30:
+ return fpu_v30;
+ case arm64_dwarf::v31:
+ return fpu_v31;
+
+ default:
+ break;
+ }
+ } else if (kind == eRegisterKindEHFrame) {
+ switch (reg) {
+ case arm64_ehframe::x0:
+ return gpr_x0;
+ case arm64_ehframe::x1:
+ return gpr_x1;
+ case arm64_ehframe::x2:
+ return gpr_x2;
+ case arm64_ehframe::x3:
+ return gpr_x3;
+ case arm64_ehframe::x4:
+ return gpr_x4;
+ case arm64_ehframe::x5:
+ return gpr_x5;
+ case arm64_ehframe::x6:
+ return gpr_x6;
+ case arm64_ehframe::x7:
+ return gpr_x7;
+ case arm64_ehframe::x8:
+ return gpr_x8;
+ case arm64_ehframe::x9:
+ return gpr_x9;
+ case arm64_ehframe::x10:
+ return gpr_x10;
+ case arm64_ehframe::x11:
+ return gpr_x11;
+ case arm64_ehframe::x12:
+ return gpr_x12;
+ case arm64_ehframe::x13:
+ return gpr_x13;
+ case arm64_ehframe::x14:
+ return gpr_x14;
+ case arm64_ehframe::x15:
+ return gpr_x15;
+ case arm64_ehframe::x16:
+ return gpr_x16;
+ case arm64_ehframe::x17:
+ return gpr_x17;
+ case arm64_ehframe::x18:
+ return gpr_x18;
+ case arm64_ehframe::x19:
+ return gpr_x19;
+ case arm64_ehframe::x20:
+ return gpr_x20;
+ case arm64_ehframe::x21:
+ return gpr_x21;
+ case arm64_ehframe::x22:
+ return gpr_x22;
+ case arm64_ehframe::x23:
+ return gpr_x23;
+ case arm64_ehframe::x24:
+ return gpr_x24;
+ case arm64_ehframe::x25:
+ return gpr_x25;
+ case arm64_ehframe::x26:
+ return gpr_x26;
+ case arm64_ehframe::x27:
+ return gpr_x27;
+ case arm64_ehframe::x28:
+ return gpr_x28;
+ case arm64_ehframe::fp:
+ return gpr_fp;
+ case arm64_ehframe::sp:
+ return gpr_sp;
+ case arm64_ehframe::lr:
+ return gpr_lr;
+ case arm64_ehframe::pc:
+ return gpr_pc;
+ case arm64_ehframe::cpsr:
+ return gpr_cpsr;
+ }
+ } else if (kind == eRegisterKindLLDB) {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+uint32_t RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints() {
+#if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__))
+ // autodetect how many watchpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX;
+ if (g_num_supported_hw_watchpoints == UINT32_MAX) {
+ size_t len;
+ uint32_t n = 0;
+ len = sizeof(n);
+ if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0) {
+ g_num_supported_hw_watchpoints = n;
+ }
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+uint32_t RegisterContextDarwin_arm64::SetHardwareWatchpoint(lldb::addr_t addr,
+ size_t size,
+ bool read,
+ bool write) {
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(addr = %8.8p,
+ // size = %u, read = %u, write = %u)", addr, size, read, write);
+
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ // Can't watch zero bytes
+ if (size == 0)
+ return LLDB_INVALID_INDEX32;
+
+ // We must watch for either read or write
+ if (!read && !write)
+ return LLDB_INVALID_INDEX32;
+
+ // Can't watch more than 4 bytes per WVR/WCR pair
+ if (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. Since we have at most so we can only watch
+ // until the next 4 byte boundary and we need to make sure we can properly
+ // encode this.
+ uint32_t addr_word_offset = addr % 4;
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() -
+ // addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - byte_mask =
+ // 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Read the debug state
+ int kret = ReadDBG(false);
+
+ if (kret == KERN_SUCCESS) {
+ // Check to make sure we have the needed hardware support
+ uint32_t i = 0;
+
+ for (i = 0; i < num_hw_watchpoints; ++i) {
+ if ((dbg.wcr[i] & WCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_watchpoints) {
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t byte_address_select = byte_mask << 5;
+ // Make sure bits 1:0 are clear in our address
+ dbg.wvr[i] = addr & ~((lldb::addr_t)3);
+ dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA
+ // that we will watch
+ S_USER | // Stop only in user mode
+ (read ? WCR_LOAD : 0) | // Stop on read access?
+ (write ? WCR_STORE : 0) | // Stop on write access?
+ WCR_ENABLE; // Enable this watchpoint;
+
+ kret = WriteDBG();
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint()
+ // WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ } else {
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint():
+ // All hardware resources (%u) are in use.",
+ // num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool RegisterContextDarwin_arm64::ClearHardwareWatchpoint(uint32_t hw_index) {
+ int kret = ReadDBG(false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
+ if (kret == KERN_SUCCESS) {
+ if (hw_index < num_hw_points) {
+ dbg.wcr[hw_index] = 0;
+ // if (log) log->Printf
+ // ("RegisterContextDarwin_arm64::ClearHardwareWatchpoint( %u )
+ // - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
+ // hw_index,
+ // hw_index,
+ // dbg.wvr[hw_index],
+ // hw_index,
+ // dbg.wcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h
new file mode 100644
index 000000000000..a0d7821ae9e8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h
@@ -0,0 +1,231 @@
+//===-- RegisterContextDarwin_arm64.h -----------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM64_H
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+
+// Break only in privileged or user mode
+#define S_RSVD ((uint32_t)(0u << 1))
+#define S_PRIV ((uint32_t)(1u << 1))
+#define S_USER ((uint32_t)(2u << 1))
+#define S_PRIV_USER ((S_PRIV) | (S_USER))
+
+#define WCR_ENABLE ((uint32_t)(1u))
+
+// Watchpoint load/store
+#define WCR_LOAD ((uint32_t)(1u << 3))
+#define WCR_STORE ((uint32_t)(1u << 4))
+
+class RegisterContextDarwin_arm64 : public lldb_private::RegisterContext {
+public:
+ RegisterContextDarwin_arm64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ ~RegisterContextDarwin_arm64() override;
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) 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;
+
+ // mirrors <mach/arm/thread_status.h> arm_thread_state64_t
+ struct GPR {
+ uint64_t x[29]; // x0-x28
+ uint64_t fp; // x29
+ uint64_t lr; // x30
+ uint64_t sp; // x31
+ uint64_t pc; // pc
+ uint32_t cpsr; // cpsr
+ };
+
+ struct VReg {
+ alignas(16) char bytes[16];
+ };
+
+ // mirrors <mach/arm/thread_status.h> arm_neon_state64_t
+ struct FPU {
+ VReg v[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ };
+
+ // mirrors <mach/arm/thread_status.h> arm_exception_state64_t
+ struct EXC {
+ uint64_t far; // Virtual Fault Address
+ uint32_t esr; // Exception syndrome
+ uint32_t exception; // number of arm exception token
+ };
+
+ // mirrors <mach/arm/thread_status.h> arm_debug_state64_t
+ struct DBG {
+ uint64_t bvr[16];
+ uint64_t bcr[16];
+ uint64_t wvr[16];
+ uint64_t wcr[16];
+ uint64_t mdscr_el1;
+ };
+
+ static void LogDBGRegisters(lldb_private::Log *log, const DBG &dbg);
+
+protected:
+ enum {
+ GPRRegSet = 6, // ARM_THREAD_STATE64
+ FPURegSet = 17, // ARM_NEON_STATE64
+ EXCRegSet = 7, // ARM_EXCEPTION_STATE64
+ DBGRegSet = 15 // ARM_DEBUG_STATE64
+ };
+
+ enum {
+ GPRWordCount = sizeof(GPR) / sizeof(uint32_t), // ARM_THREAD_STATE64_COUNT
+ FPUWordCount = sizeof(FPU) / sizeof(uint32_t), // ARM_NEON_STATE64_COUNT
+ EXCWordCount =
+ sizeof(EXC) / sizeof(uint32_t), // ARM_EXCEPTION_STATE64_COUNT
+ DBGWordCount = sizeof(DBG) / sizeof(uint32_t) // ARM_DEBUG_STATE64_COUNT
+ };
+
+ enum { Read = 0, Write = 1, kNumErrors = 2 };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ DBG dbg;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+ int dbg_errs[2]; // Read/Write errors
+
+ void InvalidateAllRegisterStates() {
+ SetError(GPRRegSet, Read, -1);
+ SetError(FPURegSet, Read, -1);
+ SetError(EXCRegSet, Read, -1);
+ }
+
+ int GetError(int flavor, uint32_t err_idx) const {
+ if (err_idx < kNumErrors) {
+ switch (flavor) {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet:
+ return gpr_errs[err_idx];
+ case FPURegSet:
+ return fpu_errs[err_idx];
+ case EXCRegSet:
+ return exc_errs[err_idx];
+ case DBGRegSet:
+ return dbg_errs[err_idx];
+ default:
+ break;
+ }
+ }
+ return -1;
+ }
+
+ bool SetError(int flavor, uint32_t err_idx, int err) {
+ if (err_idx < kNumErrors) {
+ switch (flavor) {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ case DBGRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default:
+ break;
+ }
+ }
+ return false;
+ }
+
+ bool RegisterSetIsCached(int set) const { return GetError(set, Read) == 0; }
+
+ int ReadGPR(bool force);
+
+ int ReadFPU(bool force);
+
+ int ReadEXC(bool force);
+
+ int ReadDBG(bool force);
+
+ int WriteGPR();
+
+ int WriteFPU();
+
+ int WriteEXC();
+
+ int WriteDBG();
+
+ // Subclasses override these to do the actual reading.
+ virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { return -1; }
+
+ virtual int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) = 0;
+
+ virtual int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ virtual int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) = 0;
+
+ int ReadRegisterSet(uint32_t set, bool force);
+
+ int WriteRegisterSet(uint32_t set);
+
+ static uint32_t GetRegisterNumber(uint32_t reg_kind, uint32_t reg_num);
+
+ static int GetSetForNativeRegNum(int reg_num);
+
+ static size_t GetRegisterInfosCount();
+
+ static const lldb_private::RegisterInfo *GetRegisterInfos();
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
new file mode 100644
index 000000000000..bae34af43a92
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
@@ -0,0 +1,963 @@
+//===-- RegisterContextDarwin_i386.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+
+#include <cstddef>
+
+#include <memory>
+
+#include "RegisterContextDarwin_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum {
+ gpr_eax = 0,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum {
+ ehframe_eax = 0,
+ ehframe_ecx,
+ ehframe_edx,
+ ehframe_ebx,
+ ehframe_ebp,
+ ehframe_esp,
+ ehframe_esi,
+ ehframe_edi,
+ ehframe_eip,
+ ehframe_eflags
+};
+
+enum {
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+ dwarf_eflags,
+ dwarf_stmm0 = 11,
+ dwarf_stmm1,
+ dwarf_stmm2,
+ dwarf_stmm3,
+ dwarf_stmm4,
+ dwarf_stmm5,
+ dwarf_stmm6,
+ dwarf_stmm7,
+ dwarf_xmm0 = 21,
+ dwarf_xmm1,
+ dwarf_xmm2,
+ dwarf_xmm3,
+ dwarf_xmm4,
+ dwarf_xmm5,
+ dwarf_xmm6,
+ dwarf_xmm7
+};
+
+#define GPR_OFFSET(reg) \
+ (LLVM_EXTENSION offsetof(RegisterContextDarwin_i386::GPR, reg))
+#define FPU_OFFSET(reg) \
+ (LLVM_EXTENSION offsetof(RegisterContextDarwin_i386::FPU, reg) + \
+ sizeof(RegisterContextDarwin_i386::GPR))
+#define EXC_OFFSET(reg) \
+ (LLVM_EXTENSION offsetof(RegisterContextDarwin_i386::EXC, reg) + \
+ sizeof(RegisterContextDarwin_i386::GPR) + \
+ sizeof(RegisterContextDarwin_i386::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that the
+// register state structures are defined correctly and have the correct sizes
+// and offsets.
+#define DEFINE_GPR(reg, alt) \
+ #reg, alt, sizeof(((RegisterContextDarwin_i386::GPR *) NULL)->reg), \
+ GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) \
+ #reg, NULL, sizeof(((RegisterContextDarwin_i386::FPU *) NULL)->reg), \
+ FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) \
+ #reg #i, NULL, \
+ sizeof(((RegisterContextDarwin_i386::FPU *) NULL)->reg[i].bytes), \
+ FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, \
+ {LLDB_INVALID_REGNUM, dwarf_##reg##i, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ fpu_##reg##i }, \
+ nullptr, nullptr, nullptr,
+
+#define DEFINE_EXC(reg) \
+ #reg, NULL, sizeof(((RegisterContextDarwin_i386::EXC *) NULL)->reg), \
+ EXC_OFFSET(reg), eEncodingUint, eFormatHex
+#define REG_CONTEXT_SIZE \
+ (sizeof(RegisterContextDarwin_i386::GPR) + \
+ sizeof(RegisterContextDarwin_i386::FPU) + \
+ sizeof(RegisterContextDarwin_i386::EXC))
+
+static RegisterInfo g_register_infos[] = {
+ // Macro auto defines most stuff eh_frame DWARF
+ // GENERIC PROCESS PLUGIN LLDB
+ // =============================== =======================
+ // =================== ========================= ==================
+ // =================
+ {DEFINE_GPR(eax, nullptr),
+ {ehframe_eax, dwarf_eax, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_eax},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(ebx, nullptr),
+ {ehframe_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_ebx},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(ecx, nullptr),
+ {ehframe_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_ecx},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(edx, nullptr),
+ {ehframe_edx, dwarf_edx, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_edx},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(edi, nullptr),
+ {ehframe_edi, dwarf_edi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_edi},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(esi, nullptr),
+ {ehframe_esi, dwarf_esi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_esi},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(ebp, "fp"),
+ {ehframe_ebp, dwarf_ebp, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM,
+ gpr_ebp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(esp, "sp"),
+ {ehframe_esp, dwarf_esp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM,
+ gpr_esp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(ss, nullptr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_ss},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(eflags, "flags"),
+ {ehframe_eflags, dwarf_eflags, LLDB_REGNUM_GENERIC_FLAGS,
+ LLDB_INVALID_REGNUM, gpr_eflags},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(eip, "pc"),
+ {ehframe_eip, dwarf_eip, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM,
+ gpr_eip},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(cs, nullptr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_cs},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(ds, nullptr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_ds},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(es, nullptr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_es},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(fs, nullptr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_fs},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(gs, nullptr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_gs},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+
+ {DEFINE_FPU_UINT(fcw),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_fcw},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(fsw),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_fsw},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(ftw),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_ftw},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(fop),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_fop},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(ip),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_ip},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(cs),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_cs},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(dp),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_dp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(ds),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_ds},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(mxcsr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_mxcsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(mxcsrmask),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_mxcsrmask},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_VECT(stmm, 0)},
+ {DEFINE_FPU_VECT(stmm, 1)},
+ {DEFINE_FPU_VECT(stmm, 2)},
+ {DEFINE_FPU_VECT(stmm, 3)},
+ {DEFINE_FPU_VECT(stmm, 4)},
+ {DEFINE_FPU_VECT(stmm, 5)},
+ {DEFINE_FPU_VECT(stmm, 6)},
+ {DEFINE_FPU_VECT(stmm, 7)},
+ {DEFINE_FPU_VECT(xmm, 0)},
+ {DEFINE_FPU_VECT(xmm, 1)},
+ {DEFINE_FPU_VECT(xmm, 2)},
+ {DEFINE_FPU_VECT(xmm, 3)},
+ {DEFINE_FPU_VECT(xmm, 4)},
+ {DEFINE_FPU_VECT(xmm, 5)},
+ {DEFINE_FPU_VECT(xmm, 6)},
+ {DEFINE_FPU_VECT(xmm, 7)},
+
+ {DEFINE_EXC(trapno),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_trapno},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_EXC(err),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_err},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_EXC(faultvaddr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_faultvaddr},
+ nullptr,
+ nullptr,
+ nullptr,
+ }};
+
+static size_t k_num_register_infos = std::size(g_register_infos);
+
+RegisterContextDarwin_i386::RegisterContextDarwin_i386(
+ Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc() {
+ uint32_t i;
+ for (i = 0; i < kNumErrors; i++) {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_i386::~RegisterContextDarwin_i386() = default;
+
+void RegisterContextDarwin_i386::InvalidateAllRegisters() {
+ InvalidateAllRegisterStates();
+}
+
+size_t RegisterContextDarwin_i386::GetRegisterCount() {
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_i386::GetRegisterInfoAtIndex(size_t reg) {
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return nullptr;
+}
+
+size_t RegisterContextDarwin_i386::GetRegisterInfosCount() {
+ return k_num_register_infos;
+}
+
+const RegisterInfo *RegisterContextDarwin_i386::GetRegisterInfos() {
+ return g_register_infos;
+}
+
+// General purpose registers
+static uint32_t g_gpr_regnums[] = {
+ gpr_eax, gpr_ebx, gpr_ecx, gpr_edx, gpr_edi, gpr_esi, gpr_ebp, gpr_esp,
+ gpr_ss, gpr_eflags, gpr_eip, gpr_cs, gpr_ds, gpr_es, gpr_fs, gpr_gs};
+
+// Floating point registers
+static uint32_t g_fpu_regnums[] = {
+ fpu_fcw, fpu_fsw, fpu_ftw, fpu_fop, fpu_ip, fpu_cs,
+ fpu_dp, fpu_ds, fpu_mxcsr, fpu_mxcsrmask, fpu_stmm0, fpu_stmm1,
+ fpu_stmm2, fpu_stmm3, fpu_stmm4, fpu_stmm5, fpu_stmm6, fpu_stmm7,
+ fpu_xmm0, fpu_xmm1, fpu_xmm2, fpu_xmm3, fpu_xmm4, fpu_xmm5,
+ fpu_xmm6, fpu_xmm7};
+
+// Exception registers
+
+static uint32_t g_exc_regnums[] = {exc_trapno, exc_err, exc_faultvaddr};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = std::size(g_gpr_regnums);
+const size_t k_num_fpu_registers = std::size(g_fpu_regnums);
+const size_t k_num_exc_registers = std::size(g_exc_regnums);
+
+// Register set definitions. The first definitions at register set index of
+// zero is for all registers, followed by other registers sets. The register
+// information for the all register set need not be filled in.
+static const RegisterSet g_reg_sets[] = {
+ {
+ "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums,
+ },
+ {"Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums},
+ {"Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums}};
+
+const size_t k_num_regsets = std::size(g_reg_sets);
+
+size_t RegisterContextDarwin_i386::GetRegisterSetCount() {
+ return k_num_regsets;
+}
+
+const RegisterSet *RegisterContextDarwin_i386::GetRegisterSet(size_t reg_set) {
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return nullptr;
+}
+
+// Register information definitions for 32 bit i386.
+int RegisterContextDarwin_i386::GetSetForNativeRegNum(int reg_num) {
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+void RegisterContextDarwin_i386::LogGPR(Log *log, const char *title) {
+ if (log) {
+ if (title)
+ LLDB_LOGF(log, "%s", title);
+ for (uint32_t i = 0; i < k_num_gpr_registers; i++) {
+ uint32_t reg = gpr_eax + i;
+ LLDB_LOGF(log, "%12s = 0x%8.8x", g_register_infos[reg].name,
+ (&gpr.eax)[reg]);
+ }
+ }
+}
+
+int RegisterContextDarwin_i386::ReadGPR(bool force) {
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(set, Read);
+}
+
+int RegisterContextDarwin_i386::ReadFPU(bool force) {
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(set, Read);
+}
+
+int RegisterContextDarwin_i386::ReadEXC(bool force) {
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(set, Read);
+}
+
+int RegisterContextDarwin_i386::WriteGPR() {
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return -1;
+ }
+ SetError(set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError(set, Read, -1);
+ return GetError(set, Write);
+}
+
+int RegisterContextDarwin_i386::WriteFPU() {
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return -1;
+ }
+ SetError(set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError(set, Read, -1);
+ return GetError(set, Write);
+}
+
+int RegisterContextDarwin_i386::WriteEXC() {
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return -1;
+ }
+ SetError(set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError(set, Read, -1);
+ return GetError(set, Write);
+}
+
+int RegisterContextDarwin_i386::ReadRegisterSet(uint32_t set, bool force) {
+ switch (set) {
+ case GPRRegSet:
+ return ReadGPR(force);
+ case FPURegSet:
+ return ReadFPU(force);
+ case EXCRegSet:
+ return ReadEXC(force);
+ default:
+ break;
+ }
+ return -1;
+}
+
+int RegisterContextDarwin_i386::WriteRegisterSet(uint32_t set) {
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set)) {
+ switch (set) {
+ case GPRRegSet:
+ return WriteGPR();
+ case FPURegSet:
+ return WriteFPU();
+ case EXCRegSet:
+ return WriteEXC();
+ default:
+ break;
+ }
+ }
+ return -1;
+}
+
+bool RegisterContextDarwin_i386::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_i386::GetSetForNativeRegNum(reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg) {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.eax)[reg - gpr_eax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types,
+ // RegisterContext::ReadRegisterBytes() must be used for these registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes,
+ //10);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types,
+ // RegisterContext::ReadRegisterBytes() must be used for these registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.xmm[reg - fpu_xmm0].bytes,
+ //16);
+ return false;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool RegisterContextDarwin_i386::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum(reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg) {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.eax)[reg - gpr_eax] = value.GetAsUInt32();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types,
+ // RegisterContext::ReadRegisterBytes() must be used for these registers
+ ::memcpy(fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(),
+ value.GetByteSize());
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types,
+ // RegisterContext::ReadRegisterBytes() must be used for these registers
+ ::memcpy(fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(),
+ value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool RegisterContextDarwin_i386::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ data_sp = std::make_shared<DataBufferHeap>(REG_CONTEXT_SIZE, 0);
+ if (ReadGPR(false) == 0 && ReadFPU(false) == 0 && ReadEXC(false) == 0) {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy(dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy(dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool RegisterContextDarwin_i386::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy(&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy(&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy(&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+uint32_t RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t reg) {
+ if (kind == eRegisterKindGeneric) {
+ switch (reg) {
+ case LLDB_REGNUM_GENERIC_PC:
+ return gpr_eip;
+ case LLDB_REGNUM_GENERIC_SP:
+ return gpr_esp;
+ case LLDB_REGNUM_GENERIC_FP:
+ return gpr_ebp;
+ case LLDB_REGNUM_GENERIC_FLAGS:
+ return gpr_eflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ } else if (kind == eRegisterKindEHFrame || kind == eRegisterKindDWARF) {
+ switch (reg) {
+ case dwarf_eax:
+ return gpr_eax;
+ case dwarf_ecx:
+ return gpr_ecx;
+ case dwarf_edx:
+ return gpr_edx;
+ case dwarf_ebx:
+ return gpr_ebx;
+ case dwarf_esp:
+ return gpr_esp;
+ case dwarf_ebp:
+ return gpr_ebp;
+ case dwarf_esi:
+ return gpr_esi;
+ case dwarf_edi:
+ return gpr_edi;
+ case dwarf_eip:
+ return gpr_eip;
+ case dwarf_eflags:
+ return gpr_eflags;
+ case dwarf_stmm0:
+ return fpu_stmm0;
+ case dwarf_stmm1:
+ return fpu_stmm1;
+ case dwarf_stmm2:
+ return fpu_stmm2;
+ case dwarf_stmm3:
+ return fpu_stmm3;
+ case dwarf_stmm4:
+ return fpu_stmm4;
+ case dwarf_stmm5:
+ return fpu_stmm5;
+ case dwarf_stmm6:
+ return fpu_stmm6;
+ case dwarf_stmm7:
+ return fpu_stmm7;
+ case dwarf_xmm0:
+ return fpu_xmm0;
+ case dwarf_xmm1:
+ return fpu_xmm1;
+ case dwarf_xmm2:
+ return fpu_xmm2;
+ case dwarf_xmm3:
+ return fpu_xmm3;
+ case dwarf_xmm4:
+ return fpu_xmm4;
+ case dwarf_xmm5:
+ return fpu_xmm5;
+ case dwarf_xmm6:
+ return fpu_xmm6;
+ case dwarf_xmm7:
+ return fpu_xmm7;
+ default:
+ break;
+ }
+ } else if (kind == eRegisterKindLLDB) {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+bool RegisterContextDarwin_i386::HardwareSingleStep(bool enable) {
+ if (ReadGPR(false) != 0)
+ return false;
+
+ const uint32_t trace_bit = 0x100u;
+ if (enable) {
+ // If the trace bit is already set, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ return true;
+ else
+ gpr.eflags |= trace_bit;
+ } else {
+ // If the trace bit is already cleared, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ gpr.eflags &= ~trace_bit;
+ else
+ return true;
+ }
+
+ return WriteGPR() == 0;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
new file mode 100644
index 000000000000..be933f3be266
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
@@ -0,0 +1,208 @@
+//===-- RegisterContextDarwin_i386.h ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_I386_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_I386_H
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+
+class RegisterContextDarwin_i386 : public lldb_private::RegisterContext {
+public:
+ RegisterContextDarwin_i386(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ ~RegisterContextDarwin_i386() override;
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ bool HardwareSingleStep(bool enable) override;
+
+ struct GPR {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ss;
+ uint32_t eflags;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ };
+
+ struct MMSReg {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg {
+ uint8_t bytes[16];
+ };
+
+ struct FPU {
+ uint32_t pad[2];
+ uint16_t fcw;
+ uint16_t fsw;
+ uint8_t ftw;
+ uint8_t pad1;
+ uint16_t fop;
+ uint32_t ip;
+ uint16_t cs;
+ uint16_t pad2;
+ uint32_t dp;
+ uint16_t ds;
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[8];
+ uint8_t pad4[14 * 16];
+ int pad5;
+ };
+
+ struct EXC {
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t faultvaddr;
+ };
+
+protected:
+ enum { GPRRegSet = 1, FPURegSet = 2, EXCRegSet = 3 };
+
+ enum {
+ GPRWordCount = sizeof(GPR) / sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU) / sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC) / sizeof(uint32_t)
+ };
+
+ enum { Read = 0, Write = 1, kNumErrors = 2 };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+
+ void InvalidateAllRegisterStates() {
+ SetError(GPRRegSet, Read, -1);
+ SetError(FPURegSet, Read, -1);
+ SetError(EXCRegSet, Read, -1);
+ }
+
+ int GetError(int flavor, uint32_t err_idx) const {
+ if (err_idx < kNumErrors) {
+ switch (flavor) {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet:
+ return gpr_errs[err_idx];
+ case FPURegSet:
+ return fpu_errs[err_idx];
+ case EXCRegSet:
+ return exc_errs[err_idx];
+ default:
+ break;
+ }
+ }
+ return -1;
+ }
+
+ bool SetError(int flavor, uint32_t err_idx, int err) {
+ if (err_idx < kNumErrors) {
+ switch (flavor) {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default:
+ break;
+ }
+ }
+ return false;
+ }
+
+ bool RegisterSetIsCached(int set) const { return GetError(set, Read) == 0; }
+
+ void LogGPR(lldb_private::Log *log, const char *title);
+
+ int ReadGPR(bool force);
+
+ int ReadFPU(bool force);
+
+ int ReadEXC(bool force);
+
+ int WriteGPR();
+
+ int WriteFPU();
+
+ int WriteEXC();
+
+ // Subclasses override these to do the actual reading.
+ virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ virtual int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ int ReadRegisterSet(uint32_t set, bool force);
+
+ int WriteRegisterSet(uint32_t set);
+
+ static uint32_t GetRegisterNumber(uint32_t reg_kind, uint32_t reg_num);
+
+ static int GetSetForNativeRegNum(int reg_num);
+
+ static size_t GetRegisterInfosCount();
+
+ static const lldb_private::RegisterInfo *GetRegisterInfos();
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_I386_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
new file mode 100644
index 000000000000..08d84e827090
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
@@ -0,0 +1,1056 @@
+//===-- RegisterContextDarwin_x86_64.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cinttypes>
+#include <cstdarg>
+#include <cstddef>
+
+#include <memory>
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextDarwin_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum {
+ gpr_rax = 0,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum ehframe_dwarf_regnums {
+ ehframe_dwarf_gpr_rax = 0,
+ ehframe_dwarf_gpr_rdx,
+ ehframe_dwarf_gpr_rcx,
+ ehframe_dwarf_gpr_rbx,
+ ehframe_dwarf_gpr_rsi,
+ ehframe_dwarf_gpr_rdi,
+ ehframe_dwarf_gpr_rbp,
+ ehframe_dwarf_gpr_rsp,
+ ehframe_dwarf_gpr_r8,
+ ehframe_dwarf_gpr_r9,
+ ehframe_dwarf_gpr_r10,
+ ehframe_dwarf_gpr_r11,
+ ehframe_dwarf_gpr_r12,
+ ehframe_dwarf_gpr_r13,
+ ehframe_dwarf_gpr_r14,
+ ehframe_dwarf_gpr_r15,
+ ehframe_dwarf_gpr_rip,
+ ehframe_dwarf_fpu_xmm0,
+ ehframe_dwarf_fpu_xmm1,
+ ehframe_dwarf_fpu_xmm2,
+ ehframe_dwarf_fpu_xmm3,
+ ehframe_dwarf_fpu_xmm4,
+ ehframe_dwarf_fpu_xmm5,
+ ehframe_dwarf_fpu_xmm6,
+ ehframe_dwarf_fpu_xmm7,
+ ehframe_dwarf_fpu_xmm8,
+ ehframe_dwarf_fpu_xmm9,
+ ehframe_dwarf_fpu_xmm10,
+ ehframe_dwarf_fpu_xmm11,
+ ehframe_dwarf_fpu_xmm12,
+ ehframe_dwarf_fpu_xmm13,
+ ehframe_dwarf_fpu_xmm14,
+ ehframe_dwarf_fpu_xmm15,
+ ehframe_dwarf_fpu_stmm0,
+ ehframe_dwarf_fpu_stmm1,
+ ehframe_dwarf_fpu_stmm2,
+ ehframe_dwarf_fpu_stmm3,
+ ehframe_dwarf_fpu_stmm4,
+ ehframe_dwarf_fpu_stmm5,
+ ehframe_dwarf_fpu_stmm6,
+ ehframe_dwarf_fpu_stmm7
+
+};
+
+#define GPR_OFFSET(reg) \
+ (LLVM_EXTENSION offsetof(RegisterContextDarwin_x86_64::GPR, reg))
+#define FPU_OFFSET(reg) \
+ (LLVM_EXTENSION offsetof(RegisterContextDarwin_x86_64::FPU, reg) + \
+ sizeof(RegisterContextDarwin_x86_64::GPR))
+#define EXC_OFFSET(reg) \
+ (LLVM_EXTENSION offsetof(RegisterContextDarwin_x86_64::EXC, reg) + \
+ sizeof(RegisterContextDarwin_x86_64::GPR) + \
+ sizeof(RegisterContextDarwin_x86_64::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that the
+// register state structures are defined correctly and have the correct sizes
+// and offsets.
+#define DEFINE_GPR(reg, alt) \
+ #reg, alt, sizeof(((RegisterContextDarwin_x86_64::GPR *) NULL)->reg), \
+ GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) \
+ #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *) NULL)->reg), \
+ FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) \
+ #reg #i, NULL, \
+ sizeof(((RegisterContextDarwin_x86_64::FPU *) NULL)->reg[i].bytes), \
+ FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, \
+ {ehframe_dwarf_fpu_##reg##i, \
+ ehframe_dwarf_fpu_##reg##i, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, fpu_##reg##i }, \
+ nullptr, nullptr, nullptr,
+#define DEFINE_EXC(reg) \
+ #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::EXC *) NULL)->reg), \
+ EXC_OFFSET(reg), eEncodingUint, eFormatHex
+
+#define REG_CONTEXT_SIZE \
+ (sizeof(RegisterContextDarwin_x86_64::GPR) + \
+ sizeof(RegisterContextDarwin_x86_64::FPU) + \
+ sizeof(RegisterContextDarwin_x86_64::EXC))
+
+// General purpose registers for 64 bit
+static RegisterInfo g_register_infos[] = {
+ // Macro auto defines most stuff EH_FRAME DWARF
+ // GENERIC PROCESS PLUGIN LLDB
+ // =============================== ======================
+ // =================== ========================== ====================
+ // ===================
+ {DEFINE_GPR(rax, nullptr),
+ {ehframe_dwarf_gpr_rax, ehframe_dwarf_gpr_rax, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_rax},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(rbx, nullptr),
+ {ehframe_dwarf_gpr_rbx, ehframe_dwarf_gpr_rbx, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_rbx},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(rcx, nullptr),
+ {ehframe_dwarf_gpr_rcx, ehframe_dwarf_gpr_rcx, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_rcx},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(rdx, nullptr),
+ {ehframe_dwarf_gpr_rdx, ehframe_dwarf_gpr_rdx, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_rdx},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(rdi, nullptr),
+ {ehframe_dwarf_gpr_rdi, ehframe_dwarf_gpr_rdi, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_rdi},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(rsi, nullptr),
+ {ehframe_dwarf_gpr_rsi, ehframe_dwarf_gpr_rsi, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_rsi},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(rbp, "fp"),
+ {ehframe_dwarf_gpr_rbp, ehframe_dwarf_gpr_rbp, LLDB_REGNUM_GENERIC_FP,
+ LLDB_INVALID_REGNUM, gpr_rbp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(rsp, "sp"),
+ {ehframe_dwarf_gpr_rsp, ehframe_dwarf_gpr_rsp, LLDB_REGNUM_GENERIC_SP,
+ LLDB_INVALID_REGNUM, gpr_rsp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(r8, nullptr),
+ {ehframe_dwarf_gpr_r8, ehframe_dwarf_gpr_r8, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_r8},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(r9, nullptr),
+ {ehframe_dwarf_gpr_r9, ehframe_dwarf_gpr_r9, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_r9},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(r10, nullptr),
+ {ehframe_dwarf_gpr_r10, ehframe_dwarf_gpr_r10, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_r10},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(r11, nullptr),
+ {ehframe_dwarf_gpr_r11, ehframe_dwarf_gpr_r11, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_r11},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(r12, nullptr),
+ {ehframe_dwarf_gpr_r12, ehframe_dwarf_gpr_r12, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_r12},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(r13, nullptr),
+ {ehframe_dwarf_gpr_r13, ehframe_dwarf_gpr_r13, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_r13},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(r14, nullptr),
+ {ehframe_dwarf_gpr_r14, ehframe_dwarf_gpr_r14, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_r14},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(r15, nullptr),
+ {ehframe_dwarf_gpr_r15, ehframe_dwarf_gpr_r15, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_r15},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(rip, "pc"),
+ {ehframe_dwarf_gpr_rip, ehframe_dwarf_gpr_rip, LLDB_REGNUM_GENERIC_PC,
+ LLDB_INVALID_REGNUM, gpr_rip},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(rflags, "flags"),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS,
+ LLDB_INVALID_REGNUM, gpr_rflags},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(cs, nullptr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_cs},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(fs, nullptr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_fs},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_GPR(gs, nullptr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, gpr_gs},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+
+ {DEFINE_FPU_UINT(fcw),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_fcw},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(fsw),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_fsw},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(ftw),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_ftw},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(fop),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_fop},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(ip),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_ip},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(cs),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_cs},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(dp),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_dp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(ds),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_ds},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(mxcsr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_mxcsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_UINT(mxcsrmask),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_mxcsrmask},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_FPU_VECT(stmm, 0)},
+ {DEFINE_FPU_VECT(stmm, 1)},
+ {DEFINE_FPU_VECT(stmm, 2)},
+ {DEFINE_FPU_VECT(stmm, 3)},
+ {DEFINE_FPU_VECT(stmm, 4)},
+ {DEFINE_FPU_VECT(stmm, 5)},
+ {DEFINE_FPU_VECT(stmm, 6)},
+ {DEFINE_FPU_VECT(stmm, 7)},
+ {DEFINE_FPU_VECT(xmm, 0)},
+ {DEFINE_FPU_VECT(xmm, 1)},
+ {DEFINE_FPU_VECT(xmm, 2)},
+ {DEFINE_FPU_VECT(xmm, 3)},
+ {DEFINE_FPU_VECT(xmm, 4)},
+ {DEFINE_FPU_VECT(xmm, 5)},
+ {DEFINE_FPU_VECT(xmm, 6)},
+ {DEFINE_FPU_VECT(xmm, 7)},
+ {DEFINE_FPU_VECT(xmm, 8)},
+ {DEFINE_FPU_VECT(xmm, 9)},
+ {DEFINE_FPU_VECT(xmm, 10)},
+ {DEFINE_FPU_VECT(xmm, 11)},
+ {DEFINE_FPU_VECT(xmm, 12)},
+ {DEFINE_FPU_VECT(xmm, 13)},
+ {DEFINE_FPU_VECT(xmm, 14)},
+ {DEFINE_FPU_VECT(xmm, 15)},
+
+ {DEFINE_EXC(trapno),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_trapno},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_EXC(err),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_err},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {DEFINE_EXC(faultvaddr),
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_faultvaddr},
+ nullptr,
+ nullptr,
+ nullptr,
+ }};
+
+static size_t k_num_register_infos = std::size(g_register_infos);
+
+RegisterContextDarwin_x86_64::RegisterContextDarwin_x86_64(
+ Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc() {
+ uint32_t i;
+ for (i = 0; i < kNumErrors; i++) {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_x86_64::~RegisterContextDarwin_x86_64() = default;
+
+void RegisterContextDarwin_x86_64::InvalidateAllRegisters() {
+ InvalidateAllRegisterStates();
+}
+
+size_t RegisterContextDarwin_x86_64::GetRegisterCount() {
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_x86_64::GetRegisterInfoAtIndex(size_t reg) {
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return nullptr;
+}
+
+size_t RegisterContextDarwin_x86_64::GetRegisterInfosCount() {
+ return k_num_register_infos;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDarwin_x86_64::GetRegisterInfos() {
+ return g_register_infos;
+}
+
+static uint32_t g_gpr_regnums[] = {
+ gpr_rax, gpr_rbx, gpr_rcx, gpr_rdx, gpr_rdi, gpr_rsi, gpr_rbp,
+ gpr_rsp, gpr_r8, gpr_r9, gpr_r10, gpr_r11, gpr_r12, gpr_r13,
+ gpr_r14, gpr_r15, gpr_rip, gpr_rflags, gpr_cs, gpr_fs, gpr_gs};
+
+static uint32_t g_fpu_regnums[] = {
+ fpu_fcw, fpu_fsw, fpu_ftw, fpu_fop, fpu_ip, fpu_cs,
+ fpu_dp, fpu_ds, fpu_mxcsr, fpu_mxcsrmask, fpu_stmm0, fpu_stmm1,
+ fpu_stmm2, fpu_stmm3, fpu_stmm4, fpu_stmm5, fpu_stmm6, fpu_stmm7,
+ fpu_xmm0, fpu_xmm1, fpu_xmm2, fpu_xmm3, fpu_xmm4, fpu_xmm5,
+ fpu_xmm6, fpu_xmm7, fpu_xmm8, fpu_xmm9, fpu_xmm10, fpu_xmm11,
+ fpu_xmm12, fpu_xmm13, fpu_xmm14, fpu_xmm15};
+
+static uint32_t g_exc_regnums[] = {exc_trapno, exc_err, exc_faultvaddr};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = std::size(g_gpr_regnums);
+const size_t k_num_fpu_registers = std::size(g_fpu_regnums);
+const size_t k_num_exc_registers = std::size(g_exc_regnums);
+
+// Register set definitions. The first definitions at register set index of
+// zero is for all registers, followed by other registers sets. The register
+// information for the all register set need not be filled in.
+static const RegisterSet g_reg_sets[] = {
+ {
+ "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums,
+ },
+ {"Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums},
+ {"Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums}};
+
+const size_t k_num_regsets = std::size(g_reg_sets);
+
+size_t RegisterContextDarwin_x86_64::GetRegisterSetCount() {
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_x86_64::GetRegisterSet(size_t reg_set) {
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return nullptr;
+}
+
+int RegisterContextDarwin_x86_64::GetSetForNativeRegNum(int reg_num) {
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+int RegisterContextDarwin_x86_64::ReadGPR(bool force) {
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int RegisterContextDarwin_x86_64::ReadFPU(bool force) {
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int RegisterContextDarwin_x86_64::ReadEXC(bool force) {
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set)) {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int RegisterContextDarwin_x86_64::WriteGPR() {
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return -1;
+ }
+ SetError(set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError(set, Read, -1);
+ return GetError(set, Write);
+}
+
+int RegisterContextDarwin_x86_64::WriteFPU() {
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return -1;
+ }
+ SetError(set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError(set, Read, -1);
+ return GetError(set, Write);
+}
+
+int RegisterContextDarwin_x86_64::WriteEXC() {
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set)) {
+ SetError(set, Write, -1);
+ return -1;
+ }
+ SetError(set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError(set, Read, -1);
+ return GetError(set, Write);
+}
+
+int RegisterContextDarwin_x86_64::ReadRegisterSet(uint32_t set, bool force) {
+ switch (set) {
+ case GPRRegSet:
+ return ReadGPR(force);
+ case FPURegSet:
+ return ReadFPU(force);
+ case EXCRegSet:
+ return ReadEXC(force);
+ default:
+ break;
+ }
+ return -1;
+}
+
+int RegisterContextDarwin_x86_64::WriteRegisterSet(uint32_t set) {
+ // Make sure we have a valid context to set.
+ switch (set) {
+ case GPRRegSet:
+ return WriteGPR();
+ case FPURegSet:
+ return WriteFPU();
+ case EXCRegSet:
+ return WriteEXC();
+ default:
+ break;
+ }
+ return -1;
+}
+
+bool RegisterContextDarwin_x86_64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum(reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg) {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.rax)[reg - gpr_rax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ value.SetBytes(fpu.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size,
+ endian::InlHostByteOrder());
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ value.SetBytes(fpu.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size,
+ endian::InlHostByteOrder());
+ break;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool RegisterContextDarwin_x86_64::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum(reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg) {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.rax)[reg - gpr_rax] = value.GetAsUInt64();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ ::memcpy(fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(),
+ value.GetByteSize());
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ ::memcpy(fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(),
+ value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt64();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool RegisterContextDarwin_x86_64::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ data_sp = std::make_shared<DataBufferHeap>(REG_CONTEXT_SIZE, 0);
+ if (ReadGPR(false) == 0 && ReadFPU(false) == 0 && ReadEXC(false) == 0) {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy(dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy(dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool RegisterContextDarwin_x86_64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy(&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy(&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy(&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+uint32_t RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t reg) {
+ if (kind == eRegisterKindGeneric) {
+ switch (reg) {
+ case LLDB_REGNUM_GENERIC_PC:
+ return gpr_rip;
+ case LLDB_REGNUM_GENERIC_SP:
+ return gpr_rsp;
+ case LLDB_REGNUM_GENERIC_FP:
+ return gpr_rbp;
+ case LLDB_REGNUM_GENERIC_FLAGS:
+ return gpr_rflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ } else if (kind == eRegisterKindEHFrame || kind == eRegisterKindDWARF) {
+ switch (reg) {
+ case ehframe_dwarf_gpr_rax:
+ return gpr_rax;
+ case ehframe_dwarf_gpr_rdx:
+ return gpr_rdx;
+ case ehframe_dwarf_gpr_rcx:
+ return gpr_rcx;
+ case ehframe_dwarf_gpr_rbx:
+ return gpr_rbx;
+ case ehframe_dwarf_gpr_rsi:
+ return gpr_rsi;
+ case ehframe_dwarf_gpr_rdi:
+ return gpr_rdi;
+ case ehframe_dwarf_gpr_rbp:
+ return gpr_rbp;
+ case ehframe_dwarf_gpr_rsp:
+ return gpr_rsp;
+ case ehframe_dwarf_gpr_r8:
+ return gpr_r8;
+ case ehframe_dwarf_gpr_r9:
+ return gpr_r9;
+ case ehframe_dwarf_gpr_r10:
+ return gpr_r10;
+ case ehframe_dwarf_gpr_r11:
+ return gpr_r11;
+ case ehframe_dwarf_gpr_r12:
+ return gpr_r12;
+ case ehframe_dwarf_gpr_r13:
+ return gpr_r13;
+ case ehframe_dwarf_gpr_r14:
+ return gpr_r14;
+ case ehframe_dwarf_gpr_r15:
+ return gpr_r15;
+ case ehframe_dwarf_gpr_rip:
+ return gpr_rip;
+ case ehframe_dwarf_fpu_xmm0:
+ return fpu_xmm0;
+ case ehframe_dwarf_fpu_xmm1:
+ return fpu_xmm1;
+ case ehframe_dwarf_fpu_xmm2:
+ return fpu_xmm2;
+ case ehframe_dwarf_fpu_xmm3:
+ return fpu_xmm3;
+ case ehframe_dwarf_fpu_xmm4:
+ return fpu_xmm4;
+ case ehframe_dwarf_fpu_xmm5:
+ return fpu_xmm5;
+ case ehframe_dwarf_fpu_xmm6:
+ return fpu_xmm6;
+ case ehframe_dwarf_fpu_xmm7:
+ return fpu_xmm7;
+ case ehframe_dwarf_fpu_xmm8:
+ return fpu_xmm8;
+ case ehframe_dwarf_fpu_xmm9:
+ return fpu_xmm9;
+ case ehframe_dwarf_fpu_xmm10:
+ return fpu_xmm10;
+ case ehframe_dwarf_fpu_xmm11:
+ return fpu_xmm11;
+ case ehframe_dwarf_fpu_xmm12:
+ return fpu_xmm12;
+ case ehframe_dwarf_fpu_xmm13:
+ return fpu_xmm13;
+ case ehframe_dwarf_fpu_xmm14:
+ return fpu_xmm14;
+ case ehframe_dwarf_fpu_xmm15:
+ return fpu_xmm15;
+ case ehframe_dwarf_fpu_stmm0:
+ return fpu_stmm0;
+ case ehframe_dwarf_fpu_stmm1:
+ return fpu_stmm1;
+ case ehframe_dwarf_fpu_stmm2:
+ return fpu_stmm2;
+ case ehframe_dwarf_fpu_stmm3:
+ return fpu_stmm3;
+ case ehframe_dwarf_fpu_stmm4:
+ return fpu_stmm4;
+ case ehframe_dwarf_fpu_stmm5:
+ return fpu_stmm5;
+ case ehframe_dwarf_fpu_stmm6:
+ return fpu_stmm6;
+ case ehframe_dwarf_fpu_stmm7:
+ return fpu_stmm7;
+ default:
+ break;
+ }
+ } else if (kind == eRegisterKindLLDB) {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+bool RegisterContextDarwin_x86_64::HardwareSingleStep(bool enable) {
+ if (ReadGPR(true) != 0)
+ return false;
+
+ const uint64_t trace_bit = 0x100ull;
+ if (enable) {
+
+ if (gpr.rflags & trace_bit)
+ return true; // trace bit is already set, there is nothing to do
+ else
+ gpr.rflags |= trace_bit;
+ } else {
+ if (gpr.rflags & trace_bit)
+ gpr.rflags &= ~trace_bit;
+ else
+ return true; // trace bit is clear, there is nothing to do
+ }
+
+ return WriteGPR() == 0;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
new file mode 100644
index 000000000000..a132f92d4d49
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
@@ -0,0 +1,213 @@
+//===-- RegisterContextDarwin_x86_64.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_X86_64_H
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+
+class RegisterContextDarwin_x86_64 : public lldb_private::RegisterContext {
+public:
+ RegisterContextDarwin_x86_64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ ~RegisterContextDarwin_x86_64() override;
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ bool HardwareSingleStep(bool enable) override;
+
+ struct GPR {
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rsp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t rip;
+ uint64_t rflags;
+ uint64_t cs;
+ uint64_t fs;
+ uint64_t gs;
+ };
+
+ struct MMSReg {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg {
+ uint8_t bytes[16];
+ };
+
+ struct FPU {
+ uint32_t pad[2];
+ uint16_t fcw; // "fctrl"
+ uint16_t fsw; // "fstat"
+ uint8_t ftw; // "ftag"
+ uint8_t pad1;
+ uint16_t fop; // "fop"
+ uint32_t ip; // "fioff"
+ uint16_t cs; // "fiseg"
+ uint16_t pad2;
+ uint32_t dp; // "fooff"
+ uint16_t ds; // "foseg"
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[16];
+ uint8_t pad4[6 * 16];
+ int pad5;
+ };
+
+ struct EXC {
+ uint32_t trapno;
+ uint32_t err;
+ uint64_t faultvaddr;
+ };
+
+protected:
+ enum { GPRRegSet = 4, FPURegSet = 5, EXCRegSet = 6 };
+
+ enum {
+ GPRWordCount = sizeof(GPR) / sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU) / sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC) / sizeof(uint32_t)
+ };
+
+ enum { Read = 0, Write = 1, kNumErrors = 2 };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+
+ void InvalidateAllRegisterStates() {
+ SetError(GPRRegSet, Read, -1);
+ SetError(FPURegSet, Read, -1);
+ SetError(EXCRegSet, Read, -1);
+ }
+
+ int GetError(int flavor, uint32_t err_idx) const {
+ if (err_idx < kNumErrors) {
+ switch (flavor) {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet:
+ return gpr_errs[err_idx];
+ case FPURegSet:
+ return fpu_errs[err_idx];
+ case EXCRegSet:
+ return exc_errs[err_idx];
+ default:
+ break;
+ }
+ }
+ return -1;
+ }
+
+ bool SetError(int flavor, uint32_t err_idx, int err) {
+ if (err_idx < kNumErrors) {
+ switch (flavor) {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default:
+ break;
+ }
+ }
+ return false;
+ }
+
+ bool RegisterSetIsCached(int set) const { return GetError(set, Read) == 0; }
+
+ void LogGPR(lldb_private::Log *log, const char *format, ...);
+
+ int ReadGPR(bool force);
+
+ int ReadFPU(bool force);
+
+ int ReadEXC(bool force);
+
+ int WriteGPR();
+
+ int WriteFPU();
+
+ int WriteEXC();
+
+ // Subclasses override these to do the actual reading.
+ virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ virtual int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ int ReadRegisterSet(uint32_t set, bool force);
+
+ int WriteRegisterSet(uint32_t set);
+
+ static uint32_t GetRegisterNumber(uint32_t reg_kind, uint32_t reg_num);
+
+ static int GetSetForNativeRegNum(int reg_num);
+
+ static size_t GetRegisterInfosCount();
+
+ static const lldb_private::RegisterInfo *GetRegisterInfos();
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_X86_64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp
new file mode 100644
index 000000000000..f41aa2ca599e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp
@@ -0,0 +1,120 @@
+//===-- RegisterContextDummy.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/DynamicLoader.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"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/lldb-private.h"
+
+#include "RegisterContextDummy.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextDummy::RegisterContextDummy(Thread &thread,
+ uint32_t concrete_frame_idx,
+ uint32_t address_byte_size)
+ : RegisterContext(thread, concrete_frame_idx) {
+ m_reg_set0.name = "General Purpose Registers";
+ m_reg_set0.short_name = "GPR";
+ m_reg_set0.num_registers = 1;
+ m_reg_set0.registers = new uint32_t(0);
+
+ m_pc_reg_info.name = "pc";
+ m_pc_reg_info.alt_name = "pc";
+ m_pc_reg_info.byte_offset = 0;
+ m_pc_reg_info.byte_size = address_byte_size;
+ m_pc_reg_info.encoding = eEncodingUint;
+ m_pc_reg_info.format = eFormatPointer;
+ m_pc_reg_info.invalidate_regs = nullptr;
+ m_pc_reg_info.value_regs = nullptr;
+ m_pc_reg_info.kinds[eRegisterKindEHFrame] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ m_pc_reg_info.kinds[eRegisterKindProcessPlugin] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindLLDB] = LLDB_INVALID_REGNUM;
+}
+
+RegisterContextDummy::~RegisterContextDummy() {
+ delete m_reg_set0.registers;
+ delete m_pc_reg_info.invalidate_regs;
+ delete m_pc_reg_info.value_regs;
+}
+
+void RegisterContextDummy::InvalidateAllRegisters() {}
+
+size_t RegisterContextDummy::GetRegisterCount() { return 1; }
+
+const lldb_private::RegisterInfo *
+RegisterContextDummy::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg)
+ return nullptr;
+ return &m_pc_reg_info;
+}
+
+size_t RegisterContextDummy::GetRegisterSetCount() { return 1; }
+
+const lldb_private::RegisterSet *
+RegisterContextDummy::GetRegisterSet(size_t reg_set) {
+ if (reg_set)
+ return nullptr;
+ return &m_reg_set0;
+}
+
+bool RegisterContextDummy::ReadRegister(
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) {
+ if (!reg_info)
+ return false;
+ uint32_t reg_number = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_number == LLDB_REGNUM_GENERIC_PC) {
+ value.SetUInt(LLDB_INVALID_ADDRESS, reg_info->byte_size);
+ return true;
+ }
+ return false;
+}
+
+bool RegisterContextDummy::WriteRegister(
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) {
+ return false;
+}
+
+bool RegisterContextDummy::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextDummy::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ return false;
+}
+
+uint32_t RegisterContextDummy::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC)
+ return 0;
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h
new file mode 100644
index 000000000000..631ad30b16a8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h
@@ -0,0 +1,65 @@
+//===-- RegisterContextDummy.h ----------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDUMMY_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDUMMY_H
+
+#include <vector>
+
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class RegisterContextDummy : public lldb_private::RegisterContext {
+public:
+ typedef std::shared_ptr<RegisterContextDummy> SharedPtr;
+
+ RegisterContextDummy(Thread &thread, uint32_t concrete_frame_idx,
+ uint32_t address_byte_size);
+
+ ~RegisterContextDummy() override;
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t reg_set) override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+private:
+ // For RegisterContextLLDB only
+
+ lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only)
+ lldb_private::RegisterInfo m_pc_reg_info;
+
+ RegisterContextDummy(const RegisterContextDummy &) = delete;
+ const RegisterContextDummy &operator=(const RegisterContextDummy &) = delete;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDUMMY_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
new file mode 100644
index 000000000000..df6a82c11255
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
@@ -0,0 +1,83 @@
+//===-- RegisterContextFreeBSD_i386.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSD_i386.h"
+#include "RegisterContextPOSIX_x86.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// http://svnweb.freebsd.org/base/head/sys/x86/include/reg.h
+struct GPR {
+ uint32_t fs;
+ uint32_t es;
+ uint32_t ds;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t isp;
+ uint32_t ebx;
+ uint32_t edx;
+ uint32_t ecx;
+ uint32_t eax;
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+ uint32_t esp;
+ uint32_t ss;
+ uint32_t gs;
+};
+
+struct DBG {
+ uint32_t dr[8]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+};
+
+using FPR_i386 = FXSAVE;
+
+struct UserArea {
+ GPR gpr;
+ FPR_i386 i387;
+ DBG dbg;
+};
+
+#define DR_SIZE sizeof(uint32_t)
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, dbg) + \
+ LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
+
+// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure.
+#define DECLARE_REGISTER_INFOS_I386_STRUCT
+#include "RegisterInfos_i386.h"
+#undef DECLARE_REGISTER_INFOS_I386_STRUCT
+
+RegisterContextFreeBSD_i386::RegisterContextFreeBSD_i386(
+ const ArchSpec &target_arch)
+ : RegisterInfoInterface(target_arch) {}
+
+size_t RegisterContextFreeBSD_i386::GetGPRSize() const { return sizeof(GPR); }
+
+const RegisterInfo *RegisterContextFreeBSD_i386::GetRegisterInfo() const {
+ switch (GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ return g_register_infos_i386;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+uint32_t RegisterContextFreeBSD_i386::GetRegisterCount() const {
+ return static_cast<uint32_t>(sizeof(g_register_infos_i386) /
+ sizeof(g_register_infos_i386[0]));
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h
new file mode 100644
index 000000000000..5a3e5b0551d6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h
@@ -0,0 +1,25 @@
+//===-- RegisterContextFreeBSD_i386.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_I386_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_I386_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextFreeBSD_i386 : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextFreeBSD_i386(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
new file mode 100644
index 000000000000..1f52c09df12e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
@@ -0,0 +1,179 @@
+//===-- RegisterContextFreeBSD_mips64.cpp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSD_mips64.h"
+#include "RegisterContextPOSIX_mips64.h"
+#include "lldb-mips-freebsd-register-enums.h"
+#include <vector>
+
+using namespace lldb_private;
+using namespace lldb;
+
+static 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_ic_mips64, gpr_dummy_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");
+
+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,
+ 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");
+
+// Number of register sets provided by this context.
+constexpr size_t k_num_register_sets = 2;
+
+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},
+};
+
+// http://svnweb.freebsd.org/base/head/sys/mips/include/regnum.h
+typedef struct _GPR {
+ uint64_t zero;
+ uint64_t r1;
+ uint64_t r2;
+ uint64_t r3;
+ uint64_t r4;
+ uint64_t r5;
+ uint64_t r6;
+ uint64_t r7;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t r16;
+ uint64_t r17;
+ uint64_t r18;
+ uint64_t r19;
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+ uint64_t gp;
+ uint64_t sp;
+ uint64_t r30;
+ uint64_t ra;
+ uint64_t sr;
+ uint64_t mullo;
+ uint64_t mulhi;
+ uint64_t badvaddr;
+ uint64_t cause;
+ uint64_t pc;
+ uint64_t ic;
+ uint64_t dummy;
+} GPR_freebsd_mips;
+
+typedef struct _FPR {
+ uint64_t f0;
+ uint64_t f1;
+ uint64_t f2;
+ uint64_t f3;
+ uint64_t f4;
+ uint64_t f5;
+ uint64_t f6;
+ uint64_t f7;
+ uint64_t f8;
+ uint64_t f9;
+ uint64_t f10;
+ uint64_t f11;
+ uint64_t f12;
+ uint64_t f13;
+ uint64_t f14;
+ uint64_t f15;
+ uint64_t f16;
+ uint64_t f17;
+ uint64_t f18;
+ uint64_t f19;
+ uint64_t f20;
+ uint64_t f21;
+ uint64_t f22;
+ uint64_t f23;
+ uint64_t f24;
+ uint64_t f25;
+ uint64_t f26;
+ uint64_t f27;
+ uint64_t f28;
+ uint64_t f29;
+ uint64_t f30;
+ uint64_t f31;
+ uint64_t fcsr;
+ uint64_t fir;
+} FPR_freebsd_mips;
+
+// Include RegisterInfos_mips64 to declare our g_register_infos_mips64
+// structure.
+#define DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+#include "RegisterInfos_mips64.h"
+#undef DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+
+RegisterContextFreeBSD_mips64::RegisterContextFreeBSD_mips64(
+ const ArchSpec &target_arch)
+ : RegisterInfoInterface(target_arch) {}
+
+size_t RegisterContextFreeBSD_mips64::GetGPRSize() const {
+ return sizeof(GPR_freebsd_mips);
+}
+
+const RegisterSet *
+RegisterContextFreeBSD_mips64::GetRegisterSet(size_t set) const {
+ // Check if RegisterSet is available
+ if (set < k_num_register_sets)
+ return &g_reg_sets_mips64[set];
+ return nullptr;
+}
+
+size_t RegisterContextFreeBSD_mips64::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
+const RegisterInfo *RegisterContextFreeBSD_mips64::GetRegisterInfo() const {
+ assert(GetTargetArchitecture().GetCore() == ArchSpec::eCore_mips64);
+ return g_register_infos_mips64;
+}
+
+uint32_t RegisterContextFreeBSD_mips64::GetRegisterCount() const {
+ return static_cast<uint32_t>(sizeof(g_register_infos_mips64) /
+ sizeof(g_register_infos_mips64[0]));
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
new file mode 100644
index 000000000000..39968eacf475
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
@@ -0,0 +1,30 @@
+//===-- RegisterContextFreeBSD_mips64.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_MIPS64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_MIPS64_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextFreeBSD_mips64
+ : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextFreeBSD_mips64(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) const;
+
+ size_t GetRegisterSetCount() const;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp
new file mode 100644
index 000000000000..d8dfa434335b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp
@@ -0,0 +1,233 @@
+//===-- RegisterContextFreeBSD_powerpc.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSD_powerpc.h"
+#include "RegisterContextPOSIX_powerpc.h"
+#include <vector>
+
+using namespace lldb_private;
+using namespace lldb;
+
+// http://svnweb.freebsd.org/base/head/sys/powerpc/include/reg.h
+typedef struct _GPR64 {
+ uint64_t r0;
+ uint64_t r1;
+ uint64_t r2;
+ uint64_t r3;
+ uint64_t r4;
+ uint64_t r5;
+ uint64_t r6;
+ uint64_t r7;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t r16;
+ uint64_t r17;
+ uint64_t r18;
+ uint64_t r19;
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+ uint64_t r28;
+ uint64_t r29;
+ uint64_t r30;
+ uint64_t r31;
+ uint64_t lr;
+ uint64_t cr;
+ uint64_t xer;
+ uint64_t ctr;
+ uint64_t pc;
+} GPR64;
+
+typedef struct _GPR32 {
+ uint32_t r0;
+ uint32_t r1;
+ uint32_t r2;
+ uint32_t r3;
+ uint32_t r4;
+ uint32_t r5;
+ uint32_t r6;
+ uint32_t r7;
+ uint32_t r8;
+ uint32_t r9;
+ uint32_t r10;
+ uint32_t r11;
+ uint32_t r12;
+ uint32_t r13;
+ uint32_t r14;
+ uint32_t r15;
+ uint32_t r16;
+ uint32_t r17;
+ uint32_t r18;
+ uint32_t r19;
+ uint32_t r20;
+ uint32_t r21;
+ uint32_t r22;
+ uint32_t r23;
+ uint32_t r24;
+ uint32_t r25;
+ uint32_t r26;
+ uint32_t r27;
+ uint32_t r28;
+ uint32_t r29;
+ uint32_t r30;
+ uint32_t r31;
+ uint32_t lr;
+ uint32_t cr;
+ uint32_t xer;
+ uint32_t ctr;
+ uint32_t pc;
+} GPR32;
+
+typedef struct _FPR {
+ uint64_t f0;
+ uint64_t f1;
+ uint64_t f2;
+ uint64_t f3;
+ uint64_t f4;
+ uint64_t f5;
+ uint64_t f6;
+ uint64_t f7;
+ uint64_t f8;
+ uint64_t f9;
+ uint64_t f10;
+ uint64_t f11;
+ uint64_t f12;
+ uint64_t f13;
+ uint64_t f14;
+ uint64_t f15;
+ uint64_t f16;
+ uint64_t f17;
+ uint64_t f18;
+ uint64_t f19;
+ uint64_t f20;
+ uint64_t f21;
+ uint64_t f22;
+ uint64_t f23;
+ uint64_t f24;
+ uint64_t f25;
+ uint64_t f26;
+ uint64_t f27;
+ uint64_t f28;
+ uint64_t f29;
+ uint64_t f30;
+ uint64_t f31;
+ uint64_t fpscr;
+} FPR;
+
+typedef struct _VMX {
+ uint32_t v0[4];
+ uint32_t v1[4];
+ uint32_t v2[4];
+ uint32_t v3[4];
+ uint32_t v4[4];
+ uint32_t v5[4];
+ uint32_t v6[4];
+ uint32_t v7[4];
+ uint32_t v8[4];
+ uint32_t v9[4];
+ uint32_t v10[4];
+ uint32_t v11[4];
+ uint32_t v12[4];
+ uint32_t v13[4];
+ uint32_t v14[4];
+ uint32_t v15[4];
+ uint32_t v16[4];
+ uint32_t v17[4];
+ uint32_t v18[4];
+ uint32_t v19[4];
+ uint32_t v20[4];
+ uint32_t v21[4];
+ uint32_t v22[4];
+ uint32_t v23[4];
+ uint32_t v24[4];
+ uint32_t v25[4];
+ uint32_t v26[4];
+ uint32_t v27[4];
+ uint32_t v28[4];
+ uint32_t v29[4];
+ uint32_t v30[4];
+ uint32_t v31[4];
+ uint32_t pad[2];
+ uint32_t vrsave;
+ uint32_t vscr;
+} VMX;
+
+// Include RegisterInfos_powerpc to declare our g_register_infos_powerpc
+// structure.
+#define DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+#include "RegisterInfos_powerpc.h"
+#undef DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+
+RegisterContextFreeBSD_powerpc::RegisterContextFreeBSD_powerpc(
+ const ArchSpec &target_arch)
+ : RegisterInfoInterface(target_arch) {}
+
+RegisterContextFreeBSD_powerpc::~RegisterContextFreeBSD_powerpc() = default;
+
+size_t RegisterContextFreeBSD_powerpc::GetGPRSize() const {
+ // This is an 'abstract' base, so no GPR struct.
+ return 0;
+}
+
+const RegisterInfo *RegisterContextFreeBSD_powerpc::GetRegisterInfo() const {
+ llvm_unreachable("Abstract class!");
+ return nullptr;
+}
+
+uint32_t RegisterContextFreeBSD_powerpc::GetRegisterCount() const { return 0; }
+
+RegisterContextFreeBSD_powerpc32::RegisterContextFreeBSD_powerpc32(
+ const ArchSpec &target_arch)
+ : RegisterContextFreeBSD_powerpc(target_arch) {}
+
+RegisterContextFreeBSD_powerpc32::~RegisterContextFreeBSD_powerpc32() = default;
+
+size_t RegisterContextFreeBSD_powerpc32::GetGPRSize() const {
+ return sizeof(GPR32);
+}
+
+const RegisterInfo *RegisterContextFreeBSD_powerpc32::GetRegisterInfo() const {
+ return g_register_infos_powerpc32;
+}
+
+uint32_t RegisterContextFreeBSD_powerpc32::GetRegisterCount() const {
+ return static_cast<uint32_t>(sizeof(g_register_infos_powerpc32) /
+ sizeof(g_register_infos_powerpc32[0]));
+}
+
+RegisterContextFreeBSD_powerpc64::RegisterContextFreeBSD_powerpc64(
+ const ArchSpec &target_arch)
+ : RegisterContextFreeBSD_powerpc(target_arch) {}
+
+RegisterContextFreeBSD_powerpc64::~RegisterContextFreeBSD_powerpc64() = default;
+
+size_t RegisterContextFreeBSD_powerpc64::GetGPRSize() const {
+ return sizeof(GPR64);
+}
+
+const RegisterInfo *RegisterContextFreeBSD_powerpc64::GetRegisterInfo() const {
+ if (GetTargetArchitecture().GetMachine() == llvm::Triple::ppc)
+ return g_register_infos_powerpc64_32;
+ return g_register_infos_powerpc64;
+}
+
+uint32_t RegisterContextFreeBSD_powerpc64::GetRegisterCount() const {
+ return static_cast<uint32_t>(sizeof(g_register_infos_powerpc64) /
+ sizeof(g_register_infos_powerpc64[0]));
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h
new file mode 100644
index 000000000000..7e4c43ba908a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h
@@ -0,0 +1,52 @@
+//===-- RegisterContextFreeBSD_powerpc.h -------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_POWERPC_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_POWERPC_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextFreeBSD_powerpc
+ : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextFreeBSD_powerpc(const lldb_private::ArchSpec &target_arch);
+ ~RegisterContextFreeBSD_powerpc() override;
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+};
+
+class RegisterContextFreeBSD_powerpc32 : public RegisterContextFreeBSD_powerpc {
+public:
+ RegisterContextFreeBSD_powerpc32(const lldb_private::ArchSpec &target_arch);
+ ~RegisterContextFreeBSD_powerpc32() override;
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+};
+
+class RegisterContextFreeBSD_powerpc64 : public RegisterContextFreeBSD_powerpc {
+public:
+ RegisterContextFreeBSD_powerpc64(const lldb_private::ArchSpec &target_arch);
+ ~RegisterContextFreeBSD_powerpc64() override;
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_POWERPC_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
new file mode 100644
index 000000000000..e0f3971c6e27
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
@@ -0,0 +1,145 @@
+//===-- RegisterContextFreeBSD_x86_64.cpp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSD_x86_64.h"
+#include "RegisterContextFreeBSD_i386.h"
+#include "RegisterContextPOSIX_x86.h"
+#include <vector>
+
+using namespace lldb_private;
+using namespace lldb;
+
+// http://svnweb.freebsd.org/base/head/sys/x86/include/reg.h
+typedef struct _GPR {
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t rdx;
+ uint64_t rcx;
+ uint64_t rax;
+ uint32_t trapno;
+ uint16_t fs;
+ uint16_t gs;
+ uint32_t err;
+ uint16_t es;
+ uint16_t ds;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+} GPR;
+
+struct DBG {
+ uint64_t dr[16]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+ /* Index 8-15: reserved */
+};
+
+struct UserArea {
+ GPR gpr;
+ FPR fpr;
+ DBG dbg;
+};
+
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, dbg) + \
+ LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
+
+// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64
+// structure.
+#define DECLARE_REGISTER_INFOS_X86_64_STRUCT
+#include "RegisterInfos_x86_64.h"
+#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+static std::vector<lldb_private::RegisterInfo> &GetSharedRegisterInfoVector() {
+ static std::vector<lldb_private::RegisterInfo> register_infos;
+ return register_infos;
+}
+
+static const RegisterInfo *
+GetRegisterInfo_i386(const lldb_private::ArchSpec &arch) {
+ static std::vector<lldb_private::RegisterInfo> g_register_infos(
+ GetSharedRegisterInfoVector());
+
+ // Allocate RegisterInfo only once
+ if (g_register_infos.empty()) {
+ // Copy the register information from base class
+ std::unique_ptr<RegisterContextFreeBSD_i386> reg_interface(
+ new RegisterContextFreeBSD_i386(arch));
+ const RegisterInfo *base_info = reg_interface->GetRegisterInfo();
+ g_register_infos.insert(g_register_infos.end(), &base_info[0],
+ &base_info[k_num_registers_i386]);
+
+// Include RegisterInfos_x86_64 to update the g_register_infos structure
+// with x86_64 offsets.
+#define UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+#include "RegisterInfos_x86_64.h"
+#undef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+ }
+
+ return &g_register_infos[0];
+}
+
+static const RegisterInfo *
+PrivateGetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86:
+ return GetRegisterInfo_i386(target_arch);
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+PrivateGetRegisterCount(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86:
+ // This vector should have already been filled.
+ assert(!GetSharedRegisterInfoVector().empty() &&
+ "i386 register info vector not filled.");
+ return static_cast<uint32_t>(GetSharedRegisterInfoVector().size());
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t>(sizeof(g_register_infos_x86_64) /
+ sizeof(g_register_infos_x86_64[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(
+ const ArchSpec &target_arch)
+ : lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p(PrivateGetRegisterInfoPtr(target_arch)),
+ m_register_count(PrivateGetRegisterCount(target_arch)) {}
+
+size_t RegisterContextFreeBSD_x86_64::GetGPRSize() const { return sizeof(GPR); }
+
+const RegisterInfo *RegisterContextFreeBSD_x86_64::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+uint32_t RegisterContextFreeBSD_x86_64::GetRegisterCount() const {
+ return m_register_count;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h
new file mode 100644
index 000000000000..d0f69fde1817
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h
@@ -0,0 +1,30 @@
+//===-- RegisterContextFreeBSD_x86_64.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTFREEBSD_X86_64_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextFreeBSD_x86_64
+ : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextFreeBSD_x86_64(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ const uint32_t m_register_count;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp
new file mode 100644
index 000000000000..f06af93cfa83
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp
@@ -0,0 +1,121 @@
+//===-- RegisterContextHistory.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/DynamicLoader.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"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/lldb-private.h"
+
+#include "RegisterContextHistory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextHistory::RegisterContextHistory(Thread &thread,
+ uint32_t concrete_frame_idx,
+ uint32_t address_byte_size,
+ addr_t pc_value)
+ : RegisterContext(thread, concrete_frame_idx), m_pc_value(pc_value) {
+ m_reg_set0.name = "General Purpose Registers";
+ m_reg_set0.short_name = "GPR";
+ m_reg_set0.num_registers = 1;
+ m_reg_set0.registers = new uint32_t(0);
+
+ m_pc_reg_info.name = "pc";
+ m_pc_reg_info.alt_name = "pc";
+ m_pc_reg_info.byte_offset = 0;
+ m_pc_reg_info.byte_size = address_byte_size;
+ m_pc_reg_info.encoding = eEncodingUint;
+ m_pc_reg_info.format = eFormatPointer;
+ m_pc_reg_info.invalidate_regs = nullptr;
+ m_pc_reg_info.value_regs = nullptr;
+ m_pc_reg_info.kinds[eRegisterKindEHFrame] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ m_pc_reg_info.kinds[eRegisterKindProcessPlugin] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindLLDB] = LLDB_INVALID_REGNUM;
+}
+
+RegisterContextHistory::~RegisterContextHistory() {
+ delete m_reg_set0.registers;
+ delete m_pc_reg_info.invalidate_regs;
+ delete m_pc_reg_info.value_regs;
+}
+
+void RegisterContextHistory::InvalidateAllRegisters() {}
+
+size_t RegisterContextHistory::GetRegisterCount() { return 1; }
+
+const lldb_private::RegisterInfo *
+RegisterContextHistory::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg)
+ return nullptr;
+ return &m_pc_reg_info;
+}
+
+size_t RegisterContextHistory::GetRegisterSetCount() { return 1; }
+
+const lldb_private::RegisterSet *
+RegisterContextHistory::GetRegisterSet(size_t reg_set) {
+ if (reg_set)
+ return nullptr;
+ return &m_reg_set0;
+}
+
+bool RegisterContextHistory::ReadRegister(
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) {
+ if (!reg_info)
+ return false;
+ uint32_t reg_number = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_number == LLDB_REGNUM_GENERIC_PC) {
+ value.SetUInt(m_pc_value, reg_info->byte_size);
+ return true;
+ }
+ return false;
+}
+
+bool RegisterContextHistory::WriteRegister(
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) {
+ return false;
+}
+
+bool RegisterContextHistory::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextHistory::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ return false;
+}
+
+uint32_t RegisterContextHistory::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC)
+ return 0;
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h
new file mode 100644
index 000000000000..a1eadac5d1b7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h
@@ -0,0 +1,67 @@
+//===-- RegisterContextHistory.h ----------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTHISTORY_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTHISTORY_H
+
+#include <vector>
+
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class RegisterContextHistory : public lldb_private::RegisterContext {
+public:
+ typedef std::shared_ptr<RegisterContextHistory> SharedPtr;
+
+ RegisterContextHistory(Thread &thread, uint32_t concrete_frame_idx,
+ uint32_t address_byte_size, lldb::addr_t pc_value);
+
+ ~RegisterContextHistory() override;
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t reg_set) override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+private:
+ // For RegisterContextLLDB only
+
+ lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only)
+ lldb_private::RegisterInfo m_pc_reg_info;
+
+ lldb::addr_t m_pc_value;
+
+ RegisterContextHistory(const RegisterContextHistory &) = delete;
+ const RegisterContextHistory &
+ operator=(const RegisterContextHistory &) = delete;
+};
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTHISTORY_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
new file mode 100644
index 000000000000..9e022baa297b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
@@ -0,0 +1,125 @@
+//===-- RegisterContextLinux_i386.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextLinux_i386.h"
+#include "RegisterContextPOSIX_x86.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+struct GPR {
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t ebp;
+ uint32_t eax;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ uint32_t orig_eax;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+ uint32_t esp;
+ uint32_t ss;
+};
+
+struct FPR_i386 {
+ uint16_t fctrl; // FPU Control Word (fcw)
+ uint16_t fstat; // FPU Status Word (fsw)
+ uint16_t ftag; // FPU Tag Word (ftw)
+ uint16_t fop; // Last Instruction Opcode (fop)
+ union {
+ struct {
+ uint64_t fip; // Instruction Pointer
+ uint64_t fdp; // Data Pointer
+ } x86_64;
+ struct {
+ uint32_t fioff; // FPU IP Offset (fip)
+ uint32_t fiseg; // FPU IP Selector (fcs)
+ uint32_t fooff; // FPU Operand Pointer Offset (foo)
+ uint32_t foseg; // FPU Operand Pointer Selector (fos)
+ } i386_; // Added _ in the end to avoid error with gcc defining i386 in some
+ // cases
+ } ptr;
+ uint32_t mxcsr; // MXCSR Register State
+ uint32_t mxcsrmask; // MXCSR Mask
+ MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes
+ XMMReg xmm[8]; // 8*16 bytes for each XMM-reg = 128 bytes
+ uint32_t padding[56];
+};
+
+struct UserArea {
+ GPR regs; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ FPR_i386 i387; // FPU registers.
+ uint32_t tsize; // Text segment size.
+ uint32_t dsize; // Data segment size.
+ uint32_t ssize; // Stack segment size.
+ uint32_t start_code; // VM address of text.
+ uint32_t start_stack; // VM address of stack bottom (top in rsp).
+ int32_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ uint32_t ar0; // Location of GPR's.
+ uint32_t fpstate; // Location of FPR's. Should be a FXSTATE *, but this
+ // has to be 32-bits even on 64-bit systems.
+ uint32_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+};
+
+#define DR_SIZE sizeof(((UserArea *)NULL)->u_debugreg[0])
+#define DR_0_OFFSET 0xFC
+#define DR_OFFSET(reg_index) (DR_0_OFFSET + (reg_index * 4))
+#define FPR_SIZE(reg) sizeof(((FPR_i386 *)NULL)->reg)
+
+// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure.
+#define DECLARE_REGISTER_INFOS_I386_STRUCT
+#include "RegisterInfos_i386.h"
+#undef DECLARE_REGISTER_INFOS_I386_STRUCT
+
+RegisterContextLinux_i386::RegisterContextLinux_i386(
+ const ArchSpec &target_arch)
+ : RegisterContextLinux_x86(
+ target_arch,
+ {"orig_eax",
+ nullptr,
+ sizeof(((GPR *)nullptr)->orig_eax),
+ (LLVM_EXTENSION offsetof(GPR, orig_eax)),
+ eEncodingUint,
+ eFormatHex,
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM},
+ nullptr,
+ nullptr,
+ nullptr}) {}
+
+size_t RegisterContextLinux_i386::GetGPRSizeStatic() { return sizeof(GPR); }
+
+const RegisterInfo *RegisterContextLinux_i386::GetRegisterInfo() const {
+ switch (GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return g_register_infos_i386;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+uint32_t RegisterContextLinux_i386::GetRegisterCount() const {
+ return static_cast<uint32_t>(sizeof(g_register_infos_i386) /
+ sizeof(g_register_infos_i386[0]));
+}
+
+uint32_t RegisterContextLinux_i386::GetUserRegisterCount() const {
+ return static_cast<uint32_t>(k_num_user_registers_i386);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h
new file mode 100644
index 000000000000..c10613993689
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h
@@ -0,0 +1,29 @@
+//===-- RegisterContextLinux_i386.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_I386_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_I386_H
+
+#include "Plugins/Process/Utility/RegisterContextLinux_x86.h"
+
+class RegisterContextLinux_i386
+ : public lldb_private::RegisterContextLinux_x86 {
+public:
+ RegisterContextLinux_i386(const lldb_private::ArchSpec &target_arch);
+
+ static size_t GetGPRSizeStatic();
+ size_t GetGPRSize() const override { return GetGPRSizeStatic(); }
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp
new file mode 100644
index 000000000000..77627cfbdefe
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp
@@ -0,0 +1,69 @@
+//===-- RegisterContextLinux_s390x.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextLinux_s390x.h"
+#include "RegisterContextPOSIX_s390x.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// Include RegisterInfos_s390x to declare our g_register_infos_s390x structure.
+#define DECLARE_REGISTER_INFOS_S390X_STRUCT
+#include "RegisterInfos_s390x.h"
+#undef DECLARE_REGISTER_INFOS_S390X_STRUCT
+
+static const RegisterInfo *GetRegisterInfoPtr(const ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::systemz:
+ return g_register_infos_s390x;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t GetRegisterInfoCount(const ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::systemz:
+ return k_num_registers_s390x;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+static uint32_t GetUserRegisterInfoCount(const ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::systemz:
+ return k_num_user_registers_s390x + k_num_linux_registers_s390x;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_s390x::RegisterContextLinux_s390x(
+ const ArchSpec &target_arch)
+ : lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch)),
+ m_user_register_count(GetUserRegisterInfoCount(target_arch)) {}
+
+const RegisterInfo *RegisterContextLinux_s390x::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+uint32_t RegisterContextLinux_s390x::GetRegisterCount() const {
+ return m_register_info_count;
+}
+
+uint32_t RegisterContextLinux_s390x::GetUserRegisterCount() const {
+ return m_user_register_count;
+}
+
+size_t RegisterContextLinux_s390x::GetGPRSize() const { return 0; }
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.h
new file mode 100644
index 000000000000..6bfe34de7acf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_s390x.h
@@ -0,0 +1,32 @@
+//===-- RegisterContextLinux_s390x.h ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_S390X_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_S390X_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextLinux_s390x : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextLinux_s390x(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+ uint32_t m_user_register_count;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86.h
new file mode 100644
index 000000000000..0e1863864aa6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86.h
@@ -0,0 +1,30 @@
+//===-- RegisterContextLinux_i386.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_X86_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_X86_H
+
+#include "RegisterInfoInterface.h"
+
+namespace lldb_private {
+
+class RegisterContextLinux_x86 : public RegisterInfoInterface {
+public:
+ RegisterContextLinux_x86(const ArchSpec &target_arch,
+ RegisterInfo orig_ax_info)
+ : RegisterInfoInterface(target_arch), m_orig_ax_info(orig_ax_info) {}
+
+ const RegisterInfo &GetOrigAxInfo() const { return m_orig_ax_info; }
+
+private:
+ lldb_private::RegisterInfo m_orig_ax_info;
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
new file mode 100644
index 000000000000..63c034a858d7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
@@ -0,0 +1,184 @@
+//===-- RegisterContextLinux_x86_64.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextLinux_x86_64.h"
+#include "RegisterContextLinux_i386.h"
+#include "RegisterContextPOSIX_x86.h"
+#include <vector>
+
+using namespace lldb_private;
+using namespace lldb;
+
+typedef struct _GPR {
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t orig_rax;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+ uint64_t fs_base;
+ uint64_t gs_base;
+ uint64_t ds;
+ uint64_t es;
+ uint64_t fs;
+ uint64_t gs;
+} GPR;
+
+struct DBG {
+ uint64_t dr[8];
+};
+
+struct UserArea {
+ GPR gpr; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ int32_t pad0;
+ FXSAVE fpr; // General purpose floating point registers (see FPR for extended
+ // register sets).
+ uint64_t tsize; // Text segment size.
+ uint64_t dsize; // Data segment size.
+ uint64_t ssize; // Stack segment size.
+ uint64_t start_code; // VM address of text.
+ uint64_t start_stack; // VM address of stack bottom (top in rsp).
+ int64_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ int32_t pad1;
+ uint64_t ar0; // Location of GPR's.
+ FXSAVE *fpstate; // Location of FPR's.
+ uint64_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ DBG dbg; // Debug registers.
+ uint64_t error_code; // CPU error code.
+ uint64_t fault_address; // Control register CR3.
+};
+
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, dbg) + \
+ LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
+
+// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64_with_base
+// structure.
+#define DECLARE_REGISTER_INFOS_X86_64_STRUCT
+#include "RegisterInfos_x86_64_with_base.h"
+#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+static std::vector<lldb_private::RegisterInfo> &GetPrivateRegisterInfoVector() {
+ static std::vector<lldb_private::RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
+static const RegisterInfo *
+GetRegisterInfo_i386(const lldb_private::ArchSpec &arch) {
+ std::vector<lldb_private::RegisterInfo> &g_register_infos =
+ GetPrivateRegisterInfoVector();
+
+ // Allocate RegisterInfo only once
+ if (g_register_infos.empty()) {
+ // Copy the register information from base class
+ std::unique_ptr<RegisterContextLinux_i386> reg_interface(
+ new RegisterContextLinux_i386(arch));
+ const RegisterInfo *base_info = reg_interface->GetRegisterInfo();
+ g_register_infos.insert(g_register_infos.end(), &base_info[0],
+ &base_info[k_num_registers_i386]);
+
+// Include RegisterInfos_x86_64 to update the g_register_infos structure
+// with x86_64 offsets.
+#define UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+#include "RegisterInfos_x86_64_with_base.h"
+#undef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+ }
+
+ return &g_register_infos[0];
+}
+
+static const RegisterInfo *GetRegisterInfoPtr(const ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86:
+ return GetRegisterInfo_i386(target_arch);
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64_with_base;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t GetRegisterInfoCount(const ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86: {
+ assert(!GetPrivateRegisterInfoVector().empty() &&
+ "i386 register info not yet filled.");
+ return static_cast<uint32_t>(GetPrivateRegisterInfoVector().size());
+ }
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t>(sizeof(g_register_infos_x86_64_with_base) /
+ sizeof(g_register_infos_x86_64_with_base[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+static uint32_t GetUserRegisterInfoCount(const ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86:
+ return static_cast<uint32_t>(k_num_user_registers_i386);
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t>(x86_64_with_base::k_num_user_registers);
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(
+ const ArchSpec &target_arch)
+ : lldb_private::RegisterContextLinux_x86(
+ target_arch,
+ {"orig_rax",
+ nullptr,
+ sizeof(((GPR *)nullptr)->orig_rax),
+ (LLVM_EXTENSION offsetof(GPR, orig_rax)),
+ eEncodingUint,
+ eFormatHex,
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM},
+ nullptr,
+ nullptr,
+ nullptr}),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch)),
+ m_user_register_count(GetUserRegisterInfoCount(target_arch)) {}
+
+size_t RegisterContextLinux_x86_64::GetGPRSizeStatic() { return sizeof(GPR); }
+
+const RegisterInfo *RegisterContextLinux_x86_64::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+uint32_t RegisterContextLinux_x86_64::GetRegisterCount() const {
+ return m_register_info_count;
+}
+
+uint32_t RegisterContextLinux_x86_64::GetUserRegisterCount() const {
+ return m_user_register_count;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h
new file mode 100644
index 000000000000..d141ba66b4e2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h
@@ -0,0 +1,34 @@
+//===-- RegisterContextLinux_x86_64.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTLINUX_X86_64_H
+
+#include "Plugins/Process/Utility/RegisterContextLinux_x86.h"
+
+class RegisterContextLinux_x86_64
+ : public lldb_private::RegisterContextLinux_x86 {
+public:
+ RegisterContextLinux_x86_64(const lldb_private::ArchSpec &target_arch);
+
+ static size_t GetGPRSizeStatic();
+ size_t GetGPRSize() const override { return GetGPRSizeStatic(); }
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+ uint32_t m_user_register_count;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
new file mode 100644
index 000000000000..067d1c3705e4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
@@ -0,0 +1,74 @@
+//===-- RegisterContextMach_arm.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include "RegisterContextMach_arm.h"
+
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextMach_arm::RegisterContextMach_arm(Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContextDarwin_arm(thread, concrete_frame_idx) {}
+
+RegisterContextMach_arm::~RegisterContextMach_arm() = default;
+
+int RegisterContextMach_arm::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) {
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int RegisterContextMach_arm::DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) {
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int RegisterContextMach_arm::DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) {
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int RegisterContextMach_arm::DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) {
+ mach_msg_type_number_t count = DBGWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&dbg, &count);
+}
+
+int RegisterContextMach_arm::DoWriteGPR(lldb::tid_t tid, int flavor,
+ const GPR &gpr) {
+ return ::thread_set_state(
+ tid, flavor, reinterpret_cast<thread_state_t>(const_cast<GPR *>(&gpr)),
+ GPRWordCount);
+}
+
+int RegisterContextMach_arm::DoWriteFPU(lldb::tid_t tid, int flavor,
+ const FPU &fpu) {
+ return ::thread_set_state(
+ tid, flavor, reinterpret_cast<thread_state_t>(const_cast<FPU *>(&fpu)),
+ FPUWordCount);
+}
+
+int RegisterContextMach_arm::DoWriteEXC(lldb::tid_t tid, int flavor,
+ const EXC &exc) {
+ return ::thread_set_state(
+ tid, flavor, reinterpret_cast<thread_state_t>(const_cast<EXC *>(&exc)),
+ EXCWordCount);
+}
+
+int RegisterContextMach_arm::DoWriteDBG(lldb::tid_t tid, int flavor,
+ const DBG &dbg) {
+ return ::thread_set_state(
+ tid, flavor, reinterpret_cast<thread_state_t>(const_cast<DBG *>(&dbg)),
+ DBGWordCount);
+}
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h
new file mode 100644
index 000000000000..fedd0062c99c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h
@@ -0,0 +1,39 @@
+//===-- RegisterContextMach_arm.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_ARM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_ARM_H
+
+#include "RegisterContextDarwin_arm.h"
+
+class RegisterContextMach_arm : public RegisterContextDarwin_arm {
+public:
+ RegisterContextMach_arm(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ ~RegisterContextMach_arm() override;
+
+protected:
+ int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override;
+
+ int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override;
+
+ int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override;
+
+ int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override;
+
+ int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override;
+
+ int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override;
+
+ int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override;
+
+ int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_ARM_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
new file mode 100644
index 000000000000..fe5cecef1b0c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
@@ -0,0 +1,60 @@
+//===-- RegisterContextMach_i386.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include <mach/thread_act.h>
+
+#include "RegisterContextMach_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextMach_i386::RegisterContextMach_i386(Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContextDarwin_i386(thread, concrete_frame_idx) {}
+
+RegisterContextMach_i386::~RegisterContextMach_i386() = default;
+
+int RegisterContextMach_i386::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) {
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int RegisterContextMach_i386::DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) {
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int RegisterContextMach_i386::DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) {
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int RegisterContextMach_i386::DoWriteGPR(lldb::tid_t tid, int flavor,
+ const GPR &gpr) {
+ return ::thread_set_state(
+ tid, flavor, reinterpret_cast<thread_state_t>(const_cast<GPR *>(&gpr)),
+ GPRWordCount);
+}
+
+int RegisterContextMach_i386::DoWriteFPU(lldb::tid_t tid, int flavor,
+ const FPU &fpu) {
+ return ::thread_set_state(
+ tid, flavor, reinterpret_cast<thread_state_t>(const_cast<FPU *>(&fpu)),
+ FPUWordCount);
+}
+
+int RegisterContextMach_i386::DoWriteEXC(lldb::tid_t tid, int flavor,
+ const EXC &exc) {
+ return ::thread_set_state(
+ tid, flavor, reinterpret_cast<thread_state_t>(const_cast<EXC *>(&exc)),
+ EXCWordCount);
+}
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h
new file mode 100644
index 000000000000..8bdac083863d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h
@@ -0,0 +1,35 @@
+//===-- RegisterContextMach_i386.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_I386_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_I386_H
+
+#include "RegisterContextDarwin_i386.h"
+
+class RegisterContextMach_i386 : public RegisterContextDarwin_i386 {
+public:
+ RegisterContextMach_i386(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ ~RegisterContextMach_i386() override;
+
+protected:
+ int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override;
+
+ int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override;
+
+ int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override;
+
+ int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override;
+
+ int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override;
+
+ int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_I386_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
new file mode 100644
index 000000000000..a3d8c4f649d2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
@@ -0,0 +1,63 @@
+//===-- RegisterContextMach_x86_64.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include <mach/thread_act.h>
+
+#include "RegisterContextMach_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextMach_x86_64::RegisterContextMach_x86_64(
+ Thread &thread, uint32_t concrete_frame_idx)
+ : RegisterContextDarwin_x86_64(thread, concrete_frame_idx) {}
+
+RegisterContextMach_x86_64::~RegisterContextMach_x86_64() = default;
+
+int RegisterContextMach_x86_64::DoReadGPR(lldb::tid_t tid, int flavor,
+ GPR &gpr) {
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int RegisterContextMach_x86_64::DoReadFPU(lldb::tid_t tid, int flavor,
+ FPU &fpu) {
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int RegisterContextMach_x86_64::DoReadEXC(lldb::tid_t tid, int flavor,
+ EXC &exc) {
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int RegisterContextMach_x86_64::DoWriteGPR(lldb::tid_t tid, int flavor,
+ const GPR &gpr) {
+ return ::thread_set_state(
+ tid, flavor, reinterpret_cast<thread_state_t>(const_cast<GPR *>(&gpr)),
+ GPRWordCount);
+}
+
+int RegisterContextMach_x86_64::DoWriteFPU(lldb::tid_t tid, int flavor,
+ const FPU &fpu) {
+ return ::thread_set_state(
+ tid, flavor, reinterpret_cast<thread_state_t>(const_cast<FPU *>(&fpu)),
+ FPUWordCount);
+}
+
+int RegisterContextMach_x86_64::DoWriteEXC(lldb::tid_t tid, int flavor,
+ const EXC &exc) {
+ return ::thread_set_state(
+ tid, flavor, reinterpret_cast<thread_state_t>(const_cast<EXC *>(&exc)),
+ EXCWordCount);
+}
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
new file mode 100644
index 000000000000..99841a8e9a8d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
@@ -0,0 +1,36 @@
+//===-- RegisterContextMach_x86_64.h ------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_X86_64_H
+
+#include "RegisterContextDarwin_x86_64.h"
+
+class RegisterContextMach_x86_64 : public RegisterContextDarwin_x86_64 {
+public:
+ RegisterContextMach_x86_64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ ~RegisterContextMach_x86_64() override;
+
+protected:
+ int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override;
+
+ int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override;
+
+ int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override;
+
+ int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override;
+
+ int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override;
+
+ int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_X86_64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp
new file mode 100644
index 000000000000..84a19d5b1303
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp
@@ -0,0 +1,139 @@
+//===-- RegisterContextMemory.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMemory.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// RegisterContextMemory constructor
+RegisterContextMemory::RegisterContextMemory(Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_infos,
+ addr_t reg_data_addr)
+ : RegisterContext(thread, concrete_frame_idx), m_reg_infos(reg_infos),
+ m_reg_valid(), m_reg_data(), m_reg_data_addr(reg_data_addr) {
+ // Resize our vector of bools to contain one bool for every register. We will
+ // use these boolean values to know when a register value is valid in
+ // m_reg_data.
+ const size_t num_regs = reg_infos.GetNumRegisters();
+ assert(num_regs > 0);
+ m_reg_valid.resize(num_regs);
+
+ // Make a heap based buffer that is big enough to store all registers
+ m_data =
+ std::make_shared<DataBufferHeap>(reg_infos.GetRegisterDataByteSize(), 0);
+ m_reg_data.SetData(m_data);
+}
+
+// Destructor
+RegisterContextMemory::~RegisterContextMemory() = default;
+
+void RegisterContextMemory::InvalidateAllRegisters() {
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ SetAllRegisterValid(false);
+}
+
+void RegisterContextMemory::SetAllRegisterValid(bool b) {
+ std::vector<bool>::iterator pos, end = m_reg_valid.end();
+ for (pos = m_reg_valid.begin(); pos != end; ++pos)
+ *pos = b;
+}
+
+size_t RegisterContextMemory::GetRegisterCount() {
+ return m_reg_infos.GetNumRegisters();
+}
+
+const RegisterInfo *RegisterContextMemory::GetRegisterInfoAtIndex(size_t reg) {
+ return m_reg_infos.GetRegisterInfoAtIndex(reg);
+}
+
+size_t RegisterContextMemory::GetRegisterSetCount() {
+ return m_reg_infos.GetNumRegisterSets();
+}
+
+const RegisterSet *RegisterContextMemory::GetRegisterSet(size_t reg_set) {
+ return m_reg_infos.GetRegisterSet(reg_set);
+}
+
+uint32_t RegisterContextMemory::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ return m_reg_infos.ConvertRegisterKindToRegisterNumber(kind, num);
+}
+
+bool RegisterContextMemory::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ if (!m_reg_valid[reg_num]) {
+ if (!ReadAllRegisterValues(m_data))
+ return false;
+ }
+ const bool partial_data_ok = false;
+ return reg_value
+ .SetValueFromData(*reg_info, m_reg_data, reg_info->byte_offset,
+ partial_data_ok)
+ .Success();
+}
+
+bool RegisterContextMemory::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) {
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS) {
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ addr_t reg_addr = m_reg_data_addr + reg_info->byte_offset;
+ Status error(WriteRegisterValueToMemory(reg_info, reg_addr,
+ reg_info->byte_size, reg_value));
+ m_reg_valid[reg_num] = false;
+ return error.Success();
+ }
+ return false;
+}
+
+bool RegisterContextMemory::ReadAllRegisterValues(
+ WritableDataBufferSP &data_sp) {
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS) {
+ ProcessSP process_sp(CalculateProcess());
+ if (process_sp) {
+ Status error;
+ if (process_sp->ReadMemory(m_reg_data_addr, data_sp->GetBytes(),
+ data_sp->GetByteSize(),
+ error) == data_sp->GetByteSize()) {
+ SetAllRegisterValid(true);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool RegisterContextMemory::WriteAllRegisterValues(
+ const DataBufferSP &data_sp) {
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS) {
+ ProcessSP process_sp(CalculateProcess());
+ if (process_sp) {
+ Status error;
+ SetAllRegisterValid(false);
+ if (process_sp->WriteMemory(m_reg_data_addr, data_sp->GetBytes(),
+ data_sp->GetByteSize(),
+ error) == data_sp->GetByteSize())
+ return true;
+ }
+ }
+ return false;
+}
+
+void RegisterContextMemory::SetAllRegisterData(
+ const lldb::DataBufferSP &data_sp) {
+ m_reg_data.SetData(data_sp);
+ SetAllRegisterValid(true);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h
new file mode 100644
index 000000000000..2aad99ec9b21
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h
@@ -0,0 +1,75 @@
+//===-- RegisterContextMemory.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMEMORY_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMEMORY_H
+
+#include <vector>
+
+#include "lldb/Target/DynamicRegisterInfo.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/lldb-private.h"
+
+class RegisterContextMemory : public lldb_private::RegisterContext {
+public:
+ RegisterContextMemory(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::DynamicRegisterInfo &reg_info,
+ lldb::addr_t reg_data_addr);
+
+ ~RegisterContextMemory() override;
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t reg_set) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ // If all of the thread register are in a contiguous buffer in
+ // memory, then the default ReadRegister/WriteRegister and
+ // ReadAllRegisterValues/WriteAllRegisterValues will work. If thread
+ // registers are not contiguous, clients will want to subclass this
+ // class and modify the read/write functions as needed.
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ void SetAllRegisterData(const lldb::DataBufferSP &data_sp);
+
+protected:
+ void SetAllRegisterValid(bool b);
+
+ lldb_private::DynamicRegisterInfo &m_reg_infos;
+ std::vector<bool> m_reg_valid;
+ lldb::WritableDataBufferSP m_data;
+ lldb_private::DataExtractor m_reg_data;
+ lldb::addr_t m_reg_data_addr; // If this is valid, then we have a register
+ // context that is stored in memmory
+
+private:
+ RegisterContextMemory(const RegisterContextMemory &) = delete;
+ const RegisterContextMemory &
+ operator=(const RegisterContextMemory &) = delete;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMEMORY_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp
new file mode 100644
index 000000000000..a160c87db6cf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.cpp
@@ -0,0 +1,96 @@
+//===-- RegisterContextNetBSD_i386.cpp --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextNetBSD_i386.h"
+#include "RegisterContextPOSIX_x86.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// this needs to match 'struct reg'
+struct GPR {
+ uint32_t eax;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t ebx;
+ uint32_t esp;
+ uint32_t ebp;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t eip;
+ uint32_t eflags;
+ uint32_t cs;
+ uint32_t ss;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+};
+
+struct FPR_i386 {
+ uint16_t fctrl; // FPU Control Word (fcw)
+ uint16_t fstat; // FPU Status Word (fsw)
+ uint16_t ftag; // FPU Tag Word (ftw)
+ uint16_t fop; // Last Instruction Opcode (fop)
+ union {
+ struct {
+ uint64_t fip; // Instruction Pointer
+ uint64_t fdp; // Data Pointer
+ } x86_64;
+ struct {
+ uint32_t fioff; // FPU IP Offset (fip)
+ uint32_t fiseg; // FPU IP Selector (fcs)
+ uint32_t fooff; // FPU Operand Pointer Offset (foo)
+ uint32_t foseg; // FPU Operand Pointer Selector (fos)
+ } i386_; // Added _ in the end to avoid error with gcc defining i386 in some
+ // cases
+ } ptr;
+ uint32_t mxcsr; // MXCSR Register State
+ uint32_t mxcsrmask; // MXCSR Mask
+ MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes
+ XMMReg xmm[8]; // 8*16 bytes for each XMM-reg = 128 bytes
+ uint32_t padding[56];
+};
+
+struct UserArea {
+ GPR gpr;
+ FPR_i386 i387;
+ uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+ uint32_t tlsbase;
+};
+
+#define DR_SIZE sizeof(((UserArea *)NULL)->u_debugreg[0])
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index]))
+
+// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure.
+#define DECLARE_REGISTER_INFOS_I386_STRUCT
+#include "RegisterInfos_i386.h"
+#undef DECLARE_REGISTER_INFOS_I386_STRUCT
+
+RegisterContextNetBSD_i386::RegisterContextNetBSD_i386(
+ const ArchSpec &target_arch)
+ : RegisterInfoInterface(target_arch) {}
+
+size_t RegisterContextNetBSD_i386::GetGPRSize() const { return sizeof(GPR); }
+
+const RegisterInfo *RegisterContextNetBSD_i386::GetRegisterInfo() const {
+ switch (GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return g_register_infos_i386;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+uint32_t RegisterContextNetBSD_i386::GetRegisterCount() const {
+ return static_cast<uint32_t>(sizeof(g_register_infos_i386) /
+ sizeof(g_register_infos_i386[0]));
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.h
new file mode 100644
index 000000000000..742bb18b8306
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_i386.h
@@ -0,0 +1,25 @@
+//===-- RegisterContextNetBSD_i386.h ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTNETBSD_I386_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTNETBSD_I386_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextNetBSD_i386 : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextNetBSD_i386(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp
new file mode 100644
index 000000000000..32bb7952820d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp
@@ -0,0 +1,178 @@
+//===-- RegisterContextNetBSD_x86_64.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextNetBSD_x86_64.h"
+#include "RegisterContextNetBSD_i386.h"
+#include "RegisterContextPOSIX_x86.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/TargetParser/Triple.h"
+#include <cassert>
+#include <cstddef>
+
+using namespace lldb_private;
+using namespace lldb;
+
+// src/sys/arch/amd64/include/frame_regs.h
+typedef struct _GPR {
+ uint64_t rdi; /* 0 */
+ uint64_t rsi; /* 1 */
+ uint64_t rdx; /* 2 */
+ uint64_t rcx; /* 3 */
+ uint64_t r8; /* 4 */
+ uint64_t r9; /* 5 */
+ uint64_t r10; /* 6 */
+ uint64_t r11; /* 7 */
+ uint64_t r12; /* 8 */
+ uint64_t r13; /* 9 */
+ uint64_t r14; /* 10 */
+ uint64_t r15; /* 11 */
+ uint64_t rbp; /* 12 */
+ uint64_t rbx; /* 13 */
+ uint64_t rax; /* 14 */
+ uint64_t gs; /* 15 */
+ uint64_t fs; /* 16 */
+ uint64_t es; /* 17 */
+ uint64_t ds; /* 18 */
+ uint64_t trapno; /* 19 */
+ uint64_t err; /* 20 */
+ uint64_t rip; /* 21 */
+ uint64_t cs; /* 22 */
+ uint64_t rflags; /* 23 */
+ uint64_t rsp; /* 24 */
+ uint64_t ss; /* 25 */
+} GPR;
+
+struct DBG {
+ uint64_t dr[16]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+ /* Index 8-15: reserved */
+};
+
+/*
+ * src/sys/arch/amd64/include/mcontext.h
+ *
+ * typedef struct {
+ * __gregset_t __gregs;
+ * __greg_t _mc_tlsbase;
+ * __fpregset_t __fpregs;
+ * } mcontext_t;
+ */
+
+struct UserArea {
+ GPR gpr;
+ uint64_t mc_tlsbase;
+ FPR fpr;
+ DBG dbg;
+};
+
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, dbg) + \
+ LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
+
+
+// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64
+// structure.
+#define DECLARE_REGISTER_INFOS_X86_64_STRUCT
+#include "RegisterInfos_x86_64.h"
+#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+static std::vector<lldb_private::RegisterInfo> &GetPrivateRegisterInfoVector() {
+ static std::vector<lldb_private::RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
+static const RegisterInfo *
+GetRegisterInfo_i386(const lldb_private::ArchSpec &arch) {
+ std::vector<lldb_private::RegisterInfo> &g_register_infos =
+ GetPrivateRegisterInfoVector();
+
+ // Allocate RegisterInfo only once
+ if (g_register_infos.empty()) {
+ // Copy the register information from base class
+ std::unique_ptr<RegisterContextNetBSD_i386> reg_interface(
+ new RegisterContextNetBSD_i386(arch));
+ const RegisterInfo *base_info = reg_interface->GetRegisterInfo();
+ g_register_infos.insert(g_register_infos.end(), &base_info[0],
+ &base_info[k_num_registers_i386]);
+
+// Include RegisterInfos_x86_64 to update the g_register_infos structure
+// with x86_64 offsets.
+#define UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+#include "RegisterInfos_x86_64.h"
+#undef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+ }
+
+ return &g_register_infos[0];
+}
+
+static const RegisterInfo *
+PrivateGetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86:
+ return GetRegisterInfo_i386(target_arch);
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+PrivateGetRegisterCount(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86: {
+ assert(!GetPrivateRegisterInfoVector().empty() &&
+ "i386 register info not yet filled.");
+ return static_cast<uint32_t>(GetPrivateRegisterInfoVector().size());
+ }
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t>(sizeof(g_register_infos_x86_64) /
+ sizeof(g_register_infos_x86_64[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+static uint32_t
+PrivateGetUserRegisterCount(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86:
+ return static_cast<uint32_t>(k_num_user_registers_i386);
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t>(k_num_user_registers_x86_64);
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextNetBSD_x86_64::RegisterContextNetBSD_x86_64(
+ const ArchSpec &target_arch)
+ : lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p(PrivateGetRegisterInfoPtr(target_arch)),
+ m_register_count(PrivateGetRegisterCount(target_arch)),
+ m_user_register_count(PrivateGetUserRegisterCount(target_arch)) {}
+
+size_t RegisterContextNetBSD_x86_64::GetGPRSize() const { return sizeof(GPR); }
+
+const RegisterInfo *RegisterContextNetBSD_x86_64::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+uint32_t RegisterContextNetBSD_x86_64::GetRegisterCount() const {
+ return m_register_count;
+}
+
+uint32_t RegisterContextNetBSD_x86_64::GetUserRegisterCount() const {
+ return m_user_register_count;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h
new file mode 100644
index 000000000000..6f9787506013
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h
@@ -0,0 +1,33 @@
+//===-- RegisterContextNetBSD_x86_64.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTNETBSD_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTNETBSD_X86_64_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextNetBSD_x86_64
+ : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextNetBSD_x86_64(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ const uint32_t m_register_count;
+ const uint32_t m_user_register_count;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp
new file mode 100644
index 000000000000..ddf6cc5c3c65
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp
@@ -0,0 +1,77 @@
+//===-- RegisterContextOpenBSD_i386.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextOpenBSD_i386.h"
+#include "RegisterContextPOSIX_x86.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// /usr/include/machine/reg.h
+struct GPR {
+ uint32_t eax;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t ebx;
+ uint32_t esp;
+ uint32_t ebp;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t eip;
+ uint32_t eflags;
+ uint32_t cs;
+ uint32_t ss;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+};
+
+struct dbreg {
+ uint32_t dr[8]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+};
+
+using FPR_i386 = FXSAVE;
+
+struct UserArea {
+ GPR gpr;
+ FPR_i386 i387;
+};
+
+#define DR_SIZE sizeof(uint32_t)
+#define DR_OFFSET(reg_index) (LLVM_EXTENSION offsetof(dbreg, dr[reg_index]))
+
+// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure.
+#define DECLARE_REGISTER_INFOS_I386_STRUCT
+#include "RegisterInfos_i386.h"
+#undef DECLARE_REGISTER_INFOS_I386_STRUCT
+
+RegisterContextOpenBSD_i386::RegisterContextOpenBSD_i386(
+ const ArchSpec &target_arch)
+ : RegisterInfoInterface(target_arch) {}
+
+size_t RegisterContextOpenBSD_i386::GetGPRSize() const { return sizeof(GPR); }
+
+const RegisterInfo *RegisterContextOpenBSD_i386::GetRegisterInfo() const {
+ switch (GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ return g_register_infos_i386;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+uint32_t RegisterContextOpenBSD_i386::GetRegisterCount() const {
+ return static_cast<uint32_t>(sizeof(g_register_infos_i386) /
+ sizeof(g_register_infos_i386[0]));
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h
new file mode 100644
index 000000000000..e6e24525b7fd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h
@@ -0,0 +1,25 @@
+//===-- RegisterContextOpenBSD_i386.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTOPENBSD_I386_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTOPENBSD_I386_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextOpenBSD_i386 : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextOpenBSD_i386(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp
new file mode 100644
index 000000000000..05c1f83efded
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp
@@ -0,0 +1,104 @@
+//===-- RegisterContextOpenBSD_x86_64.cpp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextOpenBSD_x86_64.h"
+#include "RegisterContextPOSIX_x86.h"
+#include <vector>
+
+using namespace lldb_private;
+using namespace lldb;
+
+// /usr/include/machine/reg.h
+typedef struct _GPR {
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rdx;
+ uint64_t rcx;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t rax;
+ uint64_t rsp;
+ uint64_t rip;
+ uint64_t rflags;
+ uint64_t cs;
+ uint64_t ss;
+ uint64_t ds;
+ uint64_t es;
+ uint64_t fs;
+ uint64_t gs;
+} GPR;
+
+struct DBG {
+ uint64_t dr[16]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+ /* Index 8-15: reserved */
+};
+
+struct UserArea {
+ GPR gpr;
+ FPR fpr;
+ DBG dbg;
+};
+
+#define DR_OFFSET(reg_index) (LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
+
+// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64
+// structure.
+#define DECLARE_REGISTER_INFOS_X86_64_STRUCT
+#include "RegisterInfos_x86_64.h"
+#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+static const RegisterInfo *
+PrivateGetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+PrivateGetRegisterCount(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t>(sizeof(g_register_infos_x86_64) /
+ sizeof(g_register_infos_x86_64[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextOpenBSD_x86_64::RegisterContextOpenBSD_x86_64(
+ const ArchSpec &target_arch)
+ : lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p(PrivateGetRegisterInfoPtr(target_arch)),
+ m_register_count(PrivateGetRegisterCount(target_arch)) {}
+
+size_t RegisterContextOpenBSD_x86_64::GetGPRSize() const { return sizeof(GPR); }
+
+const RegisterInfo *RegisterContextOpenBSD_x86_64::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+uint32_t RegisterContextOpenBSD_x86_64::GetRegisterCount() const {
+ return m_register_count;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h
new file mode 100644
index 000000000000..b399c721546a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h
@@ -0,0 +1,30 @@
+//===-- RegisterContextOpenBSD_x86_64.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTOPENBSD_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTOPENBSD_X86_64_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextOpenBSD_x86_64
+ : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextOpenBSD_x86_64(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ const uint32_t m_register_count;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
new file mode 100644
index 000000000000..684176bccdf0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
@@ -0,0 +1,98 @@
+//===-- RegisterContextPOSIX_arm.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#include <cstdint>
+#include <cstring>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_arm.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool RegisterContextPOSIX_arm::IsGPR(unsigned reg) {
+ if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_arm::GPRegSet)
+ return true;
+ return false;
+}
+
+bool RegisterContextPOSIX_arm::IsFPR(unsigned reg) {
+ if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_arm::FPRegSet)
+ return true;
+ return false;
+}
+
+RegisterContextPOSIX_arm::RegisterContextPOSIX_arm(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm> register_info)
+ : lldb_private::RegisterContext(thread, 0),
+ m_register_info_up(std::move(register_info)) {}
+
+RegisterContextPOSIX_arm::~RegisterContextPOSIX_arm() = default;
+
+void RegisterContextPOSIX_arm::Invalidate() {}
+
+void RegisterContextPOSIX_arm::InvalidateAllRegisters() {}
+
+unsigned RegisterContextPOSIX_arm::GetRegisterOffset(unsigned reg) {
+ return m_register_info_up->GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned RegisterContextPOSIX_arm::GetRegisterSize(unsigned reg) {
+ return m_register_info_up->GetRegisterInfo()[reg].byte_size;
+}
+
+size_t RegisterContextPOSIX_arm::GetRegisterCount() {
+ return m_register_info_up->GetRegisterCount();
+}
+
+size_t RegisterContextPOSIX_arm::GetGPRSize() {
+ return m_register_info_up->GetGPRSize();
+}
+
+const lldb_private::RegisterInfo *RegisterContextPOSIX_arm::GetRegisterInfo() {
+ // Commonly, this method is overridden and g_register_infos is copied and
+ // specialized. So, use GetRegisterInfo() rather than g_register_infos in
+ // this scope.
+ return m_register_info_up->GetRegisterInfo();
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_arm::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < GetRegisterCount())
+ return &GetRegisterInfo()[reg];
+
+ return nullptr;
+}
+
+size_t RegisterContextPOSIX_arm::GetRegisterSetCount() {
+ return m_register_info_up->GetRegisterSetCount();
+}
+
+const lldb_private::RegisterSet *
+RegisterContextPOSIX_arm::GetRegisterSet(size_t set) {
+ return m_register_info_up->GetRegisterSet(set);
+}
+
+const char *RegisterContextPOSIX_arm::GetRegisterName(unsigned reg) {
+ if (reg < GetRegisterCount())
+ return GetRegisterInfo()[reg].name;
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
new file mode 100644
index 000000000000..099c37d46f49
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
@@ -0,0 +1,62 @@
+//===-- RegisterContextPOSIX_arm.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM_H
+
+#include "RegisterInfoInterface.h"
+#include "RegisterInfoPOSIX_arm.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+
+class RegisterContextPOSIX_arm : public lldb_private::RegisterContext {
+public:
+ RegisterContextPOSIX_arm(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm> register_info);
+
+ ~RegisterContextPOSIX_arm() override;
+
+ void Invalidate();
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ virtual size_t GetGPRSize();
+
+ virtual unsigned GetRegisterSize(unsigned reg);
+
+ virtual unsigned GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+protected:
+ std::unique_ptr<RegisterInfoPOSIX_arm> m_register_info_up;
+
+ virtual const lldb_private::RegisterInfo *GetRegisterInfo();
+
+ bool IsGPR(unsigned reg);
+
+ bool IsFPR(unsigned reg);
+
+ size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm::FPU); }
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
new file mode 100644
index 000000000000..50e25568f2ae
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
@@ -0,0 +1,119 @@
+//===-- RegisterContextPOSIX_arm64.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#include <cstdint>
+#include <cstring>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_arm64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool RegisterContextPOSIX_arm64::IsGPR(unsigned reg) {
+ if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_arm64::GPRegSet)
+ return true;
+ return false;
+}
+
+bool RegisterContextPOSIX_arm64::IsFPR(unsigned reg) {
+ if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_arm64::FPRegSet)
+ return true;
+ return false;
+}
+
+bool RegisterContextPOSIX_arm64::IsSVE(unsigned reg) const {
+ return m_register_info_up->IsSVEReg(reg);
+}
+
+bool RegisterContextPOSIX_arm64::IsSME(unsigned reg) const {
+ return m_register_info_up->IsSMEReg(reg);
+}
+
+bool RegisterContextPOSIX_arm64::IsPAuth(unsigned reg) const {
+ return m_register_info_up->IsPAuthReg(reg);
+}
+
+bool RegisterContextPOSIX_arm64::IsTLS(unsigned reg) const {
+ return m_register_info_up->IsTLSReg(reg);
+}
+
+bool RegisterContextPOSIX_arm64::IsMTE(unsigned reg) const {
+ return m_register_info_up->IsMTEReg(reg);
+}
+
+RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm64> register_info)
+ : lldb_private::RegisterContext(thread, 0),
+ m_register_info_up(std::move(register_info)) {}
+
+RegisterContextPOSIX_arm64::~RegisterContextPOSIX_arm64() = default;
+
+void RegisterContextPOSIX_arm64::Invalidate() {}
+
+void RegisterContextPOSIX_arm64::InvalidateAllRegisters() {}
+
+unsigned RegisterContextPOSIX_arm64::GetRegisterOffset(unsigned reg) {
+ return m_register_info_up->GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned RegisterContextPOSIX_arm64::GetRegisterSize(unsigned reg) {
+ return m_register_info_up->GetRegisterInfo()[reg].byte_size;
+}
+
+size_t RegisterContextPOSIX_arm64::GetRegisterCount() {
+ return m_register_info_up->GetRegisterCount();
+}
+
+size_t RegisterContextPOSIX_arm64::GetGPRSize() {
+ return m_register_info_up->GetGPRSize();
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_arm64::GetRegisterInfo() {
+ // Commonly, this method is overridden and g_register_infos is copied and
+ // specialized. So, use GetRegisterInfo() rather than g_register_infos in
+ // this scope.
+ return m_register_info_up->GetRegisterInfo();
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_arm64::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < GetRegisterCount())
+ return &GetRegisterInfo()[reg];
+
+ return nullptr;
+}
+
+size_t RegisterContextPOSIX_arm64::GetRegisterSetCount() {
+ return m_register_info_up->GetRegisterSetCount();
+}
+
+const lldb_private::RegisterSet *
+RegisterContextPOSIX_arm64::GetRegisterSet(size_t set) {
+ return m_register_info_up->GetRegisterSet(set);
+}
+
+const char *RegisterContextPOSIX_arm64::GetRegisterName(unsigned reg) {
+ if (reg < GetRegisterCount())
+ return GetRegisterInfo()[reg].name;
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
new file mode 100644
index 000000000000..b1226b25b4be
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
@@ -0,0 +1,86 @@
+//===-- RegisterContextPOSIX_arm64.h ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM64_H
+
+#include "RegisterInfoInterface.h"
+#include "RegisterInfoPOSIX_arm64.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+
+class RegisterContextPOSIX_arm64 : public lldb_private::RegisterContext {
+public:
+ RegisterContextPOSIX_arm64(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm64> register_info);
+
+ ~RegisterContextPOSIX_arm64() override;
+
+ void Invalidate();
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ virtual size_t GetGPRSize();
+
+ virtual unsigned GetRegisterSize(unsigned reg);
+
+ virtual unsigned GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+protected:
+ std::unique_ptr<RegisterInfoPOSIX_arm64> m_register_info_up;
+
+ virtual const lldb_private::RegisterInfo *GetRegisterInfo();
+
+ bool IsGPR(unsigned reg);
+
+ bool IsFPR(unsigned reg);
+
+ size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm64::FPU); }
+
+ bool IsSVE(unsigned reg) const;
+ bool IsPAuth(unsigned reg) const;
+ bool IsTLS(unsigned reg) const;
+ bool IsSME(unsigned reg) const;
+ bool IsMTE(unsigned reg) const;
+
+ bool IsSVEZ(unsigned reg) const { return m_register_info_up->IsSVEZReg(reg); }
+ bool IsSVEP(unsigned reg) const { return m_register_info_up->IsSVEPReg(reg); }
+ bool IsSVEVG(unsigned reg) const {
+ return m_register_info_up->IsSVERegVG(reg);
+ }
+ bool IsSMEZA(unsigned reg) const {
+ return m_register_info_up->IsSMERegZA(reg);
+ }
+
+ uint32_t GetRegNumSVEZ0() const {
+ return m_register_info_up->GetRegNumSVEZ0();
+ }
+ uint32_t GetRegNumSVEFFR() const {
+ return m_register_info_up->GetRegNumSVEFFR();
+ }
+ uint32_t GetRegNumFPCR() const { return m_register_info_up->GetRegNumFPCR(); }
+ uint32_t GetRegNumFPSR() const { return m_register_info_up->GetRegNumFPSR(); }
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.cpp
new file mode 100644
index 000000000000..a48a58f28f7a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.cpp
@@ -0,0 +1,82 @@
+//===-- RegisterContextPOSIX_loongarch64.cpp --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_loongarch64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextPOSIX_loongarch64::RegisterContextPOSIX_loongarch64(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_loongarch64> register_info)
+ : lldb_private::RegisterContext(thread, 0),
+ m_register_info_up(std::move(register_info)) {}
+
+RegisterContextPOSIX_loongarch64::~RegisterContextPOSIX_loongarch64() = default;
+
+void RegisterContextPOSIX_loongarch64::invalidate() {}
+
+void RegisterContextPOSIX_loongarch64::InvalidateAllRegisters() {}
+
+size_t RegisterContextPOSIX_loongarch64::GetRegisterCount() {
+ return m_register_info_up->GetRegisterCount();
+}
+
+size_t RegisterContextPOSIX_loongarch64::GetGPRSize() {
+ return m_register_info_up->GetGPRSize();
+}
+
+unsigned RegisterContextPOSIX_loongarch64::GetRegisterSize(unsigned int reg) {
+ return m_register_info_up->GetRegisterInfo()[reg].byte_size;
+}
+
+unsigned RegisterContextPOSIX_loongarch64::GetRegisterOffset(unsigned int reg) {
+ return m_register_info_up->GetRegisterInfo()[reg].byte_offset;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_loongarch64::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < GetRegisterCount())
+ return &GetRegisterInfo()[reg];
+
+ return nullptr;
+}
+
+size_t RegisterContextPOSIX_loongarch64::GetRegisterSetCount() {
+ return m_register_info_up->GetRegisterCount();
+}
+
+const lldb_private::RegisterSet *
+RegisterContextPOSIX_loongarch64::GetRegisterSet(size_t set) {
+ return m_register_info_up->GetRegisterSet(set);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_loongarch64::GetRegisterInfo() {
+ return m_register_info_up->GetRegisterInfo();
+}
+
+bool RegisterContextPOSIX_loongarch64::IsGPR(unsigned int reg) {
+ return m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_loongarch64::GPRegSet;
+}
+
+bool RegisterContextPOSIX_loongarch64::IsFPR(unsigned int reg) {
+ return m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_loongarch64::FPRegSet;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.h
new file mode 100644
index 000000000000..95f93bb41f01
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_loongarch64.h
@@ -0,0 +1,63 @@
+//===-- RegisterContextPOSIX_loongarch64.h ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_LOONGARCH64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_LOONGARCH64_H
+
+#include "RegisterInfoInterface.h"
+#include "RegisterInfoPOSIX_loongarch64.h"
+#include "lldb-loongarch-register-enums.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+
+class RegisterContextPOSIX_loongarch64 : public lldb_private::RegisterContext {
+public:
+ RegisterContextPOSIX_loongarch64(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_loongarch64> register_info);
+
+ ~RegisterContextPOSIX_loongarch64() override;
+
+ void invalidate();
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ virtual size_t GetGPRSize();
+
+ virtual unsigned GetRegisterSize(unsigned reg);
+
+ virtual unsigned GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+protected:
+ std::unique_ptr<RegisterInfoPOSIX_loongarch64> m_register_info_up;
+
+ virtual const lldb_private::RegisterInfo *GetRegisterInfo();
+
+ bool IsGPR(unsigned reg);
+
+ bool IsFPR(unsigned reg);
+
+ size_t GetFPRSize() { return sizeof(RegisterInfoPOSIX_loongarch64::FPR); }
+
+ uint32_t GetRegNumFCSR() const { return fpr_fcsr_loongarch; }
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_LOONGARCH64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp
new file mode 100644
index 000000000000..3685d6ac72ad
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp
@@ -0,0 +1,138 @@
+//===-- RegisterContextPOSIX_mips64.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#include <cstdint>
+#include <cstring>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_mips64.h"
+#include "RegisterContextFreeBSD_mips64.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+bool RegisterContextPOSIX_mips64::IsGPR(unsigned reg) {
+ return reg < m_registers_count[gpr_registers_count]; // GPR's come first.
+}
+
+bool RegisterContextPOSIX_mips64::IsFPR(unsigned reg) {
+ int set = GetRegisterSetCount();
+ if (set > 1)
+ return reg < (m_registers_count[fpr_registers_count]
+ + m_registers_count[gpr_registers_count]);
+ return false;
+}
+
+RegisterContextPOSIX_mips64::RegisterContextPOSIX_mips64(
+ Thread &thread, uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info)
+ : RegisterContext(thread, concrete_frame_idx) {
+ m_register_info_up.reset(register_info);
+ m_num_registers = GetRegisterCount();
+ int set = GetRegisterSetCount();
+
+ const RegisterSet *reg_set_ptr;
+ for(int i = 0; i < set; ++i) {
+ reg_set_ptr = GetRegisterSet(i);
+ m_registers_count[i] = reg_set_ptr->num_registers;
+ }
+
+ assert(m_num_registers ==
+ static_cast<uint32_t>(m_registers_count[gpr_registers_count] +
+ m_registers_count[fpr_registers_count] +
+ m_registers_count[msa_registers_count]));
+}
+
+RegisterContextPOSIX_mips64::~RegisterContextPOSIX_mips64() = default;
+
+void RegisterContextPOSIX_mips64::Invalidate() {}
+
+void RegisterContextPOSIX_mips64::InvalidateAllRegisters() {}
+
+unsigned RegisterContextPOSIX_mips64::GetRegisterOffset(unsigned reg) {
+ assert(reg < m_num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned RegisterContextPOSIX_mips64::GetRegisterSize(unsigned reg) {
+ assert(reg < m_num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t RegisterContextPOSIX_mips64::GetRegisterCount() {
+ return m_register_info_up->GetRegisterCount();
+}
+
+size_t RegisterContextPOSIX_mips64::GetGPRSize() {
+ return m_register_info_up->GetGPRSize();
+}
+
+const RegisterInfo *RegisterContextPOSIX_mips64::GetRegisterInfo() {
+ // Commonly, this method is overridden and g_register_infos is copied and
+ // specialized. So, use GetRegisterInfo() rather than g_register_infos in
+ // this scope.
+ return m_register_info_up->GetRegisterInfo();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_mips64::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < m_num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return nullptr;
+}
+
+size_t RegisterContextPOSIX_mips64::GetRegisterSetCount() {
+ const auto *context = static_cast<const RegisterContextFreeBSD_mips64 *>(
+ m_register_info_up.get());
+ return context->GetRegisterSetCount();
+}
+
+const RegisterSet *RegisterContextPOSIX_mips64::GetRegisterSet(size_t set) {
+ const auto *context = static_cast<const RegisterContextFreeBSD_mips64 *>(
+ m_register_info_up.get());
+ return context->GetRegisterSet(set);
+}
+
+const char *RegisterContextPOSIX_mips64::GetRegisterName(unsigned reg) {
+ assert(reg < m_num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+bool RegisterContextPOSIX_mips64::IsRegisterSetAvailable(size_t set_index) {
+ size_t num_sets = GetRegisterSetCount();
+
+ return (set_index < num_sets);
+}
+
+// Used when parsing DWARF and EH frame information and any other object file
+// sections that contain register numbers in them.
+uint32_t RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ const uint32_t num_regs = m_num_registers;
+
+ 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;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
new file mode 100644
index 000000000000..b66dc3f44524
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
@@ -0,0 +1,78 @@
+//===-- RegisterContextPOSIX_mips64.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_MIPS64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_MIPS64_H
+
+#include "RegisterContext_mips.h"
+#include "RegisterInfoInterface.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+
+class RegisterContextPOSIX_mips64 : public lldb_private::RegisterContext {
+public:
+
+ enum Register_count{
+ gpr_registers_count = 0,
+ fpr_registers_count,
+ msa_registers_count,
+ register_set_count
+ };
+
+ RegisterContextPOSIX_mips64(
+ lldb_private::Thread &thread, uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_mips64() override;
+
+ void Invalidate();
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ virtual size_t GetGPRSize();
+
+ virtual unsigned GetRegisterSize(unsigned reg);
+
+ virtual unsigned GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+protected:
+ uint32_t m_num_registers;
+ uint8_t m_registers_count[register_set_count];
+ std::unique_ptr<lldb_private::RegisterInfoInterface>
+ m_register_info_up; // Register Info Interface (FreeBSD or Linux)
+
+ // Determines if an extended register set is supported on the processor
+ // running the inferior process.
+ virtual bool IsRegisterSetAvailable(size_t set_index);
+
+ virtual const lldb_private::RegisterInfo *GetRegisterInfo();
+
+ bool IsGPR(unsigned reg);
+
+ bool IsFPR(unsigned reg);
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_MIPS64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
new file mode 100644
index 000000000000..cffd2865e385
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
@@ -0,0 +1,164 @@
+//===-- RegisterContextPOSIX_powerpc.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#include <cstdint>
+#include <cstring>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_powerpc.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+static const uint32_t g_gpr_regnums[] = {
+ gpr_r0_powerpc, gpr_r1_powerpc, gpr_r2_powerpc, gpr_r3_powerpc,
+ gpr_r4_powerpc, gpr_r5_powerpc, gpr_r6_powerpc, gpr_r7_powerpc,
+ gpr_r8_powerpc, gpr_r9_powerpc, gpr_r10_powerpc, gpr_r11_powerpc,
+ gpr_r12_powerpc, gpr_r13_powerpc, gpr_r14_powerpc, gpr_r15_powerpc,
+ gpr_r16_powerpc, gpr_r17_powerpc, gpr_r18_powerpc, gpr_r19_powerpc,
+ gpr_r20_powerpc, gpr_r21_powerpc, gpr_r22_powerpc, gpr_r23_powerpc,
+ gpr_r24_powerpc, gpr_r25_powerpc, gpr_r26_powerpc, gpr_r27_powerpc,
+ gpr_r28_powerpc, gpr_r29_powerpc, gpr_r30_powerpc, gpr_r31_powerpc,
+ gpr_lr_powerpc, gpr_cr_powerpc, gpr_xer_powerpc, gpr_ctr_powerpc,
+ gpr_pc_powerpc,
+};
+
+static const uint32_t g_fpr_regnums[] = {
+ fpr_f0_powerpc, fpr_f1_powerpc, fpr_f2_powerpc, fpr_f3_powerpc,
+ fpr_f4_powerpc, fpr_f5_powerpc, fpr_f6_powerpc, fpr_f7_powerpc,
+ fpr_f8_powerpc, fpr_f9_powerpc, fpr_f10_powerpc, fpr_f11_powerpc,
+ fpr_f12_powerpc, fpr_f13_powerpc, fpr_f14_powerpc, fpr_f15_powerpc,
+ fpr_f16_powerpc, fpr_f17_powerpc, fpr_f18_powerpc, fpr_f19_powerpc,
+ fpr_f20_powerpc, fpr_f21_powerpc, fpr_f22_powerpc, fpr_f23_powerpc,
+ fpr_f24_powerpc, fpr_f25_powerpc, fpr_f26_powerpc, fpr_f27_powerpc,
+ fpr_f28_powerpc, fpr_f29_powerpc, fpr_f30_powerpc, fpr_f31_powerpc,
+ fpr_fpscr_powerpc,
+};
+
+static const uint32_t g_vmx_regnums[] = {
+ vmx_v0_powerpc, vmx_v1_powerpc, vmx_v2_powerpc, vmx_v3_powerpc,
+ vmx_v4_powerpc, vmx_v5_powerpc, vmx_v6_powerpc, vmx_v7_powerpc,
+ vmx_v8_powerpc, vmx_v9_powerpc, vmx_v10_powerpc, vmx_v11_powerpc,
+ vmx_v12_powerpc, vmx_v13_powerpc, vmx_v14_powerpc, vmx_v15_powerpc,
+ vmx_v16_powerpc, vmx_v17_powerpc, vmx_v18_powerpc, vmx_v19_powerpc,
+ vmx_v20_powerpc, vmx_v21_powerpc, vmx_v22_powerpc, vmx_v23_powerpc,
+ vmx_v24_powerpc, vmx_v25_powerpc, vmx_v26_powerpc, vmx_v27_powerpc,
+ vmx_v28_powerpc, vmx_v29_powerpc, vmx_v30_powerpc, vmx_v31_powerpc,
+ vmx_vrsave_powerpc, vmx_vscr_powerpc,
+};
+
+// Number of register sets provided by this context.
+enum { k_num_register_sets = 3 };
+
+static const RegisterSet g_reg_sets_powerpc[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_powerpc,
+ g_gpr_regnums},
+ {"Floating Point Registers", "fpr", k_num_fpr_registers_powerpc,
+ g_fpr_regnums},
+ {"Altivec/VMX Registers", "vmx", k_num_vmx_registers_powerpc,
+ g_vmx_regnums},
+};
+
+static_assert(k_first_gpr_powerpc == 0,
+ "GPRs must index starting at 0, or fix IsGPR()");
+bool RegisterContextPOSIX_powerpc::IsGPR(unsigned reg) {
+ return (reg <= k_last_gpr_powerpc); // GPR's come first.
+}
+
+bool RegisterContextPOSIX_powerpc::IsFPR(unsigned reg) {
+ return (reg >= k_first_fpr) && (reg <= k_last_fpr);
+}
+
+bool RegisterContextPOSIX_powerpc::IsVMX(unsigned reg) {
+ return (reg >= k_first_vmx) && (reg <= k_last_vmx);
+}
+
+RegisterContextPOSIX_powerpc::RegisterContextPOSIX_powerpc(
+ Thread &thread, uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info)
+ : RegisterContext(thread, concrete_frame_idx) {
+ m_register_info_up.reset(register_info);
+}
+
+RegisterContextPOSIX_powerpc::~RegisterContextPOSIX_powerpc() = default;
+
+void RegisterContextPOSIX_powerpc::Invalidate() {}
+
+void RegisterContextPOSIX_powerpc::InvalidateAllRegisters() {}
+
+unsigned RegisterContextPOSIX_powerpc::GetRegisterOffset(unsigned reg) {
+ assert(reg < k_num_registers_powerpc && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned RegisterContextPOSIX_powerpc::GetRegisterSize(unsigned reg) {
+ assert(reg < k_num_registers_powerpc && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t RegisterContextPOSIX_powerpc::GetRegisterCount() {
+ size_t num_registers = k_num_registers_powerpc;
+ return num_registers;
+}
+
+size_t RegisterContextPOSIX_powerpc::GetGPRSize() {
+ return m_register_info_up->GetGPRSize();
+}
+
+const RegisterInfo *RegisterContextPOSIX_powerpc::GetRegisterInfo() {
+ // Commonly, this method is overridden and g_register_infos is copied and
+ // specialized. So, use GetRegisterInfo() rather than g_register_infos in
+ // this scope.
+ return m_register_info_up->GetRegisterInfo();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_powerpc::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < k_num_registers_powerpc)
+ return &GetRegisterInfo()[reg];
+ else
+ return nullptr;
+}
+
+size_t RegisterContextPOSIX_powerpc::GetRegisterSetCount() {
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set) {
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const RegisterSet *RegisterContextPOSIX_powerpc::GetRegisterSet(size_t set) {
+ if (IsRegisterSetAvailable(set))
+ return &g_reg_sets_powerpc[set];
+ else
+ return nullptr;
+}
+
+const char *RegisterContextPOSIX_powerpc::GetRegisterName(unsigned reg) {
+ assert(reg < k_num_registers_powerpc && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+bool RegisterContextPOSIX_powerpc::IsRegisterSetAvailable(size_t set_index) {
+ size_t num_sets = k_num_register_sets;
+
+ return (set_index < num_sets);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
new file mode 100644
index 000000000000..5dd8c890da6e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
@@ -0,0 +1,195 @@
+//===-- RegisterContextPOSIX_powerpc.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_POWERPC_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_POWERPC_H
+
+#include "RegisterContext_powerpc.h"
+#include "RegisterInfoInterface.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+
+// Internal codes for all powerpc registers.
+enum {
+ k_first_gpr_powerpc,
+ gpr_r0_powerpc = k_first_gpr_powerpc,
+ gpr_r1_powerpc,
+ gpr_r2_powerpc,
+ gpr_r3_powerpc,
+ gpr_r4_powerpc,
+ gpr_r5_powerpc,
+ gpr_r6_powerpc,
+ gpr_r7_powerpc,
+ gpr_r8_powerpc,
+ gpr_r9_powerpc,
+ gpr_r10_powerpc,
+ gpr_r11_powerpc,
+ gpr_r12_powerpc,
+ gpr_r13_powerpc,
+ gpr_r14_powerpc,
+ gpr_r15_powerpc,
+ gpr_r16_powerpc,
+ gpr_r17_powerpc,
+ gpr_r18_powerpc,
+ gpr_r19_powerpc,
+ gpr_r20_powerpc,
+ gpr_r21_powerpc,
+ gpr_r22_powerpc,
+ gpr_r23_powerpc,
+ gpr_r24_powerpc,
+ gpr_r25_powerpc,
+ gpr_r26_powerpc,
+ gpr_r27_powerpc,
+ gpr_r28_powerpc,
+ gpr_r29_powerpc,
+ gpr_r30_powerpc,
+ gpr_r31_powerpc,
+ gpr_lr_powerpc,
+ gpr_cr_powerpc,
+ gpr_xer_powerpc,
+ gpr_ctr_powerpc,
+ gpr_pc_powerpc,
+ k_last_gpr_powerpc = gpr_pc_powerpc,
+
+ k_first_fpr,
+ fpr_f0_powerpc = k_first_fpr,
+ fpr_f1_powerpc,
+ fpr_f2_powerpc,
+ fpr_f3_powerpc,
+ fpr_f4_powerpc,
+ fpr_f5_powerpc,
+ fpr_f6_powerpc,
+ fpr_f7_powerpc,
+ fpr_f8_powerpc,
+ fpr_f9_powerpc,
+ fpr_f10_powerpc,
+ fpr_f11_powerpc,
+ fpr_f12_powerpc,
+ fpr_f13_powerpc,
+ fpr_f14_powerpc,
+ fpr_f15_powerpc,
+ fpr_f16_powerpc,
+ fpr_f17_powerpc,
+ fpr_f18_powerpc,
+ fpr_f19_powerpc,
+ fpr_f20_powerpc,
+ fpr_f21_powerpc,
+ fpr_f22_powerpc,
+ fpr_f23_powerpc,
+ fpr_f24_powerpc,
+ fpr_f25_powerpc,
+ fpr_f26_powerpc,
+ fpr_f27_powerpc,
+ fpr_f28_powerpc,
+ fpr_f29_powerpc,
+ fpr_f30_powerpc,
+ fpr_f31_powerpc,
+ fpr_fpscr_powerpc,
+ k_last_fpr = fpr_fpscr_powerpc,
+
+ k_first_vmx,
+ vmx_v0_powerpc = k_first_vmx,
+ vmx_v1_powerpc,
+ vmx_v2_powerpc,
+ vmx_v3_powerpc,
+ vmx_v4_powerpc,
+ vmx_v5_powerpc,
+ vmx_v6_powerpc,
+ vmx_v7_powerpc,
+ vmx_v8_powerpc,
+ vmx_v9_powerpc,
+ vmx_v10_powerpc,
+ vmx_v11_powerpc,
+ vmx_v12_powerpc,
+ vmx_v13_powerpc,
+ vmx_v14_powerpc,
+ vmx_v15_powerpc,
+ vmx_v16_powerpc,
+ vmx_v17_powerpc,
+ vmx_v18_powerpc,
+ vmx_v19_powerpc,
+ vmx_v20_powerpc,
+ vmx_v21_powerpc,
+ vmx_v22_powerpc,
+ vmx_v23_powerpc,
+ vmx_v24_powerpc,
+ vmx_v25_powerpc,
+ vmx_v26_powerpc,
+ vmx_v27_powerpc,
+ vmx_v28_powerpc,
+ vmx_v29_powerpc,
+ vmx_v30_powerpc,
+ vmx_v31_powerpc,
+ vmx_vrsave_powerpc,
+ vmx_vscr_powerpc,
+ k_last_vmx = vmx_vscr_powerpc,
+
+ k_num_registers_powerpc,
+ k_num_gpr_registers_powerpc = k_last_gpr_powerpc - k_first_gpr_powerpc + 1,
+ k_num_fpr_registers_powerpc = k_last_fpr - k_first_fpr + 1,
+ k_num_vmx_registers_powerpc = k_last_vmx - k_first_vmx + 1,
+};
+
+class RegisterContextPOSIX_powerpc : public lldb_private::RegisterContext {
+public:
+ RegisterContextPOSIX_powerpc(
+ lldb_private::Thread &thread, uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_powerpc() override;
+
+ void Invalidate();
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ virtual size_t GetGPRSize();
+
+ virtual unsigned GetRegisterSize(unsigned reg);
+
+ virtual unsigned GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+protected:
+ uint64_t
+ m_gpr_powerpc[k_num_gpr_registers_powerpc]; // general purpose registers.
+ uint64_t
+ m_fpr_powerpc[k_num_fpr_registers_powerpc]; // floating point registers.
+ uint32_t m_vmx_powerpc[k_num_vmx_registers_powerpc][4];
+ std::unique_ptr<lldb_private::RegisterInfoInterface>
+ m_register_info_up; // Register Info Interface (FreeBSD or Linux)
+
+ // Determines if an extended register set is supported on the processor
+ // running the inferior process.
+ virtual bool IsRegisterSetAvailable(size_t set_index);
+
+ virtual const lldb_private::RegisterInfo *GetRegisterInfo();
+
+ bool IsGPR(unsigned reg);
+
+ bool IsFPR(unsigned reg);
+
+ bool IsVMX(unsigned reg);
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool ReadVMX() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+ virtual bool WriteVMX() = 0;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_POWERPC_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp
new file mode 100644
index 000000000000..f70ddeba209c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp
@@ -0,0 +1,183 @@
+//===-- RegisterContextPOSIX_ppc64le.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#include <cstdint>
+#include <cstring>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_ppc64le.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+static const uint32_t g_gpr_regnums[] = {
+ gpr_r0_ppc64le, gpr_r1_ppc64le, gpr_r2_ppc64le, gpr_r3_ppc64le,
+ gpr_r4_ppc64le, gpr_r5_ppc64le, gpr_r6_ppc64le, gpr_r7_ppc64le,
+ gpr_r8_ppc64le, gpr_r9_ppc64le, gpr_r10_ppc64le, gpr_r11_ppc64le,
+ gpr_r12_ppc64le, gpr_r13_ppc64le, gpr_r14_ppc64le, gpr_r15_ppc64le,
+ gpr_r16_ppc64le, gpr_r17_ppc64le, gpr_r18_ppc64le, gpr_r19_ppc64le,
+ gpr_r20_ppc64le, gpr_r21_ppc64le, gpr_r22_ppc64le, gpr_r23_ppc64le,
+ gpr_r24_ppc64le, gpr_r25_ppc64le, gpr_r26_ppc64le, gpr_r27_ppc64le,
+ gpr_r28_ppc64le, gpr_r29_ppc64le, gpr_r30_ppc64le, gpr_r31_ppc64le,
+ gpr_pc_ppc64le, gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le,
+ gpr_lr_ppc64le, gpr_xer_ppc64le, gpr_cr_ppc64le, gpr_softe_ppc64le,
+ gpr_trap_ppc64le,
+};
+
+static const uint32_t g_fpr_regnums[] = {
+ fpr_f0_ppc64le, fpr_f1_ppc64le, fpr_f2_ppc64le, fpr_f3_ppc64le,
+ fpr_f4_ppc64le, fpr_f5_ppc64le, fpr_f6_ppc64le, fpr_f7_ppc64le,
+ fpr_f8_ppc64le, fpr_f9_ppc64le, fpr_f10_ppc64le, fpr_f11_ppc64le,
+ fpr_f12_ppc64le, fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le,
+ fpr_f16_ppc64le, fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le,
+ fpr_f20_ppc64le, fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le,
+ fpr_f24_ppc64le, fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le,
+ fpr_f28_ppc64le, fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le,
+ fpr_fpscr_ppc64le,
+};
+
+static const uint32_t g_vmx_regnums[] = {
+ vmx_vr0_ppc64le, vmx_vr1_ppc64le, vmx_vr2_ppc64le, vmx_vr3_ppc64le,
+ vmx_vr4_ppc64le, vmx_vr5_ppc64le, vmx_vr6_ppc64le, vmx_vr7_ppc64le,
+ vmx_vr8_ppc64le, vmx_vr9_ppc64le, vmx_vr10_ppc64le, vmx_vr11_ppc64le,
+ vmx_vr12_ppc64le, vmx_vr13_ppc64le, vmx_vr14_ppc64le, vmx_vr15_ppc64le,
+ vmx_vr16_ppc64le, vmx_vr17_ppc64le, vmx_vr18_ppc64le, vmx_vr19_ppc64le,
+ vmx_vr20_ppc64le, vmx_vr21_ppc64le, vmx_vr22_ppc64le, vmx_vr23_ppc64le,
+ vmx_vr24_ppc64le, vmx_vr25_ppc64le, vmx_vr26_ppc64le, vmx_vr27_ppc64le,
+ vmx_vr28_ppc64le, vmx_vr29_ppc64le, vmx_vr30_ppc64le, vmx_vr31_ppc64le,
+ vmx_vscr_ppc64le, vmx_vrsave_ppc64le,
+};
+
+static const uint32_t g_vsx_regnums[] = {
+ vsx_vs0_ppc64le, vsx_vs1_ppc64le, vsx_vs2_ppc64le, vsx_vs3_ppc64le,
+ vsx_vs4_ppc64le, vsx_vs5_ppc64le, vsx_vs6_ppc64le, vsx_vs7_ppc64le,
+ vsx_vs8_ppc64le, vsx_vs9_ppc64le, vsx_vs10_ppc64le, vsx_vs11_ppc64le,
+ vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le,
+ vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le,
+ vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le,
+ vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le,
+ vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le,
+ vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le,
+ vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le,
+ vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le,
+ vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le,
+ vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le,
+ vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le,
+ vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le,
+ vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le,
+};
+
+// Number of register sets provided by this context.
+enum { k_num_register_sets = 4 };
+
+static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le,
+ g_gpr_regnums},
+ {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le,
+ g_fpr_regnums},
+ {"Altivec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le,
+ g_vmx_regnums},
+ {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le, g_vsx_regnums},
+};
+
+bool RegisterContextPOSIX_ppc64le::IsGPR(unsigned reg) {
+ return (reg <= k_last_gpr_ppc64le); // GPR's come first.
+}
+
+bool RegisterContextPOSIX_ppc64le::IsFPR(unsigned reg) {
+ return (reg >= k_first_fpr_ppc64le) && (reg <= k_last_fpr_ppc64le);
+}
+
+bool RegisterContextPOSIX_ppc64le::IsVMX(unsigned reg) {
+ return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le);
+}
+
+bool RegisterContextPOSIX_ppc64le::IsVSX(unsigned reg) {
+ return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le);
+}
+
+RegisterContextPOSIX_ppc64le::RegisterContextPOSIX_ppc64le(
+ Thread &thread, uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info)
+ : RegisterContext(thread, concrete_frame_idx) {
+ m_register_info_up.reset(register_info);
+}
+
+void RegisterContextPOSIX_ppc64le::InvalidateAllRegisters() {}
+
+unsigned RegisterContextPOSIX_ppc64le::GetRegisterOffset(unsigned reg) {
+ assert(reg < k_num_registers_ppc64le && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned RegisterContextPOSIX_ppc64le::GetRegisterSize(unsigned reg) {
+ assert(reg < k_num_registers_ppc64le && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t RegisterContextPOSIX_ppc64le::GetRegisterCount() {
+ size_t num_registers = k_num_registers_ppc64le;
+ return num_registers;
+}
+
+size_t RegisterContextPOSIX_ppc64le::GetGPRSize() {
+ return m_register_info_up->GetGPRSize();
+}
+
+const RegisterInfo *RegisterContextPOSIX_ppc64le::GetRegisterInfo() {
+ // Commonly, this method is overridden and g_register_infos is copied and
+ // specialized. So, use GetRegisterInfo() rather than g_register_infos in
+ // this scope.
+ return m_register_info_up->GetRegisterInfo();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_ppc64le::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < k_num_registers_ppc64le)
+ return &GetRegisterInfo()[reg];
+ else
+ return nullptr;
+}
+
+size_t RegisterContextPOSIX_ppc64le::GetRegisterSetCount() {
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set) {
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const RegisterSet *RegisterContextPOSIX_ppc64le::GetRegisterSet(size_t set) {
+ if (IsRegisterSetAvailable(set))
+ return &g_reg_sets_ppc64le[set];
+ else
+ return nullptr;
+}
+
+const char *RegisterContextPOSIX_ppc64le::GetRegisterName(unsigned reg) {
+ assert(reg < k_num_registers_ppc64le && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+bool RegisterContextPOSIX_ppc64le::IsRegisterSetAvailable(size_t set_index) {
+ size_t num_sets = k_num_register_sets;
+
+ return (set_index < num_sets);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h
new file mode 100644
index 000000000000..66794ec9e9ca
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h
@@ -0,0 +1,73 @@
+//===-- RegisterContextPOSIX_ppc64le.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_PPC64LE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_PPC64LE_H
+
+#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
+#include "RegisterInfoInterface.h"
+#include "Utility/PPC64LE_DWARF_Registers.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+
+class RegisterContextPOSIX_ppc64le : public lldb_private::RegisterContext {
+public:
+ RegisterContextPOSIX_ppc64le(
+ lldb_private::Thread &thread, uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ virtual size_t GetGPRSize();
+
+ virtual unsigned GetRegisterSize(unsigned reg);
+
+ virtual unsigned GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+protected:
+ // 64-bit general purpose registers.
+ uint64_t m_gpr_ppc64le[k_num_gpr_registers_ppc64le];
+
+ // floating-point registers including extended register.
+ uint64_t m_fpr_ppc64le[k_num_fpr_registers_ppc64le];
+
+ // VMX registers.
+ uint64_t m_vmx_ppc64le[k_num_vmx_registers_ppc64le * 2];
+
+ // VSX registers.
+ uint64_t m_vsx_ppc64le[k_num_vsx_registers_ppc64le * 2];
+
+ std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_up;
+
+ // Determines if an extended register set is supported on the processor
+ // running the inferior process.
+ virtual bool IsRegisterSetAvailable(size_t set_index);
+
+ virtual const lldb_private::RegisterInfo *GetRegisterInfo();
+
+ bool IsGPR(unsigned reg);
+
+ bool IsFPR(unsigned reg);
+
+ bool IsVMX(unsigned reg);
+
+ bool IsVSX(unsigned reg);
+
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_PPC64LE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.cpp
new file mode 100644
index 000000000000..035ce00e1162
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.cpp
@@ -0,0 +1,82 @@
+//===-- RegisterContextPOSIX_riscv64.cpp ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_riscv64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextPOSIX_riscv64::RegisterContextPOSIX_riscv64(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info)
+ : lldb_private::RegisterContext(thread, 0),
+ m_register_info_up(std::move(register_info)) {}
+
+RegisterContextPOSIX_riscv64::~RegisterContextPOSIX_riscv64() = default;
+
+void RegisterContextPOSIX_riscv64::invalidate() {}
+
+void RegisterContextPOSIX_riscv64::InvalidateAllRegisters() {}
+
+size_t RegisterContextPOSIX_riscv64::GetRegisterCount() {
+ return m_register_info_up->GetRegisterCount();
+}
+
+size_t RegisterContextPOSIX_riscv64::GetGPRSize() {
+ return m_register_info_up->GetGPRSize();
+}
+
+unsigned RegisterContextPOSIX_riscv64::GetRegisterSize(unsigned int reg) {
+ return m_register_info_up->GetRegisterInfo()[reg].byte_size;
+}
+
+unsigned RegisterContextPOSIX_riscv64::GetRegisterOffset(unsigned int reg) {
+ return m_register_info_up->GetRegisterInfo()[reg].byte_offset;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_riscv64::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < GetRegisterCount())
+ return &GetRegisterInfo()[reg];
+
+ return nullptr;
+}
+
+size_t RegisterContextPOSIX_riscv64::GetRegisterSetCount() {
+ return m_register_info_up->GetRegisterSetCount();
+}
+
+const lldb_private::RegisterSet *
+RegisterContextPOSIX_riscv64::GetRegisterSet(size_t set) {
+ return m_register_info_up->GetRegisterSet(set);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_riscv64::GetRegisterInfo() {
+ return m_register_info_up->GetRegisterInfo();
+}
+
+bool RegisterContextPOSIX_riscv64::IsGPR(unsigned int reg) {
+ return m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_riscv64::GPRegSet;
+}
+
+bool RegisterContextPOSIX_riscv64::IsFPR(unsigned int reg) {
+ return m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_riscv64::FPRegSet;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.h
new file mode 100644
index 000000000000..2431ed6ab8c6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.h
@@ -0,0 +1,63 @@
+//===-- RegisterContextPOSIX_riscv64.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_RISCV64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_RISCV64_H
+
+#include "RegisterInfoInterface.h"
+#include "RegisterInfoPOSIX_riscv64.h"
+#include "lldb-riscv-register-enums.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+
+class RegisterContextPOSIX_riscv64 : public lldb_private::RegisterContext {
+public:
+ RegisterContextPOSIX_riscv64(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info);
+
+ ~RegisterContextPOSIX_riscv64() override;
+
+ void invalidate();
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ virtual size_t GetGPRSize();
+
+ virtual unsigned GetRegisterSize(unsigned reg);
+
+ virtual unsigned GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+protected:
+ std::unique_ptr<RegisterInfoPOSIX_riscv64> m_register_info_up;
+
+ virtual const lldb_private::RegisterInfo *GetRegisterInfo();
+
+ bool IsGPR(unsigned reg);
+
+ bool IsFPR(unsigned reg);
+
+ size_t GetFPRSize() { return sizeof(RegisterInfoPOSIX_riscv64::FPR); }
+
+ uint32_t GetRegNumFCSR() const { return fpr_fcsr_riscv; }
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_RISCV64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp
new file mode 100644
index 000000000000..b85da39b4c45
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp
@@ -0,0 +1,163 @@
+//===-- RegisterContextPOSIX_s390x.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#include <cstdint>
+#include <cstring>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_s390x.h"
+#include "RegisterContext_s390x.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// s390x 64-bit general purpose registers.
+static const uint32_t g_gpr_regnums_s390x[] = {
+ lldb_r0_s390x, lldb_r1_s390x, lldb_r2_s390x, lldb_r3_s390x,
+ lldb_r4_s390x, lldb_r5_s390x, lldb_r6_s390x, lldb_r7_s390x,
+ lldb_r8_s390x, lldb_r9_s390x, lldb_r10_s390x, lldb_r11_s390x,
+ lldb_r12_s390x, lldb_r13_s390x, lldb_r14_s390x, lldb_r15_s390x,
+ lldb_acr0_s390x, lldb_acr1_s390x, lldb_acr2_s390x, lldb_acr3_s390x,
+ lldb_acr4_s390x, lldb_acr5_s390x, lldb_acr6_s390x, lldb_acr7_s390x,
+ lldb_acr8_s390x, lldb_acr9_s390x, lldb_acr10_s390x, lldb_acr11_s390x,
+ lldb_acr12_s390x, lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x,
+ lldb_pswm_s390x, lldb_pswa_s390x,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) -
+ 1 ==
+ k_num_gpr_registers_s390x,
+ "g_gpr_regnums_s390x has wrong number of register infos");
+
+// s390x 64-bit floating point registers.
+static const uint32_t g_fpu_regnums_s390x[] = {
+ lldb_f0_s390x, lldb_f1_s390x, lldb_f2_s390x, lldb_f3_s390x,
+ lldb_f4_s390x, lldb_f5_s390x, lldb_f6_s390x, lldb_f7_s390x,
+ lldb_f8_s390x, lldb_f9_s390x, lldb_f10_s390x, lldb_f11_s390x,
+ lldb_f12_s390x, lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x,
+ lldb_fpc_s390x,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) -
+ 1 ==
+ k_num_fpr_registers_s390x,
+ "g_fpu_regnums_s390x has wrong number of register infos");
+
+// Number of register sets provided by this context.
+enum { k_num_register_sets = 2 };
+
+// Register sets for s390x 64-bit.
+static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x,
+ g_gpr_regnums_s390x},
+ {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x,
+ g_fpu_regnums_s390x},
+};
+
+bool RegisterContextPOSIX_s390x::IsGPR(unsigned reg) {
+ return reg <= m_reg_info.last_gpr; // GPRs come first.
+}
+
+bool RegisterContextPOSIX_s390x::IsFPR(unsigned reg) {
+ return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
+}
+
+RegisterContextPOSIX_s390x::RegisterContextPOSIX_s390x(
+ Thread &thread, uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info)
+ : RegisterContext(thread, concrete_frame_idx) {
+ m_register_info_up.reset(register_info);
+
+ switch (register_info->GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::systemz:
+ m_reg_info.num_registers = k_num_registers_s390x;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x;
+ m_reg_info.last_gpr = k_last_gpr_s390x;
+ m_reg_info.first_fpr = k_first_fpr_s390x;
+ m_reg_info.last_fpr = k_last_fpr_s390x;
+ break;
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+}
+
+RegisterContextPOSIX_s390x::~RegisterContextPOSIX_s390x() = default;
+
+void RegisterContextPOSIX_s390x::Invalidate() {}
+
+void RegisterContextPOSIX_s390x::InvalidateAllRegisters() {}
+
+const RegisterInfo *RegisterContextPOSIX_s390x::GetRegisterInfo() {
+ return m_register_info_up->GetRegisterInfo();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_s390x::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < m_reg_info.num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return nullptr;
+}
+
+size_t RegisterContextPOSIX_s390x::GetRegisterCount() {
+ return m_reg_info.num_registers;
+}
+
+unsigned RegisterContextPOSIX_s390x::GetRegisterOffset(unsigned reg) {
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned RegisterContextPOSIX_s390x::GetRegisterSize(unsigned reg) {
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+const char *RegisterContextPOSIX_s390x::GetRegisterName(unsigned reg) {
+ assert(reg < m_reg_info.num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+bool RegisterContextPOSIX_s390x::IsRegisterSetAvailable(size_t set_index) {
+ return set_index < k_num_register_sets;
+}
+
+size_t RegisterContextPOSIX_s390x::GetRegisterSetCount() {
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set) {
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const RegisterSet *RegisterContextPOSIX_s390x::GetRegisterSet(size_t set) {
+ if (IsRegisterSetAvailable(set)) {
+ switch (m_register_info_up->GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::systemz:
+ return &g_reg_sets_s390x[set];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h
new file mode 100644
index 000000000000..7027af04f0bb
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h
@@ -0,0 +1,72 @@
+//===-- RegisterContextPOSIX_s390x.h ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_S390X_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_S390X_H
+
+#include "RegisterContext_s390x.h"
+#include "RegisterInfoInterface.h"
+#include "lldb-s390x-register-enums.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+
+class RegisterContextPOSIX_s390x : public lldb_private::RegisterContext {
+public:
+ RegisterContextPOSIX_s390x(
+ lldb_private::Thread &thread, uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_s390x() override;
+
+ void Invalidate();
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ virtual unsigned GetRegisterSize(unsigned reg);
+
+ virtual unsigned GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+protected:
+ 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;
+ };
+
+ RegInfo m_reg_info;
+ std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_up;
+
+ virtual bool IsRegisterSetAvailable(size_t set_index);
+
+ virtual const lldb_private::RegisterInfo *GetRegisterInfo();
+
+ bool IsGPR(unsigned reg);
+
+ bool IsFPR(unsigned reg);
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_S390X_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
new file mode 100644
index 000000000000..c14eb135c7b1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
@@ -0,0 +1,540 @@
+//===-- RegisterContextPOSIX_x86.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#include <cstdint>
+#include <cstring>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_x86.h"
+#include "RegisterContext_x86.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+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 must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+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");
+
+const uint32_t g_lldb_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 must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+static_assert((sizeof(g_lldb_regnums_i386) / sizeof(g_lldb_regnums_i386[0])) -
+ 1 ==
+ k_num_fpr_registers_i386,
+ "g_lldb_regnums_i386 has wrong number of register infos");
+
+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 must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+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");
+
+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 must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+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");
+
+static const uint32_t g_lldb_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_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64,
+ lldb_fdp_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 must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+static_assert((sizeof(g_lldb_regnums_x86_64) /
+ sizeof(g_lldb_regnums_x86_64[0])) -
+ 1 ==
+ k_num_fpr_registers_x86_64,
+ "g_lldb_regnums_x86_64 has wrong number of register infos");
+
+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 must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+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");
+
+uint32_t RegisterContextPOSIX_x86::g_contained_eax[] = {lldb_eax_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_ebx[] = {lldb_ebx_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_ecx[] = {lldb_ecx_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_edx[] = {lldb_edx_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_edi[] = {lldb_edi_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_esi[] = {lldb_esi_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_ebp[] = {lldb_ebp_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_esp[] = {lldb_esp_i386,
+ LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_eax[] = {
+ lldb_eax_i386, lldb_ax_i386, lldb_ah_i386, lldb_al_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_ebx[] = {
+ lldb_ebx_i386, lldb_bx_i386, lldb_bh_i386, lldb_bl_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_ecx[] = {
+ lldb_ecx_i386, lldb_cx_i386, lldb_ch_i386, lldb_cl_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_edx[] = {
+ lldb_edx_i386, lldb_dx_i386, lldb_dh_i386, lldb_dl_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_edi[] = {
+ lldb_edi_i386, lldb_di_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_esi[] = {
+ lldb_esi_i386, lldb_si_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_ebp[] = {
+ lldb_ebp_i386, lldb_bp_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_esp[] = {
+ lldb_esp_i386, lldb_sp_i386, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_contained_rax[] = {lldb_rax_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_rbx[] = {lldb_rbx_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_rcx[] = {lldb_rcx_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_rdx[] = {lldb_rdx_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_rdi[] = {lldb_rdi_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_rsi[] = {lldb_rsi_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_rbp[] = {lldb_rbp_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_rsp[] = {lldb_rsp_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_r8[] = {lldb_r8_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_r9[] = {lldb_r9_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_r10[] = {lldb_r10_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_r11[] = {lldb_r11_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_r12[] = {lldb_r12_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_r13[] = {lldb_r13_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_r14[] = {lldb_r14_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_r15[] = {lldb_r15_x86_64,
+ LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rax[] = {
+ lldb_rax_x86_64, lldb_eax_x86_64, lldb_ax_x86_64,
+ lldb_ah_x86_64, lldb_al_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rbx[] = {
+ lldb_rbx_x86_64, lldb_ebx_x86_64, lldb_bx_x86_64,
+ lldb_bh_x86_64, lldb_bl_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rcx[] = {
+ lldb_rcx_x86_64, lldb_ecx_x86_64, lldb_cx_x86_64,
+ lldb_ch_x86_64, lldb_cl_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rdx[] = {
+ lldb_rdx_x86_64, lldb_edx_x86_64, lldb_dx_x86_64,
+ lldb_dh_x86_64, lldb_dl_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rdi[] = {
+ lldb_rdi_x86_64, lldb_edi_x86_64, lldb_di_x86_64, lldb_dil_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rsi[] = {
+ lldb_rsi_x86_64, lldb_esi_x86_64, lldb_si_x86_64, lldb_sil_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rbp[] = {
+ lldb_rbp_x86_64, lldb_ebp_x86_64, lldb_bp_x86_64, lldb_bpl_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rsp[] = {
+ lldb_rsp_x86_64, lldb_esp_x86_64, lldb_sp_x86_64, lldb_spl_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r8[] = {
+ lldb_r8_x86_64, lldb_r8d_x86_64, lldb_r8w_x86_64, lldb_r8l_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r9[] = {
+ lldb_r9_x86_64, lldb_r9d_x86_64, lldb_r9w_x86_64, lldb_r9l_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r10[] = {
+ lldb_r10_x86_64, lldb_r10d_x86_64, lldb_r10w_x86_64, lldb_r10l_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r11[] = {
+ lldb_r11_x86_64, lldb_r11d_x86_64, lldb_r11w_x86_64, lldb_r11l_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r12[] = {
+ lldb_r12_x86_64, lldb_r12d_x86_64, lldb_r12w_x86_64, lldb_r12l_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r13[] = {
+ lldb_r13_x86_64, lldb_r13d_x86_64, lldb_r13w_x86_64, lldb_r13l_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r14[] = {
+ lldb_r14_x86_64, lldb_r14d_x86_64, lldb_r14w_x86_64, lldb_r14l_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r15[] = {
+ lldb_r15_x86_64, lldb_r15d_x86_64, lldb_r15w_x86_64, lldb_r15l_x86_64,
+ LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_contained_fip[] = {lldb_fip_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_fdp[] = {lldb_fdp_x86_64,
+ LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_fip[] = {
+ lldb_fip_x86_64, lldb_fioff_x86_64, lldb_fiseg_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_fdp[] = {
+ lldb_fdp_x86_64, lldb_fooff_x86_64, lldb_foseg_x86_64, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_contained_st0_32[] = {lldb_st0_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st1_32[] = {lldb_st1_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st2_32[] = {lldb_st2_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st3_32[] = {lldb_st3_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st4_32[] = {lldb_st4_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st5_32[] = {lldb_st5_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st6_32[] = {lldb_st6_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st7_32[] = {lldb_st7_i386,
+ LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st0_32[] = {
+ lldb_st0_i386, lldb_mm0_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st1_32[] = {
+ lldb_st1_i386, lldb_mm1_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st2_32[] = {
+ lldb_st2_i386, lldb_mm2_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st3_32[] = {
+ lldb_st3_i386, lldb_mm3_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st4_32[] = {
+ lldb_st4_i386, lldb_mm4_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st5_32[] = {
+ lldb_st5_i386, lldb_mm5_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st6_32[] = {
+ lldb_st6_i386, lldb_mm6_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st7_32[] = {
+ lldb_st7_i386, lldb_mm7_i386, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_contained_st0_64[] = {lldb_st0_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st1_64[] = {lldb_st1_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st2_64[] = {lldb_st2_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st3_64[] = {lldb_st3_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st4_64[] = {lldb_st4_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st5_64[] = {lldb_st5_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st6_64[] = {lldb_st6_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st7_64[] = {lldb_st7_x86_64,
+ LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st0_64[] = {
+ lldb_st0_x86_64, lldb_mm0_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st1_64[] = {
+ lldb_st1_x86_64, lldb_mm1_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st2_64[] = {
+ lldb_st2_x86_64, lldb_mm2_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st3_64[] = {
+ lldb_st3_x86_64, lldb_mm3_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st4_64[] = {
+ lldb_st4_x86_64, lldb_mm4_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st5_64[] = {
+ lldb_st5_x86_64, lldb_mm5_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st6_64[] = {
+ lldb_st6_x86_64, lldb_mm6_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st7_64[] = {
+ lldb_st7_x86_64, lldb_mm7_x86_64, LLDB_INVALID_REGNUM};
+
+// Number of register sets provided by this context.
+enum { k_num_extended_register_sets = 1, k_num_register_sets = 3 };
+
+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_lldb_regnums_i386},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386,
+ g_avx_regnums_i386}};
+
+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_lldb_regnums_x86_64},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64,
+ g_avx_regnums_x86_64}};
+
+bool RegisterContextPOSIX_x86::IsGPR(unsigned reg) {
+ return reg <= GetRegInfo().last_gpr; // GPR's come first.
+}
+
+bool RegisterContextPOSIX_x86::IsFPR(unsigned reg) {
+ return (GetRegInfo().first_fpr <= reg && reg <= GetRegInfo().last_fpr);
+}
+
+bool RegisterContextPOSIX_x86::IsAVX(unsigned reg) {
+ return (GetRegInfo().first_ymm <= reg && reg <= GetRegInfo().last_ymm);
+}
+
+bool RegisterContextPOSIX_x86::IsFPR(unsigned reg, FPRType fpr_type) {
+ bool generic_fpr = IsFPR(reg);
+
+ if (fpr_type == eXSAVE)
+ return generic_fpr || IsAVX(reg);
+ return generic_fpr;
+}
+
+RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(
+ Thread &thread, uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info)
+ : RegisterContext(thread, concrete_frame_idx) {
+ m_register_info_up.reset(register_info);
+
+ ::memset(&m_fpr, 0, sizeof(FPR));
+ ::memset(&m_ymm_set, 0, sizeof(YMM));
+
+ m_fpr_type = eNotValid;
+}
+
+RegisterContextPOSIX_x86::~RegisterContextPOSIX_x86() = default;
+
+RegisterContextPOSIX_x86::FPRType RegisterContextPOSIX_x86::GetFPRType() {
+ if (m_fpr_type == eNotValid) {
+ // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx
+ m_fpr_type = eXSAVE; // extended floating-point registers, if available
+ if (!ReadFPR())
+ m_fpr_type = eFXSAVE; // assume generic floating-point registers
+ }
+ return m_fpr_type;
+}
+
+void RegisterContextPOSIX_x86::Invalidate() {}
+
+void RegisterContextPOSIX_x86::InvalidateAllRegisters() {}
+
+unsigned RegisterContextPOSIX_x86::GetRegisterOffset(unsigned reg) {
+ assert(reg < GetRegInfo().num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+RegInfo &RegisterContextPOSIX_x86::GetRegInfo() {
+ return GetRegInfoShared(
+ m_register_info_up->GetTargetArchitecture().GetMachine(),
+ /*with_base=*/false);
+}
+
+unsigned RegisterContextPOSIX_x86::GetRegisterSize(unsigned reg) {
+ assert(reg < GetRegInfo().num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t RegisterContextPOSIX_x86::GetRegisterCount() {
+ size_t num_registers =
+ GetRegInfo().num_gpr_registers + GetRegInfo().num_fpr_registers;
+ if (GetFPRType() == eXSAVE)
+ return num_registers + GetRegInfo().num_avx_registers;
+ return num_registers;
+}
+
+size_t RegisterContextPOSIX_x86::GetGPRSize() {
+ return m_register_info_up->GetGPRSize();
+}
+
+size_t RegisterContextPOSIX_x86::GetFXSAVEOffset() {
+ return GetRegisterInfo()[GetRegInfo().first_fpr].byte_offset;
+}
+
+const RegisterInfo *RegisterContextPOSIX_x86::GetRegisterInfo() {
+ // Commonly, this method is overridden and g_register_infos is copied and
+ // specialized. So, use GetRegisterInfo() rather than g_register_infos in
+ // this scope.
+ return m_register_info_up->GetRegisterInfo();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_x86::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < GetRegInfo().num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return nullptr;
+}
+
+size_t RegisterContextPOSIX_x86::GetRegisterSetCount() {
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set) {
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const RegisterSet *RegisterContextPOSIX_x86::GetRegisterSet(size_t set) {
+ if (IsRegisterSetAvailable(set)) {
+ switch (m_register_info_up->GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ return &g_reg_sets_i386[set];
+ case llvm::Triple::x86_64:
+ return &g_reg_sets_x86_64[set];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
+
+const char *RegisterContextPOSIX_x86::GetRegisterName(unsigned reg) {
+ assert(reg < GetRegInfo().num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+// Parse ymm registers and into xmm.bytes and ymmh.bytes.
+bool RegisterContextPOSIX_x86::CopyYMMtoXSTATE(uint32_t reg,
+ lldb::ByteOrder byte_order) {
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == eByteOrderLittle) {
+ uint32_t reg_no = reg - GetRegInfo().first_ymm;
+ YMMToXState(m_ymm_set.ymm[reg_no], m_fpr.fxsave.xmm[reg_no].bytes,
+ m_fpr.xsave.ymmh[reg_no].bytes);
+ return true;
+ }
+
+ return false; // unsupported or invalid byte order
+}
+
+// Concatenate xmm.bytes with ymmh.bytes
+bool RegisterContextPOSIX_x86::CopyXSTATEtoYMM(uint32_t reg,
+ lldb::ByteOrder byte_order) {
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == eByteOrderLittle) {
+ uint32_t reg_no = reg - GetRegInfo().first_ymm;
+ m_ymm_set.ymm[reg_no] = XStateToYMM(m_fpr.fxsave.xmm[reg_no].bytes,
+ m_fpr.xsave.ymmh[reg_no].bytes);
+ return true;
+ }
+
+ return false; // unsupported or invalid byte order
+}
+
+bool RegisterContextPOSIX_x86::IsRegisterSetAvailable(size_t set_index) {
+ // Note: Extended register sets are assumed to be at the end of g_reg_sets...
+ size_t num_sets = k_num_register_sets - k_num_extended_register_sets;
+
+ if (GetFPRType() == eXSAVE) // ...and to start with AVX registers.
+ ++num_sets;
+ return (set_index < num_sets);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
new file mode 100644
index 000000000000..9284f5cc07d9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
@@ -0,0 +1,185 @@
+//===-- RegisterContextPOSIX_x86.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_X86_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_X86_H
+
+#include "RegisterContext_x86.h"
+#include "RegisterInfoInterface.h"
+#include "RegisterInfos_x86_64_with_base_shared.h"
+#include "lldb-x86-register-enums.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+
+class RegisterContextPOSIX_x86 : public lldb_private::RegisterContext {
+public:
+ RegisterContextPOSIX_x86(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_x86() override;
+
+ void Invalidate();
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ virtual size_t GetGPRSize();
+
+ virtual size_t GetFXSAVEOffset();
+
+ virtual unsigned GetRegisterSize(unsigned reg);
+
+ virtual unsigned GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+ // Note: prefer kernel definitions over user-land
+ enum FPRType {
+ eNotValid = 0,
+ eFSAVE, // TODO
+ eFXSAVE,
+ eSOFT, // TODO
+ eXSAVE
+ };
+
+ static uint32_t g_contained_eax[];
+ static uint32_t g_contained_ebx[];
+ static uint32_t g_contained_ecx[];
+ static uint32_t g_contained_edx[];
+ static uint32_t g_contained_edi[];
+ static uint32_t g_contained_esi[];
+ static uint32_t g_contained_ebp[];
+ static uint32_t g_contained_esp[];
+
+ static uint32_t g_invalidate_eax[];
+ static uint32_t g_invalidate_ebx[];
+ static uint32_t g_invalidate_ecx[];
+ static uint32_t g_invalidate_edx[];
+ static uint32_t g_invalidate_edi[];
+ static uint32_t g_invalidate_esi[];
+ static uint32_t g_invalidate_ebp[];
+ static uint32_t g_invalidate_esp[];
+
+ static uint32_t g_contained_rax[];
+ static uint32_t g_contained_rbx[];
+ static uint32_t g_contained_rcx[];
+ static uint32_t g_contained_rdx[];
+ static uint32_t g_contained_rdi[];
+ static uint32_t g_contained_rsi[];
+ static uint32_t g_contained_rbp[];
+ static uint32_t g_contained_rsp[];
+ static uint32_t g_contained_r8[];
+ static uint32_t g_contained_r9[];
+ static uint32_t g_contained_r10[];
+ static uint32_t g_contained_r11[];
+ static uint32_t g_contained_r12[];
+ static uint32_t g_contained_r13[];
+ static uint32_t g_contained_r14[];
+ static uint32_t g_contained_r15[];
+
+ static uint32_t g_invalidate_rax[];
+ static uint32_t g_invalidate_rbx[];
+ static uint32_t g_invalidate_rcx[];
+ static uint32_t g_invalidate_rdx[];
+ static uint32_t g_invalidate_rdi[];
+ static uint32_t g_invalidate_rsi[];
+ static uint32_t g_invalidate_rbp[];
+ static uint32_t g_invalidate_rsp[];
+ static uint32_t g_invalidate_r8[];
+ static uint32_t g_invalidate_r9[];
+ static uint32_t g_invalidate_r10[];
+ static uint32_t g_invalidate_r11[];
+ static uint32_t g_invalidate_r12[];
+ static uint32_t g_invalidate_r13[];
+ static uint32_t g_invalidate_r14[];
+ static uint32_t g_invalidate_r15[];
+
+ static uint32_t g_contained_fip[];
+ static uint32_t g_contained_fdp[];
+
+ static uint32_t g_invalidate_fip[];
+ static uint32_t g_invalidate_fdp[];
+
+ static uint32_t g_contained_st0_32[];
+ static uint32_t g_contained_st1_32[];
+ static uint32_t g_contained_st2_32[];
+ static uint32_t g_contained_st3_32[];
+ static uint32_t g_contained_st4_32[];
+ static uint32_t g_contained_st5_32[];
+ static uint32_t g_contained_st6_32[];
+ static uint32_t g_contained_st7_32[];
+
+ static uint32_t g_invalidate_st0_32[];
+ static uint32_t g_invalidate_st1_32[];
+ static uint32_t g_invalidate_st2_32[];
+ static uint32_t g_invalidate_st3_32[];
+ static uint32_t g_invalidate_st4_32[];
+ static uint32_t g_invalidate_st5_32[];
+ static uint32_t g_invalidate_st6_32[];
+ static uint32_t g_invalidate_st7_32[];
+
+ static uint32_t g_contained_st0_64[];
+ static uint32_t g_contained_st1_64[];
+ static uint32_t g_contained_st2_64[];
+ static uint32_t g_contained_st3_64[];
+ static uint32_t g_contained_st4_64[];
+ static uint32_t g_contained_st5_64[];
+ static uint32_t g_contained_st6_64[];
+ static uint32_t g_contained_st7_64[];
+
+ static uint32_t g_invalidate_st0_64[];
+ static uint32_t g_invalidate_st1_64[];
+ static uint32_t g_invalidate_st2_64[];
+ static uint32_t g_invalidate_st3_64[];
+ static uint32_t g_invalidate_st4_64[];
+ static uint32_t g_invalidate_st5_64[];
+ static uint32_t g_invalidate_st6_64[];
+ static uint32_t g_invalidate_st7_64[];
+
+protected:
+ FPRType
+ m_fpr_type; // determines the type of data stored by union FPR, if any.
+ lldb_private::FPR m_fpr; // floating-point registers including extended
+ // register sets.
+ lldb_private::YMM m_ymm_set; // copy of ymmh and xmm register halves.
+ std::unique_ptr<lldb_private::RegisterInfoInterface>
+ m_register_info_up; // Register Info Interface (FreeBSD or Linux)
+
+ // Determines if an extended register set is supported on the processor
+ // running the inferior process.
+ virtual bool IsRegisterSetAvailable(size_t set_index);
+
+ virtual const lldb_private::RegisterInfo *GetRegisterInfo();
+
+ bool IsGPR(unsigned reg);
+
+ bool IsFPR(unsigned reg);
+
+ bool IsAVX(unsigned reg);
+
+ bool CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order);
+ bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
+ bool IsFPR(unsigned reg, FPRType fpr_type);
+ FPRType GetFPRType();
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+ virtual lldb_private::RegInfo &GetRegInfo();
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_X86_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
new file mode 100644
index 000000000000..b5f2b0d2212d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
@@ -0,0 +1,216 @@
+//===-- RegisterContextThreadMemory.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-private.h"
+
+#include "RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextThreadMemory::RegisterContextThreadMemory(
+ Thread &thread, lldb::addr_t register_data_addr)
+ : RegisterContext(thread, 0), m_thread_wp(thread.shared_from_this()),
+ m_reg_ctx_sp(), m_register_data_addr(register_data_addr), m_stop_id(0) {}
+
+RegisterContextThreadMemory::~RegisterContextThreadMemory() = default;
+
+void RegisterContextThreadMemory::UpdateRegisterContext() {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+ ProcessSP process_sp(thread_sp->GetProcess());
+
+ if (process_sp) {
+ const uint32_t stop_id = process_sp->GetModID().GetStopID();
+ if (m_stop_id != stop_id) {
+ m_stop_id = stop_id;
+ m_reg_ctx_sp.reset();
+ }
+ if (!m_reg_ctx_sp) {
+ ThreadSP backing_thread_sp(thread_sp->GetBackingThread());
+ if (backing_thread_sp) {
+ m_reg_ctx_sp = backing_thread_sp->GetRegisterContext();
+ } else {
+ OperatingSystem *os = process_sp->GetOperatingSystem();
+ if (os->IsOperatingSystemPluginThread(thread_sp))
+ m_reg_ctx_sp = os->CreateRegisterContextForThread(
+ thread_sp.get(), m_register_data_addr);
+ }
+ }
+ } else {
+ m_reg_ctx_sp.reset();
+ }
+ } else {
+ m_reg_ctx_sp.reset();
+ }
+}
+
+// Subclasses must override these functions
+void RegisterContextThreadMemory::InvalidateAllRegisters() {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ m_reg_ctx_sp->InvalidateAllRegisters();
+}
+
+size_t RegisterContextThreadMemory::GetRegisterCount() {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterCount();
+ return 0;
+}
+
+const RegisterInfo *
+RegisterContextThreadMemory::GetRegisterInfoAtIndex(size_t reg) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg);
+ return nullptr;
+}
+
+size_t RegisterContextThreadMemory::GetRegisterSetCount() {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSetCount();
+ return 0;
+}
+
+const RegisterSet *RegisterContextThreadMemory::GetRegisterSet(size_t reg_set) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSet(reg_set);
+ return nullptr;
+}
+
+bool RegisterContextThreadMemory::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegister(reg_info, reg_value);
+ return false;
+}
+
+bool RegisterContextThreadMemory::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegister(reg_info, reg_value);
+ return false;
+}
+
+bool RegisterContextThreadMemory::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadAllRegisterValues(data_sp);
+ return false;
+}
+
+bool RegisterContextThreadMemory::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteAllRegisterValues(data_sp);
+ return false;
+}
+
+bool RegisterContextThreadMemory::CopyFromRegisterContext(
+ lldb::RegisterContextSP reg_ctx_sp) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp);
+ return false;
+}
+
+uint32_t RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num);
+ return false;
+}
+
+uint32_t RegisterContextThreadMemory::NumSupportedHardwareBreakpoints() {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareBreakpoints();
+ return false;
+}
+
+uint32_t RegisterContextThreadMemory::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size);
+ return 0;
+}
+
+bool RegisterContextThreadMemory::ClearHardwareBreakpoint(uint32_t hw_idx) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareBreakpoint(hw_idx);
+ return false;
+}
+
+uint32_t RegisterContextThreadMemory::NumSupportedHardwareWatchpoints() {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
+uint32_t RegisterContextThreadMemory::SetHardwareWatchpoint(lldb::addr_t addr,
+ size_t size,
+ bool read,
+ bool write) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write);
+ return 0;
+}
+
+bool RegisterContextThreadMemory::ClearHardwareWatchpoint(uint32_t hw_index) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index);
+ return false;
+}
+
+bool RegisterContextThreadMemory::HardwareSingleStep(bool enable) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->HardwareSingleStep(enable);
+ return false;
+}
+
+Status RegisterContextThreadMemory::ReadRegisterValueFromMemory(
+ const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr,
+ uint32_t src_len, RegisterValue &reg_value) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegisterValueFromMemory(reg_info, src_addr,
+ src_len, reg_value);
+ Status error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
+
+Status RegisterContextThreadMemory::WriteRegisterValueToMemory(
+ const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr,
+ uint32_t dst_len, const RegisterValue &reg_value) {
+ UpdateRegisterContext();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegisterValueToMemory(reg_info, dst_addr, dst_len,
+ reg_value);
+ Status error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
new file mode 100644
index 000000000000..0a7314528f0a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
@@ -0,0 +1,102 @@
+//===-- RegisterContextThreadMemory.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTTHREADMEMORY_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTTHREADMEMORY_H
+
+#include <vector>
+
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class RegisterContextThreadMemory : public lldb_private::RegisterContext {
+public:
+ RegisterContextThreadMemory(Thread &thread, lldb::addr_t register_data_addr);
+
+ ~RegisterContextThreadMemory() override;
+
+ void InvalidateAllRegisters() override;
+
+ 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;
+
+ // These two functions are used to implement "push" and "pop" of register
+ // states. They are used primarily
+ // for expression evaluation, where we need to push a new state (storing the
+ // old one in data_sp) and then
+ // restoring the original state by passing the data_sp we got from
+ // ReadAllRegisters to WriteAllRegisterValues.
+ // ReadAllRegisters will do what is necessary to return a coherent set of
+ // register values for this thread, which
+ // may mean e.g. interrupting a thread that is sitting in a kernel trap. That
+ // is a somewhat disruptive operation,
+ // so these API's should only be used when this behavior is needed.
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ bool CopyFromRegisterContext(lldb::RegisterContextSP context);
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ 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;
+
+ Status ReadRegisterValueFromMemory(const lldb_private::RegisterInfo *reg_info,
+ lldb::addr_t src_addr, uint32_t src_len,
+ RegisterValue &reg_value) override;
+
+ Status WriteRegisterValueToMemory(const lldb_private::RegisterInfo *reg_info,
+ lldb::addr_t dst_addr, uint32_t dst_len,
+ const RegisterValue &reg_value) override;
+
+protected:
+ void UpdateRegisterContext();
+
+ lldb::ThreadWP m_thread_wp;
+ lldb::RegisterContextSP m_reg_ctx_sp;
+ lldb::addr_t m_register_data_addr;
+ uint32_t m_stop_id;
+
+private:
+ RegisterContextThreadMemory(const RegisterContextThreadMemory &) = delete;
+ const RegisterContextThreadMemory &
+ operator=(const RegisterContextThreadMemory &) = delete;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTTHREADMEMORY_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.cpp
new file mode 100644
index 000000000000..faf4021aa499
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.cpp
@@ -0,0 +1,89 @@
+//===-- RegisterContextWindows_i386.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextWindows_i386.h"
+#include "RegisterContext_x86.h"
+#include "lldb-x86-register-enums.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+namespace {
+// Declare our g_register_infos structure.
+typedef struct _GPR {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t eip;
+ uint32_t eflags;
+ uint32_t cs;
+ uint32_t fs;
+ uint32_t gs;
+ uint32_t ss;
+ uint32_t ds;
+ uint32_t es;
+} GPR;
+
+#define GPR_OFFSET(regname) (LLVM_EXTENSION offsetof(GPR, regname))
+
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { \
+#reg, alt, sizeof(((GPR *)nullptr)->reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, \
+ {kind1, kind2, kind3, kind4, lldb_##reg##_i386 }, nullptr, nullptr, \
+ nullptr, \
+ }
+
+// clang-format off
+static RegisterInfo g_register_infos_i386[] = {
+// General purpose registers EH_Frame DWARF Generic Process Plugin
+// =========================== ================== ================ ========================= ====================
+ DEFINE_GPR(eax, nullptr, ehframe_eax_i386, dwarf_eax_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ebx, nullptr, ehframe_ebx_i386, dwarf_ebx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ecx, nullptr, ehframe_ecx_i386, dwarf_ecx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(edx, nullptr, ehframe_edx_i386, dwarf_edx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(edi, nullptr, ehframe_edi_i386, dwarf_edi_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(esi, nullptr, ehframe_esi_i386, dwarf_esi_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ebp, "fp", ehframe_ebp_i386, dwarf_ebp_i386, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(esp, "sp", ehframe_esp_i386, dwarf_esp_i386, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(eip, "pc", ehframe_eip_i386, dwarf_eip_i386, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(eflags, "flags", ehframe_eflags_i386, dwarf_eflags_i386, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(cs, nullptr, LLDB_INVALID_REGNUM, dwarf_cs_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(fs, nullptr, LLDB_INVALID_REGNUM, dwarf_fs_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(gs, nullptr, LLDB_INVALID_REGNUM, dwarf_gs_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ss, nullptr, LLDB_INVALID_REGNUM, dwarf_ss_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ds, nullptr, LLDB_INVALID_REGNUM, dwarf_ds_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(es, nullptr, LLDB_INVALID_REGNUM, dwarf_es_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+};
+// clang-format on
+} // namespace
+
+RegisterContextWindows_i386::RegisterContextWindows_i386(
+ const ArchSpec &target_arch)
+ : lldb_private::RegisterInfoInterface(target_arch) {
+ assert(target_arch.GetMachine() == llvm::Triple::x86);
+}
+
+const RegisterInfo *RegisterContextWindows_i386::GetRegisterInfo() const {
+ return g_register_infos_i386;
+}
+
+uint32_t RegisterContextWindows_i386::GetRegisterCount() const {
+ return std::size(g_register_infos_i386);
+}
+
+uint32_t RegisterContextWindows_i386::GetUserRegisterCount() const {
+ return std::size(g_register_infos_i386);
+}
+
+size_t RegisterContextWindows_i386::GetGPRSize() const { return sizeof(GPR); }
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.h
new file mode 100644
index 000000000000..6a5d3524300d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_i386.h
@@ -0,0 +1,27 @@
+//===-- RegisterContextWindows_i386.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTWINDOWS_I386_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTWINDOWS_I386_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextWindows_i386 : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextWindows_i386(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.cpp
new file mode 100644
index 000000000000..c3fc2e0026bc
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.cpp
@@ -0,0 +1,152 @@
+//===-- RegisterContextWindows_x86_64.cpp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextWindows_x86_64.h"
+#include "RegisterContext_x86.h"
+#include "lldb-x86-register-enums.h"
+
+#include <vector>
+
+using namespace lldb_private;
+using namespace lldb;
+
+namespace {
+typedef struct _GPR {
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rbx;
+ uint64_t rsp;
+ uint64_t rbp;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t rip;
+ uint64_t rflags;
+ uint16_t cs;
+ uint16_t fs;
+ uint16_t gs;
+ uint16_t ss;
+ uint16_t ds;
+ uint16_t es;
+} GPR;
+
+#define GPR_OFFSET(regname) (LLVM_EXTENSION offsetof(GPR, regname))
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { \
+#reg, alt, sizeof(((GPR *)nullptr)->reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, \
+ {kind1, kind2, kind3, kind4, lldb_##reg##_x86_64 }, nullptr, nullptr, \
+ nullptr, \
+ }
+
+typedef struct _FPReg {
+ XMMReg xmm0;
+ XMMReg xmm1;
+ XMMReg xmm2;
+ XMMReg xmm3;
+ XMMReg xmm4;
+ XMMReg xmm5;
+ XMMReg xmm6;
+ XMMReg xmm7;
+ XMMReg xmm8;
+ XMMReg xmm9;
+ XMMReg xmm10;
+ XMMReg xmm11;
+ XMMReg xmm12;
+ XMMReg xmm13;
+ XMMReg xmm14;
+ XMMReg xmm15;
+} FPReg;
+
+#define FPR_OFFSET(regname) \
+ (sizeof(GPR) + LLVM_EXTENSION offsetof(FPReg, regname))
+
+#define DEFINE_XMM(reg) \
+ { \
+#reg, NULL, sizeof(((FPReg *)nullptr)->reg), FPR_OFFSET(reg), \
+ eEncodingUint, eFormatVectorOfUInt64, \
+ {dwarf_##reg##_x86_64, dwarf_##reg##_x86_64, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_##reg##_x86_64 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+// clang-format off
+static RegisterInfo g_register_infos_x86_64[] = {
+// General purpose registers EH_Frame DWARF Generic Process Plugin
+// =========================== ================== ================ ========================= ====================
+ DEFINE_GPR(rax, nullptr, dwarf_rax_x86_64, dwarf_rax_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rbx, nullptr, dwarf_rbx_x86_64, dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rcx, nullptr, dwarf_rcx_x86_64, dwarf_rcx_x86_64, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rdx, nullptr, dwarf_rdx_x86_64, dwarf_rdx_x86_64, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rdi, nullptr, dwarf_rdi_x86_64, dwarf_rdi_x86_64, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rsi, nullptr, dwarf_rsi_x86_64, dwarf_rsi_x86_64, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rbp, nullptr, dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rsp, nullptr, dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r8, nullptr, dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r9, nullptr, dwarf_r9_x86_64, dwarf_r9_x86_64, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r10, nullptr, dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r11, nullptr, dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r12, nullptr, dwarf_r12_x86_64, dwarf_r12_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r13, nullptr, dwarf_r13_x86_64, dwarf_r13_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r14, nullptr, dwarf_r14_x86_64, dwarf_r14_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r15, nullptr, dwarf_r15_x86_64, dwarf_r15_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rip, nullptr, dwarf_rip_x86_64, dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rflags, nullptr, dwarf_rflags_x86_64, dwarf_rflags_x86_64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(cs, nullptr, dwarf_cs_x86_64, dwarf_cs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(fs, nullptr, dwarf_fs_x86_64, dwarf_fs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(gs, nullptr, dwarf_gs_x86_64, dwarf_gs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ss, nullptr, dwarf_ss_x86_64, dwarf_ss_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ds, nullptr, dwarf_ds_x86_64, dwarf_ds_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(es, nullptr, dwarf_es_x86_64, dwarf_es_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_XMM(xmm0),
+ DEFINE_XMM(xmm1),
+ DEFINE_XMM(xmm2),
+ DEFINE_XMM(xmm3),
+ DEFINE_XMM(xmm4),
+ DEFINE_XMM(xmm5),
+ DEFINE_XMM(xmm6),
+ DEFINE_XMM(xmm7),
+ DEFINE_XMM(xmm8),
+ DEFINE_XMM(xmm9),
+ DEFINE_XMM(xmm10),
+ DEFINE_XMM(xmm11),
+ DEFINE_XMM(xmm12),
+ DEFINE_XMM(xmm13),
+ DEFINE_XMM(xmm14),
+ DEFINE_XMM(xmm15)
+};
+// clang-format on
+} // namespace
+
+RegisterContextWindows_x86_64::RegisterContextWindows_x86_64(
+ const ArchSpec &target_arch)
+ : lldb_private::RegisterInfoInterface(target_arch) {
+ assert(target_arch.GetMachine() == llvm::Triple::x86_64);
+}
+
+const RegisterInfo *RegisterContextWindows_x86_64::GetRegisterInfo() const {
+ return g_register_infos_x86_64;
+}
+
+uint32_t RegisterContextWindows_x86_64::GetRegisterCount() const {
+ return std::size(g_register_infos_x86_64);
+}
+
+uint32_t RegisterContextWindows_x86_64::GetUserRegisterCount() const {
+ return std::size(g_register_infos_x86_64);
+}
+
+size_t RegisterContextWindows_x86_64::GetGPRSize() const { return sizeof(GPR); }
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.h
new file mode 100644
index 000000000000..c29acf284841
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextWindows_x86_64.h
@@ -0,0 +1,28 @@
+//===-- RegisterContextWindows_x86_64.h --- ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTWINDOWS_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTWINDOWS_X86_64_H
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextWindows_x86_64
+ : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextWindows_x86_64(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h
new file mode 100644
index 000000000000..15081f974c66
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h
@@ -0,0 +1,374 @@
+//===-- RegisterContext_mips.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_MIPS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_MIPS_H
+
+#include <cstddef>
+#include <cstdint>
+
+// eh_frame and DWARF Register numbers (eRegisterKindEHFrame &
+// eRegisterKindDWARF)
+
+enum {
+ // GP Registers
+ dwarf_zero_mips = 0,
+ dwarf_r1_mips,
+ dwarf_r2_mips,
+ dwarf_r3_mips,
+ dwarf_r4_mips,
+ dwarf_r5_mips,
+ dwarf_r6_mips,
+ dwarf_r7_mips,
+ dwarf_r8_mips,
+ dwarf_r9_mips,
+ dwarf_r10_mips,
+ dwarf_r11_mips,
+ dwarf_r12_mips,
+ dwarf_r13_mips,
+ dwarf_r14_mips,
+ dwarf_r15_mips,
+ dwarf_r16_mips,
+ dwarf_r17_mips,
+ dwarf_r18_mips,
+ dwarf_r19_mips,
+ dwarf_r20_mips,
+ dwarf_r21_mips,
+ dwarf_r22_mips,
+ dwarf_r23_mips,
+ dwarf_r24_mips,
+ dwarf_r25_mips,
+ dwarf_r26_mips,
+ dwarf_r27_mips,
+ dwarf_gp_mips,
+ dwarf_sp_mips,
+ dwarf_r30_mips,
+ dwarf_ra_mips,
+ dwarf_sr_mips,
+ dwarf_lo_mips,
+ dwarf_hi_mips,
+ dwarf_bad_mips,
+ dwarf_cause_mips,
+ dwarf_pc_mips,
+ dwarf_f0_mips,
+ dwarf_f1_mips,
+ dwarf_f2_mips,
+ dwarf_f3_mips,
+ dwarf_f4_mips,
+ dwarf_f5_mips,
+ dwarf_f6_mips,
+ dwarf_f7_mips,
+ dwarf_f8_mips,
+ dwarf_f9_mips,
+ dwarf_f10_mips,
+ dwarf_f11_mips,
+ dwarf_f12_mips,
+ dwarf_f13_mips,
+ dwarf_f14_mips,
+ dwarf_f15_mips,
+ dwarf_f16_mips,
+ dwarf_f17_mips,
+ dwarf_f18_mips,
+ dwarf_f19_mips,
+ dwarf_f20_mips,
+ dwarf_f21_mips,
+ dwarf_f22_mips,
+ dwarf_f23_mips,
+ dwarf_f24_mips,
+ dwarf_f25_mips,
+ dwarf_f26_mips,
+ dwarf_f27_mips,
+ dwarf_f28_mips,
+ dwarf_f29_mips,
+ dwarf_f30_mips,
+ dwarf_f31_mips,
+ dwarf_fcsr_mips,
+ dwarf_fir_mips,
+ dwarf_w0_mips,
+ dwarf_w1_mips,
+ dwarf_w2_mips,
+ dwarf_w3_mips,
+ dwarf_w4_mips,
+ dwarf_w5_mips,
+ dwarf_w6_mips,
+ dwarf_w7_mips,
+ dwarf_w8_mips,
+ dwarf_w9_mips,
+ dwarf_w10_mips,
+ dwarf_w11_mips,
+ dwarf_w12_mips,
+ dwarf_w13_mips,
+ dwarf_w14_mips,
+ dwarf_w15_mips,
+ dwarf_w16_mips,
+ dwarf_w17_mips,
+ dwarf_w18_mips,
+ dwarf_w19_mips,
+ dwarf_w20_mips,
+ dwarf_w21_mips,
+ dwarf_w22_mips,
+ dwarf_w23_mips,
+ dwarf_w24_mips,
+ dwarf_w25_mips,
+ dwarf_w26_mips,
+ dwarf_w27_mips,
+ dwarf_w28_mips,
+ dwarf_w29_mips,
+ dwarf_w30_mips,
+ dwarf_w31_mips,
+ dwarf_mcsr_mips,
+ dwarf_mir_mips,
+ dwarf_config5_mips,
+ dwarf_ic_mips,
+ dwarf_dummy_mips
+};
+
+enum {
+ dwarf_zero_mips64 = 0,
+ dwarf_r1_mips64,
+ dwarf_r2_mips64,
+ dwarf_r3_mips64,
+ dwarf_r4_mips64,
+ dwarf_r5_mips64,
+ dwarf_r6_mips64,
+ dwarf_r7_mips64,
+ dwarf_r8_mips64,
+ dwarf_r9_mips64,
+ dwarf_r10_mips64,
+ dwarf_r11_mips64,
+ dwarf_r12_mips64,
+ dwarf_r13_mips64,
+ dwarf_r14_mips64,
+ dwarf_r15_mips64,
+ dwarf_r16_mips64,
+ dwarf_r17_mips64,
+ dwarf_r18_mips64,
+ dwarf_r19_mips64,
+ dwarf_r20_mips64,
+ dwarf_r21_mips64,
+ dwarf_r22_mips64,
+ dwarf_r23_mips64,
+ dwarf_r24_mips64,
+ dwarf_r25_mips64,
+ dwarf_r26_mips64,
+ dwarf_r27_mips64,
+ dwarf_gp_mips64,
+ dwarf_sp_mips64,
+ dwarf_r30_mips64,
+ dwarf_ra_mips64,
+ dwarf_sr_mips64,
+ dwarf_lo_mips64,
+ dwarf_hi_mips64,
+ dwarf_bad_mips64,
+ dwarf_cause_mips64,
+ dwarf_pc_mips64,
+ dwarf_f0_mips64,
+ dwarf_f1_mips64,
+ dwarf_f2_mips64,
+ dwarf_f3_mips64,
+ dwarf_f4_mips64,
+ dwarf_f5_mips64,
+ dwarf_f6_mips64,
+ dwarf_f7_mips64,
+ dwarf_f8_mips64,
+ dwarf_f9_mips64,
+ dwarf_f10_mips64,
+ dwarf_f11_mips64,
+ dwarf_f12_mips64,
+ dwarf_f13_mips64,
+ dwarf_f14_mips64,
+ dwarf_f15_mips64,
+ dwarf_f16_mips64,
+ dwarf_f17_mips64,
+ dwarf_f18_mips64,
+ dwarf_f19_mips64,
+ dwarf_f20_mips64,
+ dwarf_f21_mips64,
+ dwarf_f22_mips64,
+ dwarf_f23_mips64,
+ dwarf_f24_mips64,
+ dwarf_f25_mips64,
+ dwarf_f26_mips64,
+ dwarf_f27_mips64,
+ dwarf_f28_mips64,
+ dwarf_f29_mips64,
+ dwarf_f30_mips64,
+ dwarf_f31_mips64,
+ dwarf_fcsr_mips64,
+ dwarf_fir_mips64,
+ dwarf_ic_mips64,
+ dwarf_dummy_mips64,
+ dwarf_w0_mips64,
+ dwarf_w1_mips64,
+ dwarf_w2_mips64,
+ dwarf_w3_mips64,
+ dwarf_w4_mips64,
+ dwarf_w5_mips64,
+ dwarf_w6_mips64,
+ dwarf_w7_mips64,
+ dwarf_w8_mips64,
+ dwarf_w9_mips64,
+ dwarf_w10_mips64,
+ dwarf_w11_mips64,
+ dwarf_w12_mips64,
+ dwarf_w13_mips64,
+ dwarf_w14_mips64,
+ dwarf_w15_mips64,
+ dwarf_w16_mips64,
+ dwarf_w17_mips64,
+ dwarf_w18_mips64,
+ dwarf_w19_mips64,
+ dwarf_w20_mips64,
+ dwarf_w21_mips64,
+ dwarf_w22_mips64,
+ dwarf_w23_mips64,
+ dwarf_w24_mips64,
+ dwarf_w25_mips64,
+ dwarf_w26_mips64,
+ dwarf_w27_mips64,
+ dwarf_w28_mips64,
+ dwarf_w29_mips64,
+ dwarf_w30_mips64,
+ dwarf_w31_mips64,
+ dwarf_mcsr_mips64,
+ dwarf_mir_mips64,
+ dwarf_config5_mips64,
+};
+
+// GP registers
+struct GPR_linux_mips {
+ uint64_t zero;
+ uint64_t r1;
+ uint64_t r2;
+ uint64_t r3;
+ uint64_t r4;
+ uint64_t r5;
+ uint64_t r6;
+ uint64_t r7;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t r16;
+ uint64_t r17;
+ uint64_t r18;
+ uint64_t r19;
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+ uint64_t gp;
+ uint64_t sp;
+ uint64_t r30;
+ uint64_t ra;
+ uint64_t mullo;
+ uint64_t mulhi;
+ uint64_t pc;
+ uint64_t badvaddr;
+ uint64_t sr;
+ uint64_t cause;
+ uint64_t config5;
+};
+
+struct FPR_linux_mips {
+ uint64_t f0;
+ uint64_t f1;
+ uint64_t f2;
+ uint64_t f3;
+ uint64_t f4;
+ uint64_t f5;
+ uint64_t f6;
+ uint64_t f7;
+ uint64_t f8;
+ uint64_t f9;
+ uint64_t f10;
+ uint64_t f11;
+ uint64_t f12;
+ uint64_t f13;
+ uint64_t f14;
+ uint64_t f15;
+ uint64_t f16;
+ uint64_t f17;
+ uint64_t f18;
+ uint64_t f19;
+ uint64_t f20;
+ uint64_t f21;
+ uint64_t f22;
+ uint64_t f23;
+ uint64_t f24;
+ uint64_t f25;
+ uint64_t f26;
+ uint64_t f27;
+ uint64_t f28;
+ uint64_t f29;
+ uint64_t f30;
+ uint64_t f31;
+ uint32_t fcsr;
+ uint32_t fir;
+ uint32_t config5;
+};
+
+struct MSAReg {
+ uint8_t byte[16];
+};
+
+struct MSA_linux_mips {
+ MSAReg w0;
+ MSAReg w1;
+ MSAReg w2;
+ MSAReg w3;
+ MSAReg w4;
+ MSAReg w5;
+ MSAReg w6;
+ MSAReg w7;
+ MSAReg w8;
+ MSAReg w9;
+ MSAReg w10;
+ MSAReg w11;
+ MSAReg w12;
+ MSAReg w13;
+ MSAReg w14;
+ MSAReg w15;
+ MSAReg w16;
+ MSAReg w17;
+ MSAReg w18;
+ MSAReg w19;
+ MSAReg w20;
+ MSAReg w21;
+ MSAReg w22;
+ MSAReg w23;
+ MSAReg w24;
+ MSAReg w25;
+ MSAReg w26;
+ MSAReg w27;
+ MSAReg w28;
+ MSAReg w29;
+ MSAReg w30;
+ MSAReg w31;
+ uint32_t fcsr; /* FPU control status register */
+ uint32_t fir; /* FPU implementaion revision */
+ uint32_t mcsr; /* MSA control status register */
+ uint32_t mir; /* MSA implementation revision */
+ uint32_t config5; /* Config5 register */
+};
+
+struct UserArea {
+ GPR_linux_mips gpr; // General purpose registers.
+ FPR_linux_mips fpr; // Floating point registers.
+ MSA_linux_mips msa; // MSA registers.
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_MIPS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h
new file mode 100644
index 000000000000..7407e2f402e0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h
@@ -0,0 +1,123 @@
+//===-- RegisterContext_powerpc.h --------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_POWERPC_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_POWERPC_H
+
+// eh_frame and DWARF Register numbers (eRegisterKindEHFrame &
+// eRegisterKindDWARF)
+enum {
+ dwarf_r0_powerpc = 0,
+ dwarf_r1_powerpc,
+ dwarf_r2_powerpc,
+ dwarf_r3_powerpc,
+ dwarf_r4_powerpc,
+ dwarf_r5_powerpc,
+ dwarf_r6_powerpc,
+ dwarf_r7_powerpc,
+ dwarf_r8_powerpc,
+ dwarf_r9_powerpc,
+ dwarf_r10_powerpc,
+ dwarf_r11_powerpc,
+ dwarf_r12_powerpc,
+ dwarf_r13_powerpc,
+ dwarf_r14_powerpc,
+ dwarf_r15_powerpc,
+ dwarf_r16_powerpc,
+ dwarf_r17_powerpc,
+ dwarf_r18_powerpc,
+ dwarf_r19_powerpc,
+ dwarf_r20_powerpc,
+ dwarf_r21_powerpc,
+ dwarf_r22_powerpc,
+ dwarf_r23_powerpc,
+ dwarf_r24_powerpc,
+ dwarf_r25_powerpc,
+ dwarf_r26_powerpc,
+ dwarf_r27_powerpc,
+ dwarf_r28_powerpc,
+ dwarf_r29_powerpc,
+ dwarf_r30_powerpc,
+ dwarf_r31_powerpc,
+ dwarf_f0_powerpc,
+ dwarf_f1_powerpc,
+ dwarf_f2_powerpc,
+ dwarf_f3_powerpc,
+ dwarf_f4_powerpc,
+ dwarf_f5_powerpc,
+ dwarf_f6_powerpc,
+ dwarf_f7_powerpc,
+ dwarf_f8_powerpc,
+ dwarf_f9_powerpc,
+ dwarf_f10_powerpc,
+ dwarf_f11_powerpc,
+ dwarf_f12_powerpc,
+ dwarf_f13_powerpc,
+ dwarf_f14_powerpc,
+ dwarf_f15_powerpc,
+ dwarf_f16_powerpc,
+ dwarf_f17_powerpc,
+ dwarf_f18_powerpc,
+ dwarf_f19_powerpc,
+ dwarf_f20_powerpc,
+ dwarf_f21_powerpc,
+ dwarf_f22_powerpc,
+ dwarf_f23_powerpc,
+ dwarf_f24_powerpc,
+ dwarf_f25_powerpc,
+ dwarf_f26_powerpc,
+ dwarf_f27_powerpc,
+ dwarf_f28_powerpc,
+ dwarf_f29_powerpc,
+ dwarf_f30_powerpc,
+ dwarf_f31_powerpc,
+ dwarf_cr_powerpc,
+ dwarf_fpscr_powerpc,
+ dwarf_msr_powerpc,
+ dwarf_vscr_powerpc,
+ dwarf_xer_powerpc = 101,
+ dwarf_lr_powerpc = 108,
+ dwarf_ctr_powerpc,
+ dwarf_pc_powerpc,
+ dwarf_vrsave_powerpc = 356,
+ dwarf_v0_powerpc = 1124,
+ dwarf_v1_powerpc,
+ dwarf_v2_powerpc,
+ dwarf_v3_powerpc,
+ dwarf_v4_powerpc,
+ dwarf_v5_powerpc,
+ dwarf_v6_powerpc,
+ dwarf_v7_powerpc,
+ dwarf_v8_powerpc,
+ dwarf_v9_powerpc,
+ dwarf_v10_powerpc,
+ dwarf_v11_powerpc,
+ dwarf_v12_powerpc,
+ dwarf_v13_powerpc,
+ dwarf_v14_powerpc,
+ dwarf_v15_powerpc,
+ dwarf_v16_powerpc,
+ dwarf_v17_powerpc,
+ dwarf_v18_powerpc,
+ dwarf_v19_powerpc,
+ dwarf_v20_powerpc,
+ dwarf_v21_powerpc,
+ dwarf_v22_powerpc,
+ dwarf_v23_powerpc,
+ dwarf_v24_powerpc,
+ dwarf_v25_powerpc,
+ dwarf_v26_powerpc,
+ dwarf_v27_powerpc,
+ dwarf_v28_powerpc,
+ dwarf_v29_powerpc,
+ dwarf_v30_powerpc,
+ dwarf_v31_powerpc,
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_POWERPC_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_s390x.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_s390x.h
new file mode 100644
index 000000000000..248b3bd0beac
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_s390x.h
@@ -0,0 +1,90 @@
+//===-- RegisterContext_s390x.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_S390X_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_S390X_H
+
+// SystemZ ehframe, dwarf regnums
+
+// EHFrame and DWARF Register numbers (eRegisterKindEHFrame &
+// eRegisterKindDWARF)
+enum {
+ // General Purpose Registers
+ dwarf_r0_s390x = 0,
+ dwarf_r1_s390x,
+ dwarf_r2_s390x,
+ dwarf_r3_s390x,
+ dwarf_r4_s390x,
+ dwarf_r5_s390x,
+ dwarf_r6_s390x,
+ dwarf_r7_s390x,
+ dwarf_r8_s390x,
+ dwarf_r9_s390x,
+ dwarf_r10_s390x,
+ dwarf_r11_s390x,
+ dwarf_r12_s390x,
+ dwarf_r13_s390x,
+ dwarf_r14_s390x,
+ dwarf_r15_s390x,
+ // Floating Point Registers / Vector Registers 0-15
+ dwarf_f0_s390x = 16,
+ dwarf_f2_s390x,
+ dwarf_f4_s390x,
+ dwarf_f6_s390x,
+ dwarf_f1_s390x,
+ dwarf_f3_s390x,
+ dwarf_f5_s390x,
+ dwarf_f7_s390x,
+ dwarf_f8_s390x,
+ dwarf_f10_s390x,
+ dwarf_f12_s390x,
+ dwarf_f14_s390x,
+ dwarf_f9_s390x,
+ dwarf_f11_s390x,
+ dwarf_f13_s390x,
+ dwarf_f15_s390x,
+ // Access Registers
+ dwarf_acr0_s390x = 48,
+ dwarf_acr1_s390x,
+ dwarf_acr2_s390x,
+ dwarf_acr3_s390x,
+ dwarf_acr4_s390x,
+ dwarf_acr5_s390x,
+ dwarf_acr6_s390x,
+ dwarf_acr7_s390x,
+ dwarf_acr8_s390x,
+ dwarf_acr9_s390x,
+ dwarf_acr10_s390x,
+ dwarf_acr11_s390x,
+ dwarf_acr12_s390x,
+ dwarf_acr13_s390x,
+ dwarf_acr14_s390x,
+ dwarf_acr15_s390x,
+ // Program Status Word
+ dwarf_pswm_s390x = 64,
+ dwarf_pswa_s390x,
+ // Vector Registers 16-31
+ dwarf_v16_s390x = 68,
+ dwarf_v18_s390x,
+ dwarf_v20_s390x,
+ dwarf_v22_s390x,
+ dwarf_v17_s390x,
+ dwarf_v19_s390x,
+ dwarf_v21_s390x,
+ dwarf_v23_s390x,
+ dwarf_v24_s390x,
+ dwarf_v26_s390x,
+ dwarf_v28_s390x,
+ dwarf_v30_s390x,
+ dwarf_v25_s390x,
+ dwarf_v27_s390x,
+ dwarf_v29_s390x,
+ dwarf_v31_s390x,
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp
new file mode 100644
index 000000000000..b21c72bd9621
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp
@@ -0,0 +1,58 @@
+//===-- RegisterContext_x86.cpp ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContext_x86.h"
+
+using namespace lldb_private;
+
+// Convert the 8-bit abridged FPU Tag Word (as found in FXSAVE) to the full
+// 16-bit FPU Tag Word (as found in FSAVE, and used by gdb protocol). This
+// requires knowing the values of the ST(i) registers and the FPU Status Word.
+uint16_t lldb_private::AbridgedToFullTagWord(uint8_t abridged_tw, uint16_t sw,
+ llvm::ArrayRef<MMSReg> st_regs) {
+ // Tag word is using internal FPU register numbering rather than ST(i).
+ // Mapping to ST(i): i = FPU regno - TOP (Status Word, bits 11:13).
+ // Here we start with FPU reg 7 and go down.
+ int st = 7 - ((sw >> 11) & 7);
+ uint16_t tw = 0;
+ for (uint8_t mask = 0x80; mask != 0; mask >>= 1) {
+ tw <<= 2;
+ if (abridged_tw & mask) {
+ // The register is non-empty, so we need to check the value of ST(i).
+ uint16_t exp =
+ st_regs[st].comp.sign_exp & 0x7fff; // Discard the sign bit.
+ if (exp == 0) {
+ if (st_regs[st].comp.mantissa == 0)
+ tw |= 1; // Zero
+ else
+ tw |= 2; // Denormal
+ } else if (exp == 0x7fff)
+ tw |= 2; // Infinity or NaN
+ // 0 if normal number
+ } else
+ tw |= 3; // Empty register
+
+ // Rotate ST down.
+ st = (st - 1) & 7;
+ }
+
+ return tw;
+}
+
+// Convert the 16-bit FPU Tag Word to the abridged 8-bit value, to be written
+// into FXSAVE.
+uint8_t lldb_private::FullToAbridgedTagWord(uint16_t tw) {
+ uint8_t abridged_tw = 0;
+ for (uint16_t mask = 0xc000; mask != 0; mask >>= 2) {
+ abridged_tw <<= 1;
+ // full TW uses 11 for empty registers, aTW uses 0
+ if ((tw & mask) != mask)
+ abridged_tw |= 1;
+ }
+ return abridged_tw;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h
new file mode 100644
index 000000000000..e24da37b7261
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h
@@ -0,0 +1,395 @@
+//===-- RegisterContext_x86.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_X86_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXT_X86_H
+
+#include <cstddef>
+#include <cstdint>
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/Support/Compiler.h"
+
+namespace lldb_private {
+// i386 ehframe, dwarf regnums
+
+// Register numbers seen in eh_frame (eRegisterKindEHFrame) on i386 systems
+// (non-Darwin)
+//
+enum {
+ ehframe_eax_i386 = 0,
+ ehframe_ecx_i386,
+ ehframe_edx_i386,
+ ehframe_ebx_i386,
+
+ // on Darwin esp & ebp are reversed in the eh_frame section for i386 (versus
+ // dwarf's reg numbering).
+ // To be specific:
+ // i386+darwin eh_frame: 4 is ebp, 5 is esp
+ // i386+everyone else eh_frame: 4 is esp, 5 is ebp
+ // i386 dwarf: 4 is esp, 5 is ebp
+ // lldb will get the darwin-specific eh_frame reg numberings from debugserver,
+ // or the ABI, so we
+ // only encode the generally correct 4 == esp, 5 == ebp numbers in this
+ // generic header.
+
+ ehframe_esp_i386,
+ ehframe_ebp_i386,
+ ehframe_esi_i386,
+ ehframe_edi_i386,
+ ehframe_eip_i386,
+ ehframe_eflags_i386,
+ ehframe_st0_i386 = 12,
+ ehframe_st1_i386,
+ ehframe_st2_i386,
+ ehframe_st3_i386,
+ ehframe_st4_i386,
+ ehframe_st5_i386,
+ ehframe_st6_i386,
+ ehframe_st7_i386,
+ ehframe_xmm0_i386 = 21,
+ ehframe_xmm1_i386,
+ ehframe_xmm2_i386,
+ ehframe_xmm3_i386,
+ ehframe_xmm4_i386,
+ ehframe_xmm5_i386,
+ ehframe_xmm6_i386,
+ ehframe_xmm7_i386,
+ ehframe_mm0_i386 = 29,
+ ehframe_mm1_i386,
+ ehframe_mm2_i386,
+ ehframe_mm3_i386,
+ ehframe_mm4_i386,
+ ehframe_mm5_i386,
+ ehframe_mm6_i386,
+ ehframe_mm7_i386,
+};
+
+// DWARF register numbers (eRegisterKindDWARF)
+// Intel's x86 or IA-32
+enum {
+ // General Purpose Registers.
+ dwarf_eax_i386 = 0,
+ dwarf_ecx_i386,
+ dwarf_edx_i386,
+ dwarf_ebx_i386,
+ dwarf_esp_i386,
+ dwarf_ebp_i386,
+ dwarf_esi_i386,
+ dwarf_edi_i386,
+ dwarf_eip_i386,
+ dwarf_eflags_i386,
+ // Floating Point Registers
+ dwarf_st0_i386 = 11,
+ dwarf_st1_i386,
+ dwarf_st2_i386,
+ dwarf_st3_i386,
+ dwarf_st4_i386,
+ dwarf_st5_i386,
+ dwarf_st6_i386,
+ dwarf_st7_i386,
+ // SSE Registers
+ dwarf_xmm0_i386 = 21,
+ dwarf_xmm1_i386,
+ dwarf_xmm2_i386,
+ dwarf_xmm3_i386,
+ dwarf_xmm4_i386,
+ dwarf_xmm5_i386,
+ dwarf_xmm6_i386,
+ dwarf_xmm7_i386,
+ // MMX Registers
+ dwarf_mm0_i386 = 29,
+ dwarf_mm1_i386,
+ dwarf_mm2_i386,
+ dwarf_mm3_i386,
+ dwarf_mm4_i386,
+ dwarf_mm5_i386,
+ dwarf_mm6_i386,
+ dwarf_mm7_i386,
+ dwarf_fctrl_i386 = 37, // x87 control word
+ dwarf_fstat_i386 = 38, // x87 status word
+ dwarf_mxcsr_i386 = 39,
+ dwarf_es_i386 = 40,
+ dwarf_cs_i386 = 41,
+ dwarf_ss_i386 = 42,
+ dwarf_ds_i386 = 43,
+ dwarf_fs_i386 = 44,
+ dwarf_gs_i386 = 45,
+
+ // I believe the ymm registers use the dwarf_xmm%_i386 register numbers and
+ // then differentiate based on size of the register.
+ dwarf_bnd0_i386 = 101,
+ dwarf_bnd1_i386,
+ dwarf_bnd2_i386,
+ dwarf_bnd3_i386,
+};
+
+// AMD x86_64, AMD64, Intel EM64T, or Intel 64 ehframe, dwarf regnums
+
+// EHFrame and DWARF Register numbers (eRegisterKindEHFrame &
+// eRegisterKindDWARF)
+// This is the spec I used (as opposed to x86-64-abi-0.99.pdf):
+// http://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf
+enum {
+ // GP Registers
+ dwarf_rax_x86_64 = 0,
+ dwarf_rdx_x86_64,
+ dwarf_rcx_x86_64,
+ dwarf_rbx_x86_64,
+ dwarf_rsi_x86_64,
+ dwarf_rdi_x86_64,
+ dwarf_rbp_x86_64,
+ dwarf_rsp_x86_64,
+ // Extended GP Registers
+ dwarf_r8_x86_64 = 8,
+ dwarf_r9_x86_64,
+ dwarf_r10_x86_64,
+ dwarf_r11_x86_64,
+ dwarf_r12_x86_64,
+ dwarf_r13_x86_64,
+ dwarf_r14_x86_64,
+ dwarf_r15_x86_64,
+ // Return Address (RA) mapped to RIP
+ dwarf_rip_x86_64 = 16,
+ // SSE Vector Registers
+ dwarf_xmm0_x86_64 = 17,
+ dwarf_xmm1_x86_64,
+ dwarf_xmm2_x86_64,
+ dwarf_xmm3_x86_64,
+ dwarf_xmm4_x86_64,
+ dwarf_xmm5_x86_64,
+ dwarf_xmm6_x86_64,
+ dwarf_xmm7_x86_64,
+ dwarf_xmm8_x86_64,
+ dwarf_xmm9_x86_64,
+ dwarf_xmm10_x86_64,
+ dwarf_xmm11_x86_64,
+ dwarf_xmm12_x86_64,
+ dwarf_xmm13_x86_64,
+ dwarf_xmm14_x86_64,
+ dwarf_xmm15_x86_64,
+ // Floating Point Registers
+ dwarf_st0_x86_64 = 33,
+ dwarf_st1_x86_64,
+ dwarf_st2_x86_64,
+ dwarf_st3_x86_64,
+ dwarf_st4_x86_64,
+ dwarf_st5_x86_64,
+ dwarf_st6_x86_64,
+ dwarf_st7_x86_64,
+ // MMX Registers
+ dwarf_mm0_x86_64 = 41,
+ dwarf_mm1_x86_64,
+ dwarf_mm2_x86_64,
+ dwarf_mm3_x86_64,
+ dwarf_mm4_x86_64,
+ dwarf_mm5_x86_64,
+ dwarf_mm6_x86_64,
+ dwarf_mm7_x86_64,
+ // Control and Status Flags Register
+ dwarf_rflags_x86_64 = 49,
+ // selector registers
+ dwarf_es_x86_64 = 50,
+ dwarf_cs_x86_64,
+ dwarf_ss_x86_64,
+ dwarf_ds_x86_64,
+ dwarf_fs_x86_64,
+ dwarf_gs_x86_64,
+ // Base registers
+ dwarf_fs_base_x86_64 = 58,
+ dwarf_gs_base_x86_64 = 59,
+ // Floating point control registers
+ dwarf_mxcsr_x86_64 = 64, // Media Control and Status
+ dwarf_fctrl_x86_64, // x87 control word
+ dwarf_fstat_x86_64, // x87 status word
+ // Upper Vector Registers
+ dwarf_ymm0h_x86_64 = 67,
+ dwarf_ymm1h_x86_64,
+ dwarf_ymm2h_x86_64,
+ dwarf_ymm3h_x86_64,
+ dwarf_ymm4h_x86_64,
+ dwarf_ymm5h_x86_64,
+ dwarf_ymm6h_x86_64,
+ dwarf_ymm7h_x86_64,
+ dwarf_ymm8h_x86_64,
+ dwarf_ymm9h_x86_64,
+ dwarf_ymm10h_x86_64,
+ dwarf_ymm11h_x86_64,
+ dwarf_ymm12h_x86_64,
+ dwarf_ymm13h_x86_64,
+ dwarf_ymm14h_x86_64,
+ dwarf_ymm15h_x86_64,
+ // MPX registers
+ dwarf_bnd0_x86_64 = 126,
+ dwarf_bnd1_x86_64,
+ dwarf_bnd2_x86_64,
+ dwarf_bnd3_x86_64,
+ // AVX2 Vector Mask Registers
+ // dwarf_k0_x86_64 = 118,
+ // dwarf_k1_x86_64,
+ // dwarf_k2_x86_64,
+ // dwarf_k3_x86_64,
+ // dwarf_k4_x86_64,
+ // dwarf_k5_x86_64,
+ // dwarf_k6_x86_64,
+ // dwarf_k7_x86_64,
+};
+
+// Generic floating-point registers
+
+LLVM_PACKED_START
+struct MMSRegComp {
+ uint64_t mantissa;
+ uint16_t sign_exp;
+};
+
+struct MMSReg {
+ union {
+ uint8_t bytes[10];
+ MMSRegComp comp;
+ };
+ uint8_t pad[6];
+};
+LLVM_PACKED_END
+
+static_assert(sizeof(MMSRegComp) == 10, "MMSRegComp is not 10 bytes of size");
+static_assert(sizeof(MMSReg) == 16, "MMSReg is not 16 bytes of size");
+
+struct XMMReg {
+ uint8_t bytes[16]; // 128-bits for each XMM register
+};
+
+// i387_fxsave_struct
+struct FXSAVE {
+ uint16_t fctrl; // FPU Control Word (fcw)
+ uint16_t fstat; // FPU Status Word (fsw)
+ uint16_t ftag; // FPU Tag Word (ftw)
+ uint16_t fop; // Last Instruction Opcode (fop)
+ union {
+ struct {
+ uint64_t fip; // Instruction Pointer
+ uint64_t fdp; // Data Pointer
+ } x86_64;
+ struct {
+ uint32_t fioff; // FPU IP Offset (fip)
+ uint32_t fiseg; // FPU IP Selector (fcs)
+ uint32_t fooff; // FPU Operand Pointer Offset (foo)
+ uint32_t foseg; // FPU Operand Pointer Selector (fos)
+ } i386_; // Added _ in the end to avoid error with gcc defining i386 in some
+ // cases
+ } ptr;
+ uint32_t mxcsr; // MXCSR Register State
+ uint32_t mxcsrmask; // MXCSR Mask
+ MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes
+ XMMReg xmm[16]; // 16*16 bytes for each XMM-reg = 256 bytes
+ uint8_t padding1[48];
+ uint64_t xcr0;
+ uint8_t padding2[40];
+};
+
+// Extended floating-point registers
+
+struct YMMHReg {
+ uint8_t bytes[16]; // 16 * 8 bits for the high bytes of each YMM register
+};
+
+struct YMMReg {
+ uint8_t bytes[32]; // 16 * 16 bits for each YMM register
+};
+
+struct YMM {
+ YMMReg ymm[16]; // assembled from ymmh and xmm registers
+};
+
+struct MPXReg {
+ uint8_t bytes[16]; // MPX 128 bit bound registers
+};
+
+struct MPXCsr {
+ uint8_t bytes[8]; // MPX 64 bit bndcfgu and bndstatus registers (collectively
+ // BNDCSR state)
+};
+
+struct MPX {
+ MPXReg mpxr[4];
+ MPXCsr mpxc[2];
+};
+
+LLVM_PACKED_START
+struct XSAVE_HDR {
+ enum class XFeature : uint64_t {
+ FP = 1,
+ SSE = FP << 1,
+ YMM = SSE << 1,
+ BNDREGS = YMM << 1,
+ BNDCSR = BNDREGS << 1,
+ OPMASK = BNDCSR << 1,
+ ZMM_Hi256 = OPMASK << 1,
+ Hi16_ZMM = ZMM_Hi256 << 1,
+ PT = Hi16_ZMM << 1,
+ PKRU = PT << 1,
+ LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ PKRU)
+ };
+
+ XFeature xstate_bv; // OS enabled xstate mask to determine the extended states
+ // supported by the processor
+ XFeature xcomp_bv; // Mask to indicate the format of the XSAVE area and of
+ // the XRSTOR instruction
+ uint64_t reserved1[1];
+ uint64_t reserved2[5];
+};
+static_assert(sizeof(XSAVE_HDR) == 64, "XSAVE_HDR layout incorrect");
+LLVM_PACKED_END
+
+// x86 extensions to FXSAVE (i.e. for AVX and MPX processors)
+LLVM_PACKED_START
+struct XSAVE {
+ FXSAVE i387; // floating point registers typical in i387_fxsave_struct
+ XSAVE_HDR header; // The xsave_hdr_struct can be used to determine if the
+ // following extensions are usable
+ YMMHReg ymmh[16]; // High 16 bytes of each of 16 YMM registers (the low bytes
+ // are in FXSAVE.xmm for compatibility with SSE)
+ uint64_t reserved3[16];
+ MPXReg mpxr[4]; // MPX BNDREG state, containing 128-bit bound registers
+ MPXCsr mpxc[2]; // MPX BNDCSR state, containing 64-bit BNDCFGU and
+ // BNDSTATUS registers
+};
+LLVM_PACKED_END
+
+// Floating-point registers
+union FPR {
+ FXSAVE fxsave; // Generic floating-point registers.
+ XSAVE xsave; // x86 extended processor state.
+};
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+// Convenience function to combine YMM register data from XSAVE-style input.
+inline YMMReg XStateToYMM(const void* xmm_bytes, const void* ymmh_bytes) {
+ YMMReg ret;
+
+ ::memcpy(ret.bytes, xmm_bytes, sizeof(XMMReg));
+ ::memcpy(ret.bytes + sizeof(XMMReg), ymmh_bytes, sizeof(YMMHReg));
+
+ return ret;
+}
+
+// Convenience function to copy YMM register data into XSAVE-style output.
+inline void YMMToXState(const YMMReg& input, void* xmm_bytes, void* ymmh_bytes) {
+ ::memcpy(xmm_bytes, input.bytes, sizeof(XMMReg));
+ ::memcpy(ymmh_bytes, input.bytes + sizeof(XMMReg), sizeof(YMMHReg));
+}
+
+uint16_t AbridgedToFullTagWord(uint8_t abridged_tw, uint16_t sw,
+ llvm::ArrayRef<MMSReg> st_regs);
+uint8_t FullToAbridgedTagWord(uint16_t tw);
+
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
new file mode 100644
index 000000000000..7c8dba368093
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
@@ -0,0 +1,217 @@
+//===-- RegisterFlagsDetector_arm64.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterFlagsDetector_arm64.h"
+#include "lldb/lldb-private-types.h"
+
+// This file is built on all systems because it is used by native processes and
+// core files, so we manually define the needed HWCAP values here.
+// These values are the same for Linux and FreeBSD.
+
+#define HWCAP_FPHP (1ULL << 9)
+#define HWCAP_ASIMDHP (1ULL << 10)
+#define HWCAP_DIT (1ULL << 24)
+#define HWCAP_SSBS (1ULL << 28)
+
+#define HWCAP2_BTI (1ULL << 17)
+#define HWCAP2_MTE (1ULL << 18)
+#define HWCAP2_AFP (1ULL << 20)
+#define HWCAP2_SME (1ULL << 23)
+#define HWCAP2_EBF16 (1ULL << 32)
+
+using namespace lldb_private;
+
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) {
+ (void)hwcap;
+
+ if (!(hwcap2 & HWCAP2_SME))
+ return {};
+
+ // Represents the pseudo register that lldb-server builds, which itself
+ // matches the architectural register SCVR. The fields match SVCR in the Arm
+ // manual.
+ return {
+ {"ZA", 1},
+ {"SM", 0},
+ };
+}
+
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectMTECtrlFields(uint64_t hwcap,
+ uint64_t hwcap2) {
+ (void)hwcap;
+
+ if (!(hwcap2 & HWCAP2_MTE))
+ return {};
+
+ // Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed
+ // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines
+ // used to build the value.
+
+ static const FieldEnum tcf_enum(
+ "tcf_enum",
+ {{0, "TCF_NONE"}, {1, "TCF_SYNC"}, {2, "TCF_ASYNC"}, {3, "TCF_ASYMM"}});
+ return {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT.
+ {"TCF", 1, 2, &tcf_enum},
+ {"TAGGED_ADDR_ENABLE", 0}};
+}
+
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) {
+ static const FieldEnum rmode_enum(
+ "rmode_enum", {{0, "RN"}, {1, "RP"}, {2, "RM"}, {3, "RZ"}});
+
+ std::vector<RegisterFlags::Field> fpcr_fields{
+ {"AHP", 26}, {"DN", 25}, {"FZ", 24}, {"RMode", 22, 23, &rmode_enum},
+ // Bits 21-20 are "Stride" which is unused in AArch64 state.
+ };
+
+ // FEAT_FP16 is indicated by the presence of FPHP (floating point half
+ // precision) and ASIMDHP (Advanced SIMD half precision) features.
+ if ((hwcap & HWCAP_FPHP) && (hwcap & HWCAP_ASIMDHP))
+ fpcr_fields.push_back({"FZ16", 19});
+
+ // Bits 18-16 are "Len" which is unused in AArch64 state.
+
+ fpcr_fields.push_back({"IDE", 15});
+
+ // Bit 14 is unused.
+ if (hwcap2 & HWCAP2_EBF16)
+ fpcr_fields.push_back({"EBF", 13});
+
+ fpcr_fields.push_back({"IXE", 12});
+ fpcr_fields.push_back({"UFE", 11});
+ fpcr_fields.push_back({"OFE", 10});
+ fpcr_fields.push_back({"DZE", 9});
+ fpcr_fields.push_back({"IOE", 8});
+ // Bits 7-3 reserved.
+
+ if (hwcap2 & HWCAP2_AFP) {
+ fpcr_fields.push_back({"NEP", 2});
+ fpcr_fields.push_back({"AH", 1});
+ fpcr_fields.push_back({"FIZ", 0});
+ }
+
+ return fpcr_fields;
+}
+
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) {
+ // fpsr's contents are constant.
+ (void)hwcap;
+ (void)hwcap2;
+
+ return {
+ // Bits 31-28 are N/Z/C/V, only used by AArch32.
+ {"QC", 27},
+ // Bits 26-8 reserved.
+ {"IDC", 7},
+ // Bits 6-5 reserved.
+ {"IXC", 4},
+ {"UFC", 3},
+ {"OFC", 2},
+ {"DZC", 1},
+ {"IOC", 0},
+ };
+}
+
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) {
+ // The fields here are a combination of the Arm manual's SPSR_EL1,
+ // plus a few changes where Linux has decided not to make use of them at all,
+ // or at least not from userspace.
+
+ // Status bits that are always present.
+ std::vector<RegisterFlags::Field> cpsr_fields{
+ {"N", 31}, {"Z", 30}, {"C", 29}, {"V", 28},
+ // Bits 27-26 reserved.
+ };
+
+ if (hwcap2 & HWCAP2_MTE)
+ cpsr_fields.push_back({"TCO", 25});
+ if (hwcap & HWCAP_DIT)
+ cpsr_fields.push_back({"DIT", 24});
+
+ // UAO and PAN are bits 23 and 22 and have no meaning for userspace so
+ // are treated as reserved by the kernels.
+
+ cpsr_fields.push_back({"SS", 21});
+ cpsr_fields.push_back({"IL", 20});
+ // Bits 19-14 reserved.
+
+ // Bit 13, ALLINT, requires FEAT_NMI that isn't relevant to userspace, and we
+ // can't detect either, don't show this field.
+ if (hwcap & HWCAP_SSBS)
+ cpsr_fields.push_back({"SSBS", 12});
+ if (hwcap2 & HWCAP2_BTI)
+ cpsr_fields.push_back({"BTYPE", 10, 11});
+
+ cpsr_fields.push_back({"D", 9});
+ cpsr_fields.push_back({"A", 8});
+ cpsr_fields.push_back({"I", 7});
+ cpsr_fields.push_back({"F", 6});
+ // Bit 5 reserved
+ // Called "M" in the ARMARM.
+ cpsr_fields.push_back({"nRW", 4});
+ // This is a 4 bit field M[3:0] in the ARMARM, we split it into parts.
+ cpsr_fields.push_back({"EL", 2, 3});
+ // Bit 1 is unused and expected to be 0.
+ cpsr_fields.push_back({"SP", 0});
+
+ return cpsr_fields;
+}
+
+void Arm64RegisterFlagsDetector::DetectFields(uint64_t hwcap, uint64_t hwcap2) {
+ for (auto &reg : m_registers)
+ reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2));
+ m_has_detected = true;
+}
+
+void Arm64RegisterFlagsDetector::UpdateRegisterInfo(
+ const RegisterInfo *reg_info, uint32_t num_regs) {
+ assert(m_has_detected &&
+ "Must call DetectFields before updating register info.");
+
+ // Register names will not be duplicated, so we do not want to compare against
+ // one if it has already been found. Each time we find one, we erase it from
+ // this list.
+ std::vector<std::pair<llvm::StringRef, const RegisterFlags *>>
+ search_registers;
+ for (const auto &reg : m_registers) {
+ // It is possible that a register is all extension dependent fields, and
+ // none of them are present.
+ if (reg.m_flags.GetFields().size())
+ search_registers.push_back({reg.m_name, &reg.m_flags});
+ }
+
+ // Walk register information while there are registers we know need
+ // to be updated. Example:
+ // Register information: [a, b, c, d]
+ // To be patched: [b, c]
+ // * a != b, a != c, do nothing and move on.
+ // * b == b, patch b, new patch list is [c], move on.
+ // * c == c, patch c, patch list is empty, exit early without looking at d.
+ for (uint32_t idx = 0; idx < num_regs && search_registers.size();
+ ++idx, ++reg_info) {
+ auto reg_it = std::find_if(
+ search_registers.cbegin(), search_registers.cend(),
+ [reg_info](auto reg) { return reg.first == reg_info->name; });
+
+ if (reg_it != search_registers.end()) {
+ // Attach the field information.
+ reg_info->flags_type = reg_it->second;
+ // We do not expect to see this name again so don't look for it again.
+ search_registers.erase(reg_it);
+ }
+ }
+
+ // We do not assert that search_registers is empty here, because it may
+ // contain registers from optional extensions that are not present on the
+ // current target.
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
new file mode 100644
index 000000000000..a5bb38670b9c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
@@ -0,0 +1,86 @@
+//===-- RegisterFlagsDetector_arm64.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
+
+#include "lldb/Target/RegisterFlags.h"
+#include "llvm/ADT/StringRef.h"
+#include <functional>
+
+namespace lldb_private {
+
+struct RegisterInfo;
+
+/// This class manages the storage and detection of register field information.
+/// The same register may have different fields on different CPUs. This class
+/// abstracts out the field detection process so we can use it on live processes
+/// and core files.
+///
+/// The way to use this class is:
+/// * Make an instance somewhere that will last as long as the debug session
+/// (because your final register info will point to this instance).
+/// * Read hardware capabilities from a core note, binary, prctl, etc.
+/// * Pass those to DetectFields.
+/// * Call UpdateRegisterInfo with your RegisterInfo to add pointers
+/// to the detected fields for all registers listed in this class.
+///
+/// This must be done in that order, and you should ensure that if multiple
+/// threads will reference the information, a mutex is used to make sure only
+/// one calls DetectFields.
+class Arm64RegisterFlagsDetector {
+public:
+ /// For the registers listed in this class, detect which fields are
+ /// present. Must be called before UpdateRegisterInfos.
+ /// If called more than once, fields will be redetected each time from
+ /// scratch. If the target would not have this register at all, the list of
+ /// fields will be left empty.
+ void DetectFields(uint64_t hwcap, uint64_t hwcap2);
+
+ /// Add the field information of any registers named in this class,
+ /// to the relevant RegisterInfo instances. Note that this will be done
+ /// with a pointer to the instance of this class that you call this on, so
+ /// the lifetime of that instance must be at least that of the register info.
+ void UpdateRegisterInfo(const RegisterInfo *reg_info, uint32_t num_regs);
+
+ /// Returns true if field detection has been run at least once.
+ bool HasDetected() const { return m_has_detected; }
+
+private:
+ using Fields = std::vector<RegisterFlags::Field>;
+ using DetectorFn = std::function<Fields(uint64_t, uint64_t)>;
+
+ static Fields DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2);
+ static Fields DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2);
+ static Fields DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2);
+ static Fields DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2);
+ static Fields DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2);
+
+ struct RegisterEntry {
+ RegisterEntry(llvm::StringRef name, unsigned size, DetectorFn detector)
+ : m_name(name), m_flags(std::string(name) + "_flags", size, {}),
+ m_detector(detector) {}
+
+ llvm::StringRef m_name;
+ RegisterFlags m_flags;
+ DetectorFn m_detector;
+ } m_registers[5] = {
+ RegisterEntry("cpsr", 4, DetectCPSRFields),
+ RegisterEntry("fpsr", 4, DetectFPSRFields),
+ RegisterEntry("fpcr", 4, DetectFPCRFields),
+ RegisterEntry("mte_ctrl", 8, DetectMTECtrlFields),
+ RegisterEntry("svcr", 8, DetectSVCRFields),
+ };
+
+ // Becomes true once field detection has been run for all registers.
+ bool m_has_detected = false;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoAndSetInterface.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoAndSetInterface.h
new file mode 100644
index 000000000000..7e569dc9ba78
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoAndSetInterface.h
@@ -0,0 +1,36 @@
+//===-- RegisterInfoAndSetInterface.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOANDSETINTERFACE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOANDSETINTERFACE_H
+
+#include "RegisterInfoInterface.h"
+
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/lldb-private-types.h"
+#include <vector>
+
+namespace lldb_private {
+
+class RegisterInfoAndSetInterface : public RegisterInfoInterface {
+public:
+ RegisterInfoAndSetInterface(const lldb_private::ArchSpec &target_arch)
+ : RegisterInfoInterface(target_arch) {}
+
+ virtual size_t GetFPRSize() const = 0;
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet(size_t reg_set) const = 0;
+
+ virtual size_t GetRegisterSetCount() const = 0;
+
+ virtual size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const = 0;
+};
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h
new file mode 100644
index 000000000000..a79c5cc22b24
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h
@@ -0,0 +1,49 @@
+//===-- RegisterInfoInterface.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOINTERFACE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOINTERFACE_H
+
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/lldb-private-types.h"
+#include <vector>
+
+namespace lldb_private {
+
+/// \class RegisterInfoInterface
+///
+/// RegisterInfo interface to patch RegisterInfo structure for archs.
+class RegisterInfoInterface {
+public:
+ RegisterInfoInterface(const lldb_private::ArchSpec &target_arch)
+ : m_target_arch(target_arch) {}
+ virtual ~RegisterInfoInterface() = default;
+
+ virtual size_t GetGPRSize() const = 0;
+
+ virtual const lldb_private::RegisterInfo *GetRegisterInfo() const = 0;
+
+ // Returns the number of registers including the user registers and the
+ // lldb internal registers also
+ virtual uint32_t GetRegisterCount() const = 0;
+
+ // Returns the number of the user registers (excluding the registers
+ // kept for lldb internal use only). Subclasses should override it if
+ // they belongs to an architecture with lldb internal registers.
+ virtual uint32_t GetUserRegisterCount() const { return GetRegisterCount(); }
+
+ const lldb_private::ArchSpec &GetTargetArchitecture() const {
+ return m_target_arch;
+ }
+
+private:
+ lldb_private::ArchSpec m_target_arch;
+};
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp
new file mode 100644
index 000000000000..d47647422ae2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp
@@ -0,0 +1,193 @@
+//===-- RegisterInfoPOSIX_arm.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include <cassert>
+#include <cstddef>
+#include <vector>
+
+#include "lldb/lldb-defines.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterInfoPOSIX_arm.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Based on RegisterContextDarwin_arm.cpp
+#define GPR_OFFSET(idx) ((idx)*4)
+#define FPU_OFFSET(idx) ((idx)*4 + sizeof(RegisterInfoPOSIX_arm::GPR))
+#define FPSCR_OFFSET \
+ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm::FPU, fpscr) + \
+ sizeof(RegisterInfoPOSIX_arm::GPR))
+#define EXC_OFFSET(idx) \
+ ((idx)*4 + sizeof(RegisterInfoPOSIX_arm::GPR) + \
+ sizeof(RegisterInfoPOSIX_arm::FPU))
+#define DBG_OFFSET(reg) \
+ ((LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm::DBG, reg) + \
+ sizeof(RegisterInfoPOSIX_arm::GPR) + sizeof(RegisterInfoPOSIX_arm::FPU) + \
+ sizeof(RegisterInfoPOSIX_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) \
+ #reg, NULL, sizeof(((RegisterInfoPOSIX_arm::DBG *) NULL)->reg[i]), \
+ DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ dbg_##reg##i }, \
+ NULL, NULL, NULL,
+#define REG_CONTEXT_SIZE \
+ (sizeof(RegisterInfoPOSIX_arm::GPR) + sizeof(RegisterInfoPOSIX_arm::FPU) + \
+ sizeof(RegisterInfoPOSIX_arm::EXC))
+
+// Include RegisterInfos_arm to declare our g_register_infos_arm structure.
+#define DECLARE_REGISTER_INFOS_ARM_STRUCT
+#include "RegisterInfos_arm.h"
+#undef DECLARE_REGISTER_INFOS_ARM_STRUCT
+
+static const lldb_private::RegisterInfo *
+GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::arm:
+ return g_register_infos_arm;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::arm:
+ return static_cast<uint32_t>(sizeof(g_register_infos_arm) /
+ sizeof(g_register_infos_arm[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+// Number of register sets provided by this context.
+enum {
+ k_num_gpr_registers = gpr_cpsr - gpr_r0 + 1,
+ k_num_fpr_registers = fpu_q15 - fpu_s0 + 1,
+ k_num_register_sets = 2
+};
+
+// arm general purpose registers.
+static const uint32_t g_gpr_regnums_arm[] = {
+ gpr_r0, gpr_r1,
+ gpr_r2, gpr_r3,
+ gpr_r4, gpr_r5,
+ gpr_r6, gpr_r7,
+ gpr_r8, gpr_r9,
+ gpr_r10, gpr_r11,
+ gpr_r12, gpr_sp,
+ gpr_lr, gpr_pc,
+ gpr_cpsr, 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,
+ "g_gpr_regnums_arm has wrong number of register infos");
+
+// arm floating point registers.
+static const uint32_t g_fpu_regnums_arm[] = {
+ fpu_s0, fpu_s1,
+ fpu_s2, fpu_s3,
+ fpu_s4, fpu_s5,
+ fpu_s6, fpu_s7,
+ fpu_s8, fpu_s9,
+ fpu_s10, fpu_s11,
+ fpu_s12, fpu_s13,
+ fpu_s14, fpu_s15,
+ fpu_s16, fpu_s17,
+ fpu_s18, fpu_s19,
+ fpu_s20, fpu_s21,
+ fpu_s22, fpu_s23,
+ fpu_s24, fpu_s25,
+ fpu_s26, fpu_s27,
+ fpu_s28, fpu_s29,
+ fpu_s30, fpu_s31,
+ fpu_fpscr, fpu_d0,
+ fpu_d1, fpu_d2,
+ fpu_d3, fpu_d4,
+ fpu_d5, fpu_d6,
+ fpu_d7, fpu_d8,
+ fpu_d9, fpu_d10,
+ fpu_d11, fpu_d12,
+ fpu_d13, fpu_d14,
+ fpu_d15, fpu_d16,
+ fpu_d17, fpu_d18,
+ fpu_d19, fpu_d20,
+ fpu_d21, fpu_d22,
+ fpu_d23, fpu_d24,
+ fpu_d25, fpu_d26,
+ fpu_d27, fpu_d28,
+ fpu_d29, fpu_d30,
+ fpu_d31, fpu_q0,
+ fpu_q1, fpu_q2,
+ fpu_q3, fpu_q4,
+ fpu_q5, fpu_q6,
+ fpu_q7, fpu_q8,
+ fpu_q9, fpu_q10,
+ fpu_q11, fpu_q12,
+ fpu_q13, fpu_q14,
+ fpu_q15, 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,
+ "g_fpu_regnums_arm has wrong number of register infos");
+
+// Register sets for arm.
+static const RegisterSet g_reg_sets_arm[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers,
+ g_gpr_regnums_arm},
+ {"Floating Point Registers", "fpu", k_num_fpr_registers,
+ g_fpu_regnums_arm}};
+
+RegisterInfoPOSIX_arm::RegisterInfoPOSIX_arm(
+ const lldb_private::ArchSpec &target_arch)
+ : lldb_private::RegisterInfoAndSetInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch)) {}
+
+size_t RegisterInfoPOSIX_arm::GetGPRSize() const {
+ return sizeof(struct RegisterInfoPOSIX_arm::GPR);
+}
+
+size_t RegisterInfoPOSIX_arm::GetFPRSize() const {
+ return sizeof(struct RegisterInfoPOSIX_arm::FPU);
+}
+
+const lldb_private::RegisterInfo *
+RegisterInfoPOSIX_arm::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+size_t RegisterInfoPOSIX_arm::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
+size_t RegisterInfoPOSIX_arm::GetRegisterSetFromRegisterIndex(
+ uint32_t reg_index) const {
+ if (reg_index <= gpr_cpsr)
+ return GPRegSet;
+ if (reg_index <= fpu_q15)
+ return FPRegSet;
+ return LLDB_INVALID_REGNUM;
+}
+
+const lldb_private::RegisterSet *
+RegisterInfoPOSIX_arm::GetRegisterSet(size_t set_index) const {
+ if (set_index < GetRegisterSetCount())
+ return &g_reg_sets_arm[set_index];
+ return nullptr;
+}
+
+uint32_t RegisterInfoPOSIX_arm::GetRegisterCount() const {
+ return m_register_info_count;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h
new file mode 100644
index 000000000000..db155d757ca8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h
@@ -0,0 +1,72 @@
+//===-- RegisterInfoPOSIX_arm.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H
+
+#include "RegisterInfoAndSetInterface.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+
+class RegisterInfoPOSIX_arm : public lldb_private::RegisterInfoAndSetInterface {
+public:
+ enum { GPRegSet = 0, FPRegSet};
+
+ struct GPR {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+ 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;
+ };
+ struct EXC {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ RegisterInfoPOSIX_arm(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ size_t GetFPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t reg_set) const override;
+
+ size_t GetRegisterSetCount() const override;
+
+ size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
new file mode 100644
index 000000000000..054b7d9b2ec5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
@@ -0,0 +1,561 @@
+//===-- RegisterInfoPOSIX_arm64.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include <cassert>
+#include <cstddef>
+#include <vector>
+
+#include "lldb/lldb-defines.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterInfoPOSIX_arm64.h"
+
+// Based on RegisterContextDarwin_arm64.cpp
+#define GPR_OFFSET(idx) ((idx)*8)
+#define GPR_OFFSET_NAME(reg) \
+ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::GPR, reg))
+
+#define FPU_OFFSET(idx) ((idx)*16 + sizeof(RegisterInfoPOSIX_arm64::GPR))
+#define FPU_OFFSET_NAME(reg) \
+ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::FPU, reg) + \
+ sizeof(RegisterInfoPOSIX_arm64::GPR))
+
+// This information is based on AArch64 with SVE architecture reference manual.
+// AArch64 with SVE has 32 Z and 16 P vector registers. There is also an FFR
+// (First Fault) register and a VG (Vector Granule) pseudo register.
+
+// SVE 16-byte quad word is the basic unit of expansion in vector length.
+#define SVE_QUAD_WORD_BYTES 16
+
+// Vector length is the multiplier which decides the no of quad words,
+// (multiples of 128-bits or 16-bytes) present in a Z register. Vector length
+// is decided during execution and can change at runtime. SVE AArch64 register
+// infos have modes one for each valid value of vector length. A change in
+// vector length requires register context to update sizes of SVE Z, P and FFR.
+// Also register context needs to update byte offsets of all registers affected
+// by the change in vector length.
+#define SVE_REGS_DEFAULT_OFFSET_LINUX sizeof(RegisterInfoPOSIX_arm64::GPR)
+
+#define SVE_OFFSET_VG SVE_REGS_DEFAULT_OFFSET_LINUX
+
+#define EXC_OFFSET_NAME(reg) \
+ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::EXC, reg) + \
+ sizeof(RegisterInfoPOSIX_arm64::GPR) + \
+ sizeof(RegisterInfoPOSIX_arm64::FPU))
+#define DBG_OFFSET_NAME(reg) \
+ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::DBG, reg) + \
+ sizeof(RegisterInfoPOSIX_arm64::GPR) + \
+ sizeof(RegisterInfoPOSIX_arm64::FPU) + \
+ sizeof(RegisterInfoPOSIX_arm64::EXC))
+
+#define DEFINE_DBG(reg, i) \
+ #reg, NULL, \
+ sizeof(((RegisterInfoPOSIX_arm64::DBG *) NULL)->reg[i]), \
+ DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ dbg_##reg##i }, \
+ NULL, NULL, NULL,
+#define REG_CONTEXT_SIZE \
+ (sizeof(RegisterInfoPOSIX_arm64::GPR) + \
+ sizeof(RegisterInfoPOSIX_arm64::FPU) + \
+ sizeof(RegisterInfoPOSIX_arm64::EXC))
+
+// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure.
+#define DECLARE_REGISTER_INFOS_ARM64_STRUCT
+#include "RegisterInfos_arm64.h"
+#include "RegisterInfos_arm64_sve.h"
+#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+static lldb_private::RegisterInfo g_register_infos_pauth[] = {
+ DEFINE_EXTENSION_REG(data_mask), DEFINE_EXTENSION_REG(code_mask)};
+
+static lldb_private::RegisterInfo g_register_infos_mte[] = {
+ DEFINE_EXTENSION_REG(mte_ctrl)};
+
+static lldb_private::RegisterInfo g_register_infos_tls[] = {
+ DEFINE_EXTENSION_REG(tpidr),
+ // Only present when SME is present
+ DEFINE_EXTENSION_REG(tpidr2)};
+
+static lldb_private::RegisterInfo g_register_infos_sme[] = {
+ DEFINE_EXTENSION_REG(svcr),
+ DEFINE_EXTENSION_REG(svg),
+ // 16 is a default size we will change later.
+ {"za", nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8,
+ KIND_ALL_INVALID, nullptr, nullptr, nullptr}};
+
+static lldb_private::RegisterInfo g_register_infos_sme2[] = {
+ {"zt0", nullptr, 64, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8,
+ KIND_ALL_INVALID, nullptr, nullptr, nullptr}};
+
+// Number of register sets provided by this context.
+enum {
+ k_num_gpr_registers = gpr_w28 - gpr_x0 + 1,
+ k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1,
+ k_num_sve_registers = sve_ffr - sve_vg + 1,
+ k_num_mte_register = 1,
+ // Number of TLS registers is dynamic so it is not listed here.
+ k_num_pauth_register = 2,
+ // SME2's ZT0 will also be added to this set if present. So this number is
+ // only for SME1 registers.
+ k_num_sme_register = 3,
+ k_num_register_sets_default = 2,
+ k_num_register_sets = 3
+};
+
+// ARM64 general purpose registers.
+static const uint32_t g_gpr_regnums_arm64[] = {
+ gpr_x0, gpr_x1, gpr_x2, gpr_x3,
+ gpr_x4, gpr_x5, gpr_x6, gpr_x7,
+ gpr_x8, gpr_x9, gpr_x10, gpr_x11,
+ gpr_x12, gpr_x13, gpr_x14, gpr_x15,
+ gpr_x16, gpr_x17, gpr_x18, gpr_x19,
+ gpr_x20, gpr_x21, gpr_x22, gpr_x23,
+ gpr_x24, gpr_x25, gpr_x26, gpr_x27,
+ gpr_x28, gpr_fp, gpr_lr, gpr_sp,
+ gpr_pc, gpr_cpsr, gpr_w0, gpr_w1,
+ gpr_w2, gpr_w3, gpr_w4, gpr_w5,
+ gpr_w6, gpr_w7, gpr_w8, gpr_w9,
+ gpr_w10, gpr_w11, gpr_w12, gpr_w13,
+ gpr_w14, gpr_w15, gpr_w16, gpr_w17,
+ gpr_w18, gpr_w19, gpr_w20, gpr_w21,
+ gpr_w22, gpr_w23, gpr_w24, gpr_w25,
+ gpr_w26, gpr_w27, gpr_w28, LLDB_INVALID_REGNUM};
+
+static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) -
+ 1) == k_num_gpr_registers,
+ "g_gpr_regnums_arm64 has wrong number of register infos");
+
+// ARM64 floating point registers.
+static const uint32_t g_fpu_regnums_arm64[] = {
+ fpu_v0, fpu_v1, fpu_v2,
+ fpu_v3, fpu_v4, fpu_v5,
+ fpu_v6, fpu_v7, fpu_v8,
+ fpu_v9, fpu_v10, fpu_v11,
+ fpu_v12, fpu_v13, fpu_v14,
+ fpu_v15, fpu_v16, fpu_v17,
+ fpu_v18, fpu_v19, fpu_v20,
+ fpu_v21, fpu_v22, fpu_v23,
+ fpu_v24, fpu_v25, fpu_v26,
+ fpu_v27, fpu_v28, fpu_v29,
+ fpu_v30, fpu_v31, fpu_s0,
+ fpu_s1, fpu_s2, fpu_s3,
+ fpu_s4, fpu_s5, fpu_s6,
+ fpu_s7, fpu_s8, fpu_s9,
+ fpu_s10, fpu_s11, fpu_s12,
+ fpu_s13, fpu_s14, fpu_s15,
+ fpu_s16, fpu_s17, fpu_s18,
+ fpu_s19, fpu_s20, fpu_s21,
+ fpu_s22, fpu_s23, fpu_s24,
+ fpu_s25, fpu_s26, fpu_s27,
+ fpu_s28, fpu_s29, fpu_s30,
+ fpu_s31, fpu_d0, fpu_d1,
+ fpu_d2, fpu_d3, fpu_d4,
+ fpu_d5, fpu_d6, fpu_d7,
+ fpu_d8, fpu_d9, fpu_d10,
+ fpu_d11, fpu_d12, fpu_d13,
+ fpu_d14, fpu_d15, fpu_d16,
+ fpu_d17, fpu_d18, fpu_d19,
+ fpu_d20, fpu_d21, fpu_d22,
+ fpu_d23, fpu_d24, fpu_d25,
+ fpu_d26, fpu_d27, fpu_d28,
+ fpu_d29, fpu_d30, fpu_d31,
+ fpu_fpsr, fpu_fpcr, LLDB_INVALID_REGNUM};
+static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) -
+ 1) == k_num_fpr_registers,
+ "g_fpu_regnums_arm64 has wrong number of register infos");
+
+// ARM64 SVE registers.
+static const uint32_t g_sve_regnums_arm64[] = {
+ sve_vg, sve_z0, sve_z1,
+ sve_z2, sve_z3, sve_z4,
+ sve_z5, sve_z6, sve_z7,
+ sve_z8, sve_z9, sve_z10,
+ sve_z11, sve_z12, sve_z13,
+ sve_z14, sve_z15, sve_z16,
+ sve_z17, sve_z18, sve_z19,
+ sve_z20, sve_z21, sve_z22,
+ sve_z23, sve_z24, sve_z25,
+ sve_z26, sve_z27, sve_z28,
+ sve_z29, sve_z30, sve_z31,
+ sve_p0, sve_p1, sve_p2,
+ sve_p3, sve_p4, sve_p5,
+ sve_p6, sve_p7, sve_p8,
+ sve_p9, sve_p10, sve_p11,
+ sve_p12, sve_p13, sve_p14,
+ sve_p15, sve_ffr, LLDB_INVALID_REGNUM};
+static_assert(((sizeof g_sve_regnums_arm64 / sizeof g_sve_regnums_arm64[0]) -
+ 1) == k_num_sve_registers,
+ "g_sve_regnums_arm64 has wrong number of register infos");
+
+// Register sets for ARM64.
+static const lldb_private::RegisterSet g_reg_sets_arm64[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers,
+ g_gpr_regnums_arm64},
+ {"Floating Point Registers", "fpu", k_num_fpr_registers,
+ g_fpu_regnums_arm64},
+ {"Scalable Vector Extension Registers", "sve", k_num_sve_registers,
+ g_sve_regnums_arm64}};
+
+static const lldb_private::RegisterSet g_reg_set_pauth_arm64 = {
+ "Pointer Authentication Registers", "pauth", k_num_pauth_register, nullptr};
+
+static const lldb_private::RegisterSet g_reg_set_mte_arm64 = {
+ "MTE Control Register", "mte", k_num_mte_register, nullptr};
+
+// The size of the TLS set is dynamic, so not listed here.
+
+static const lldb_private::RegisterSet g_reg_set_sme_arm64 = {
+ "Scalable Matrix Extension Registers", "sme", k_num_sme_register, nullptr};
+
+RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64(
+ const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets)
+ : lldb_private::RegisterInfoAndSetInterface(target_arch),
+ m_opt_regsets(opt_regsets) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32: {
+ m_register_set_p = g_reg_sets_arm64;
+ m_register_set_count = k_num_register_sets_default;
+ m_per_regset_regnum_range[GPRegSet] = std::make_pair(gpr_x0, gpr_w28 + 1);
+ m_per_regset_regnum_range[FPRegSet] = std::make_pair(fpu_v0, fpu_fpcr + 1);
+
+ // Now configure register sets supported by current target. If we have a
+ // dynamic register set like MTE, Pointer Authentication regset then we need
+ // to create dynamic register infos and regset array. Push back all optional
+ // register infos and regset and calculate register offsets accordingly.
+ if (m_opt_regsets.AnySet(eRegsetMaskSVE | eRegsetMaskSSVE)) {
+ m_register_info_p = g_register_infos_arm64_sve_le;
+ m_register_info_count = sve_ffr + 1;
+ m_per_regset_regnum_range[m_register_set_count++] =
+ std::make_pair(sve_vg, sve_ffr + 1);
+ } else {
+ m_register_info_p = g_register_infos_arm64_le;
+ m_register_info_count = fpu_fpcr + 1;
+ }
+
+ if (m_opt_regsets.AnySet(eRegsetMaskDynamic)) {
+ llvm::ArrayRef<lldb_private::RegisterInfo> reg_infos_ref =
+ llvm::ArrayRef(m_register_info_p, m_register_info_count);
+ llvm::ArrayRef<lldb_private::RegisterSet> reg_sets_ref =
+ llvm::ArrayRef(m_register_set_p, m_register_set_count);
+ llvm::copy(reg_infos_ref, std::back_inserter(m_dynamic_reg_infos));
+ llvm::copy(reg_sets_ref, std::back_inserter(m_dynamic_reg_sets));
+
+ if (m_opt_regsets.AllSet(eRegsetMaskPAuth))
+ AddRegSetPAuth();
+
+ if (m_opt_regsets.AllSet(eRegsetMaskMTE))
+ AddRegSetMTE();
+
+ // The TLS set always contains tpidr but only has tpidr2 when SME is
+ // present.
+ AddRegSetTLS(m_opt_regsets.AllSet(eRegsetMaskSSVE));
+
+ if (m_opt_regsets.AnySet(eRegsetMaskSSVE))
+ AddRegSetSME(m_opt_regsets.AnySet(eRegsetMaskZT));
+
+ m_register_info_count = m_dynamic_reg_infos.size();
+ m_register_info_p = m_dynamic_reg_infos.data();
+ m_register_set_p = m_dynamic_reg_sets.data();
+ m_register_set_count = m_dynamic_reg_sets.size();
+ }
+ break;
+ }
+ default:
+ assert(false && "Unhandled target architecture.");
+ }
+}
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegisterCount() const {
+ return m_register_info_count;
+}
+
+size_t RegisterInfoPOSIX_arm64::GetGPRSizeStatic() {
+ return sizeof(struct RegisterInfoPOSIX_arm64::GPR);
+}
+
+size_t RegisterInfoPOSIX_arm64::GetFPRSize() const {
+ return sizeof(struct RegisterInfoPOSIX_arm64::FPU);
+}
+
+const lldb_private::RegisterInfo *
+RegisterInfoPOSIX_arm64::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+size_t RegisterInfoPOSIX_arm64::GetRegisterSetCount() const {
+ return m_register_set_count;
+}
+
+size_t RegisterInfoPOSIX_arm64::GetRegisterSetFromRegisterIndex(
+ uint32_t reg_index) const {
+ for (const auto &regset_range : m_per_regset_regnum_range) {
+ if (reg_index >= regset_range.second.first &&
+ reg_index < regset_range.second.second)
+ return regset_range.first;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+const lldb_private::RegisterSet *
+RegisterInfoPOSIX_arm64::GetRegisterSet(size_t set_index) const {
+ if (set_index < GetRegisterSetCount())
+ return &m_register_set_p[set_index];
+ return nullptr;
+}
+
+void RegisterInfoPOSIX_arm64::AddRegSetPAuth() {
+ uint32_t pa_regnum = m_dynamic_reg_infos.size();
+ for (uint32_t i = 0; i < k_num_pauth_register; i++) {
+ pauth_regnum_collection.push_back(pa_regnum + i);
+ m_dynamic_reg_infos.push_back(g_register_infos_pauth[i]);
+ m_dynamic_reg_infos[pa_regnum + i].byte_offset =
+ m_dynamic_reg_infos[pa_regnum + i - 1].byte_offset +
+ m_dynamic_reg_infos[pa_regnum + i - 1].byte_size;
+ m_dynamic_reg_infos[pa_regnum + i].kinds[lldb::eRegisterKindLLDB] =
+ pa_regnum + i;
+ }
+
+ m_per_regset_regnum_range[m_register_set_count] =
+ std::make_pair(pa_regnum, m_dynamic_reg_infos.size());
+ m_dynamic_reg_sets.push_back(g_reg_set_pauth_arm64);
+ m_dynamic_reg_sets.back().registers = pauth_regnum_collection.data();
+}
+
+void RegisterInfoPOSIX_arm64::AddRegSetMTE() {
+ uint32_t mte_regnum = m_dynamic_reg_infos.size();
+ m_mte_regnum_collection.push_back(mte_regnum);
+ m_dynamic_reg_infos.push_back(g_register_infos_mte[0]);
+ m_dynamic_reg_infos[mte_regnum].byte_offset =
+ m_dynamic_reg_infos[mte_regnum - 1].byte_offset +
+ m_dynamic_reg_infos[mte_regnum - 1].byte_size;
+ m_dynamic_reg_infos[mte_regnum].kinds[lldb::eRegisterKindLLDB] = mte_regnum;
+
+ m_per_regset_regnum_range[m_register_set_count] =
+ std::make_pair(mte_regnum, mte_regnum + 1);
+ m_dynamic_reg_sets.push_back(g_reg_set_mte_arm64);
+ m_dynamic_reg_sets.back().registers = m_mte_regnum_collection.data();
+}
+
+void RegisterInfoPOSIX_arm64::AddRegSetTLS(bool has_tpidr2) {
+ uint32_t tls_regnum = m_dynamic_reg_infos.size();
+ uint32_t num_regs = has_tpidr2 ? 2 : 1;
+ for (uint32_t i = 0; i < num_regs; i++) {
+ m_tls_regnum_collection.push_back(tls_regnum + i);
+ m_dynamic_reg_infos.push_back(g_register_infos_tls[i]);
+ m_dynamic_reg_infos[tls_regnum + i].byte_offset =
+ m_dynamic_reg_infos[tls_regnum + i - 1].byte_offset +
+ m_dynamic_reg_infos[tls_regnum + i - 1].byte_size;
+ m_dynamic_reg_infos[tls_regnum + i].kinds[lldb::eRegisterKindLLDB] =
+ tls_regnum + i;
+ }
+
+ m_per_regset_regnum_range[m_register_set_count] =
+ std::make_pair(tls_regnum, m_dynamic_reg_infos.size());
+ m_dynamic_reg_sets.push_back(
+ {"Thread Local Storage Registers", "tls", num_regs, nullptr});
+ m_dynamic_reg_sets.back().registers = m_tls_regnum_collection.data();
+}
+
+void RegisterInfoPOSIX_arm64::AddRegSetSME(bool has_zt) {
+ const uint32_t first_sme_regnum = m_dynamic_reg_infos.size();
+ uint32_t sme_regnum = first_sme_regnum;
+
+ for (uint32_t i = 0; i < k_num_sme_register; ++i, ++sme_regnum) {
+ m_sme_regnum_collection.push_back(sme_regnum);
+ m_dynamic_reg_infos.push_back(g_register_infos_sme[i]);
+ m_dynamic_reg_infos[sme_regnum].byte_offset =
+ m_dynamic_reg_infos[sme_regnum - 1].byte_offset +
+ m_dynamic_reg_infos[sme_regnum - 1].byte_size;
+ m_dynamic_reg_infos[sme_regnum].kinds[lldb::eRegisterKindLLDB] = sme_regnum;
+ }
+
+ lldb_private::RegisterSet sme_regset = g_reg_set_sme_arm64;
+
+ if (has_zt) {
+ m_sme_regnum_collection.push_back(sme_regnum);
+ m_dynamic_reg_infos.push_back(g_register_infos_sme2[0]);
+ m_dynamic_reg_infos[sme_regnum].byte_offset =
+ m_dynamic_reg_infos[sme_regnum - 1].byte_offset +
+ m_dynamic_reg_infos[sme_regnum - 1].byte_size;
+ m_dynamic_reg_infos[sme_regnum].kinds[lldb::eRegisterKindLLDB] = sme_regnum;
+
+ sme_regset.num_registers += 1;
+ }
+
+ m_per_regset_regnum_range[m_register_set_count] =
+ std::make_pair(first_sme_regnum, m_dynamic_reg_infos.size());
+ m_dynamic_reg_sets.push_back(sme_regset);
+ m_dynamic_reg_sets.back().registers = m_sme_regnum_collection.data();
+
+ // When vg is written during streaming mode, svg will also change, as vg and
+ // svg in this state are both showing the streaming vector length.
+ // We model this as vg invalidating svg. In non-streaming mode this doesn't
+ // happen but to keep things simple we will invalidate svg anyway.
+ //
+ // This must be added now, rather than when vg is defined because SME is a
+ // dynamic set that may or may not be present.
+ static uint32_t vg_invalidates[] = {sme_regnum + 1 /*svg*/,
+ LLDB_INVALID_REGNUM};
+ m_dynamic_reg_infos[GetRegNumSVEVG()].invalidate_regs = vg_invalidates;
+}
+
+uint32_t RegisterInfoPOSIX_arm64::ConfigureVectorLengthSVE(uint32_t sve_vq) {
+ // sve_vq contains SVE Quad vector length in context of AArch64 SVE.
+ // SVE register infos if enabled cannot be disabled by selecting sve_vq = 0.
+ // Also if an invalid or previously set vector length is passed to this
+ // function then it will exit immediately with previously set vector length.
+ if (!VectorSizeIsValid(sve_vq) || m_vector_reg_vq == sve_vq)
+ return m_vector_reg_vq;
+
+ // We cannot enable AArch64 only mode if SVE was enabled.
+ if (sve_vq == eVectorQuadwordAArch64 &&
+ m_vector_reg_vq > eVectorQuadwordAArch64)
+ sve_vq = eVectorQuadwordAArch64SVE;
+
+ m_vector_reg_vq = sve_vq;
+
+ if (sve_vq == eVectorQuadwordAArch64)
+ return m_vector_reg_vq;
+ std::vector<lldb_private::RegisterInfo> &reg_info_ref =
+ m_per_vq_reg_infos[sve_vq];
+
+ if (reg_info_ref.empty()) {
+ reg_info_ref = llvm::ArrayRef(m_register_info_p, m_register_info_count);
+
+ uint32_t offset = SVE_REGS_DEFAULT_OFFSET_LINUX;
+ reg_info_ref[fpu_fpsr].byte_offset = offset;
+ reg_info_ref[fpu_fpcr].byte_offset = offset + 4;
+ reg_info_ref[sve_vg].byte_offset = offset + 8;
+ offset += 16;
+
+ // Update Z registers size and offset
+ uint32_t s_reg_base = fpu_s0;
+ uint32_t d_reg_base = fpu_d0;
+ uint32_t v_reg_base = fpu_v0;
+ uint32_t z_reg_base = sve_z0;
+
+ for (uint32_t index = 0; index < 32; index++) {
+ reg_info_ref[s_reg_base + index].byte_offset = offset;
+ reg_info_ref[d_reg_base + index].byte_offset = offset;
+ reg_info_ref[v_reg_base + index].byte_offset = offset;
+ reg_info_ref[z_reg_base + index].byte_offset = offset;
+
+ reg_info_ref[z_reg_base + index].byte_size = sve_vq * SVE_QUAD_WORD_BYTES;
+ offset += reg_info_ref[z_reg_base + index].byte_size;
+ }
+
+ // Update P registers and FFR size and offset
+ for (uint32_t it = sve_p0; it <= sve_ffr; it++) {
+ reg_info_ref[it].byte_offset = offset;
+ reg_info_ref[it].byte_size = sve_vq * SVE_QUAD_WORD_BYTES / 8;
+ offset += reg_info_ref[it].byte_size;
+ }
+
+ for (uint32_t it = sve_ffr + 1; it < m_register_info_count; it++) {
+ reg_info_ref[it].byte_offset = offset;
+ offset += reg_info_ref[it].byte_size;
+ }
+
+ m_per_vq_reg_infos[sve_vq] = reg_info_ref;
+ }
+
+ m_register_info_p = m_per_vq_reg_infos[sve_vq].data();
+ return m_vector_reg_vq;
+}
+
+void RegisterInfoPOSIX_arm64::ConfigureVectorLengthZA(uint32_t za_vq) {
+ if (!VectorSizeIsValid(za_vq) || m_za_reg_vq == za_vq)
+ return;
+
+ m_za_reg_vq = za_vq;
+
+ // For SVE changes, we replace m_register_info_p completely. ZA is in a
+ // dynamic set and is just 1 register so we make an exception to const here.
+ lldb_private::RegisterInfo *non_const_reginfo =
+ const_cast<lldb_private::RegisterInfo *>(m_register_info_p);
+ non_const_reginfo[m_sme_regnum_collection[2]].byte_size =
+ (za_vq * 16) * (za_vq * 16);
+}
+
+bool RegisterInfoPOSIX_arm64::IsSVEReg(unsigned reg) const {
+ if (m_vector_reg_vq > eVectorQuadwordAArch64)
+ return (sve_vg <= reg && reg <= sve_ffr);
+ else
+ return false;
+}
+
+bool RegisterInfoPOSIX_arm64::IsSVEZReg(unsigned reg) const {
+ return (sve_z0 <= reg && reg <= sve_z31);
+}
+
+bool RegisterInfoPOSIX_arm64::IsSVEPReg(unsigned reg) const {
+ return (sve_p0 <= reg && reg <= sve_p15);
+}
+
+bool RegisterInfoPOSIX_arm64::IsSVERegVG(unsigned reg) const {
+ return sve_vg == reg;
+}
+
+bool RegisterInfoPOSIX_arm64::IsSMERegZA(unsigned reg) const {
+ return reg == m_sme_regnum_collection[2];
+}
+
+bool RegisterInfoPOSIX_arm64::IsSMERegZT(unsigned reg) const {
+ // ZT0 is part of the SME register set only if SME2 is present.
+ return m_sme_regnum_collection.size() >= 4 &&
+ reg == m_sme_regnum_collection[3];
+}
+
+bool RegisterInfoPOSIX_arm64::IsPAuthReg(unsigned reg) const {
+ return llvm::is_contained(pauth_regnum_collection, reg);
+}
+
+bool RegisterInfoPOSIX_arm64::IsMTEReg(unsigned reg) const {
+ return llvm::is_contained(m_mte_regnum_collection, reg);
+}
+
+bool RegisterInfoPOSIX_arm64::IsTLSReg(unsigned reg) const {
+ return llvm::is_contained(m_tls_regnum_collection, reg);
+}
+
+bool RegisterInfoPOSIX_arm64::IsSMEReg(unsigned reg) const {
+ return llvm::is_contained(m_sme_regnum_collection, reg);
+}
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; }
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEFFR() const { return sve_ffr; }
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPCR() const { return fpu_fpcr; }
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPSR() const { return fpu_fpsr; }
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEVG() const { return sve_vg; }
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumSMESVG() const {
+ return m_sme_regnum_collection[1];
+}
+
+uint32_t RegisterInfoPOSIX_arm64::GetPAuthOffset() const {
+ return m_register_info_p[pauth_regnum_collection[0]].byte_offset;
+}
+
+uint32_t RegisterInfoPOSIX_arm64::GetMTEOffset() const {
+ return m_register_info_p[m_mte_regnum_collection[0]].byte_offset;
+}
+
+uint32_t RegisterInfoPOSIX_arm64::GetTLSOffset() const {
+ return m_register_info_p[m_tls_regnum_collection[0]].byte_offset;
+}
+
+uint32_t RegisterInfoPOSIX_arm64::GetSMEOffset() const {
+ return m_register_info_p[m_sme_regnum_collection[0]].byte_offset;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
new file mode 100644
index 000000000000..3b8171042c73
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
@@ -0,0 +1,186 @@
+//===-- RegisterInfoPOSIX_arm64.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM64_H
+
+#include "RegisterInfoAndSetInterface.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Flags.h"
+#include "lldb/lldb-private.h"
+#include <map>
+
+enum class SVEState : uint8_t { Unknown, Disabled, FPSIMD, Full, Streaming };
+
+class RegisterInfoPOSIX_arm64
+ : public lldb_private::RegisterInfoAndSetInterface {
+public:
+ enum { GPRegSet = 0, FPRegSet };
+
+ // AArch64 register set mask value
+ enum {
+ eRegsetMaskDefault = 0,
+ eRegsetMaskSVE = 1,
+ eRegsetMaskSSVE = 2,
+ eRegsetMaskPAuth = 4,
+ eRegsetMaskMTE = 8,
+ eRegsetMaskTLS = 16,
+ eRegsetMaskZA = 32,
+ eRegsetMaskZT = 64,
+ eRegsetMaskDynamic = ~1,
+ };
+
+ // AArch64 Register set FP/SIMD feature configuration
+ enum {
+ eVectorQuadwordAArch64,
+ eVectorQuadwordAArch64SVE,
+ eVectorQuadwordAArch64SVEMax = 256
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ LLVM_PACKED_START
+ struct GPR {
+ uint64_t x[29]; // x0-x28
+ uint64_t fp; // x29
+ uint64_t lr; // x30
+ uint64_t sp; // x31
+ uint64_t pc; // pc
+ uint32_t cpsr; // cpsr
+ uint32_t pad;
+ };
+ LLVM_PACKED_END
+
+ // 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;
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct EXC {
+ uint64_t far; // Virtual Fault Address
+ uint32_t esr; // Exception syndrome
+ uint32_t exception; // number of arm exception token
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct DBG {
+ uint64_t bvr[16];
+ uint64_t bcr[16];
+ uint64_t wvr[16];
+ uint64_t wcr[16];
+ uint64_t mdscr_el1;
+ };
+
+ RegisterInfoPOSIX_arm64(const lldb_private::ArchSpec &target_arch,
+ lldb_private::Flags opt_regsets);
+
+ static size_t GetGPRSizeStatic();
+ size_t GetGPRSize() const override { return GetGPRSizeStatic(); }
+
+ size_t GetFPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t reg_set) const override;
+
+ size_t GetRegisterSetCount() const override;
+
+ size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override;
+
+ void AddRegSetPAuth();
+
+ void AddRegSetMTE();
+
+ void AddRegSetTLS(bool has_tpidr2);
+
+ void AddRegSetSME(bool has_zt);
+
+ uint32_t ConfigureVectorLengthSVE(uint32_t sve_vq);
+
+ void ConfigureVectorLengthZA(uint32_t za_vq);
+
+ bool VectorSizeIsValid(uint32_t vq) {
+ // coverity[unsigned_compare]
+ if (vq >= eVectorQuadwordAArch64 && vq <= eVectorQuadwordAArch64SVEMax)
+ return true;
+ return false;
+ }
+
+ bool IsSVEPresent() const { return m_opt_regsets.AnySet(eRegsetMaskSVE); }
+ bool IsSSVEPresent() const { return m_opt_regsets.AnySet(eRegsetMaskSSVE); }
+ bool IsZAPresent() const { return m_opt_regsets.AnySet(eRegsetMaskZA); }
+ bool IsZTPresent() const { return m_opt_regsets.AnySet(eRegsetMaskZT); }
+ bool IsPAuthPresent() const { return m_opt_regsets.AnySet(eRegsetMaskPAuth); }
+ bool IsMTEPresent() const { return m_opt_regsets.AnySet(eRegsetMaskMTE); }
+ bool IsTLSPresent() const { return m_opt_regsets.AnySet(eRegsetMaskTLS); }
+
+ bool IsSVEReg(unsigned reg) const;
+ bool IsSVEZReg(unsigned reg) const;
+ bool IsSVEPReg(unsigned reg) const;
+ bool IsSVERegVG(unsigned reg) const;
+ bool IsPAuthReg(unsigned reg) const;
+ bool IsMTEReg(unsigned reg) const;
+ bool IsTLSReg(unsigned reg) const;
+ bool IsSMEReg(unsigned reg) const;
+ bool IsSMERegZA(unsigned reg) const;
+ bool IsSMERegZT(unsigned reg) const;
+
+ uint32_t GetRegNumSVEZ0() const;
+ uint32_t GetRegNumSVEFFR() const;
+ uint32_t GetRegNumFPCR() const;
+ uint32_t GetRegNumFPSR() const;
+ uint32_t GetRegNumSVEVG() const;
+ uint32_t GetRegNumSMESVG() const;
+ uint32_t GetPAuthOffset() const;
+ uint32_t GetMTEOffset() const;
+ uint32_t GetTLSOffset() const;
+ uint32_t GetSMEOffset() const;
+
+private:
+ typedef std::map<uint32_t, std::vector<lldb_private::RegisterInfo>>
+ per_vq_register_infos;
+
+ per_vq_register_infos m_per_vq_reg_infos;
+
+ uint32_t m_vector_reg_vq = eVectorQuadwordAArch64;
+ uint32_t m_za_reg_vq = eVectorQuadwordAArch64;
+
+ // In normal operation this is const. Only when SVE or SME registers change
+ // size is it either replaced or the content modified.
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+
+ const lldb_private::RegisterSet *m_register_set_p;
+ uint32_t m_register_set_count;
+
+ // Contains pair of [start, end] register numbers of a register set with start
+ // and end included.
+ std::map<uint32_t, std::pair<uint32_t, uint32_t>> m_per_regset_regnum_range;
+
+ lldb_private::Flags m_opt_regsets;
+
+ std::vector<lldb_private::RegisterInfo> m_dynamic_reg_infos;
+ std::vector<lldb_private::RegisterSet> m_dynamic_reg_sets;
+
+ std::vector<uint32_t> pauth_regnum_collection;
+ std::vector<uint32_t> m_mte_regnum_collection;
+ std::vector<uint32_t> m_tls_regnum_collection;
+ std::vector<uint32_t> m_sme_regnum_collection;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.cpp
new file mode 100644
index 000000000000..6c723afe4b69
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.cpp
@@ -0,0 +1,158 @@
+//===-- RegisterInfoPOSIX_loongarch64.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include <cassert>
+#include <lldb/Utility/Flags.h>
+#include <stddef.h>
+
+#include "lldb/lldb-defines.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterInfoPOSIX_loongarch64.h"
+
+#define GPR_OFFSET(idx) ((idx)*8 + 0)
+#define FPR_OFFSET(idx) ((idx)*8 + sizeof(RegisterInfoPOSIX_loongarch64::GPR))
+#define FCC_OFFSET(idx) ((idx)*1 + 32 * 8 + sizeof(RegisterInfoPOSIX_loongarch64::GPR))
+#define FCSR_OFFSET (8 * 1 + 32 * 8 + sizeof(RegisterInfoPOSIX_loongarch64::GPR))
+
+#define REG_CONTEXT_SIZE \
+ (sizeof(RegisterInfoPOSIX_loongarch64::GPR) + \
+ sizeof(RegisterInfoPOSIX_loongarch64::FPR))
+
+#define DECLARE_REGISTER_INFOS_LOONGARCH64_STRUCT
+#include "RegisterInfos_loongarch64.h"
+#undef DECLARE_REGISTER_INFOS_LOONGARCH64_STRUCT
+
+const lldb_private::RegisterInfo *
+RegisterInfoPOSIX_loongarch64::GetRegisterInfoPtr(
+ const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::loongarch64:
+ return g_register_infos_loongarch64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+uint32_t RegisterInfoPOSIX_loongarch64::GetRegisterInfoCount(
+ const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::loongarch64:
+ return static_cast<uint32_t>(sizeof(g_register_infos_loongarch64) /
+ sizeof(g_register_infos_loongarch64[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+// Number of register sets provided by this context.
+enum {
+ k_num_gpr_registers = gpr_last_loongarch - gpr_first_loongarch + 1,
+ k_num_fpr_registers = fpr_last_loongarch - fpr_first_loongarch + 1,
+ k_num_register_sets = 2
+};
+
+// LoongArch64 general purpose registers.
+static const uint32_t g_gpr_regnums_loongarch64[] = {
+ gpr_r0_loongarch, gpr_r1_loongarch, gpr_r2_loongarch,
+ gpr_r3_loongarch, gpr_r4_loongarch, gpr_r5_loongarch,
+ gpr_r6_loongarch, gpr_r7_loongarch, gpr_r8_loongarch,
+ gpr_r9_loongarch, gpr_r10_loongarch, gpr_r11_loongarch,
+ gpr_r12_loongarch, gpr_r13_loongarch, gpr_r14_loongarch,
+ gpr_r15_loongarch, gpr_r16_loongarch, gpr_r17_loongarch,
+ gpr_r18_loongarch, gpr_r19_loongarch, gpr_r20_loongarch,
+ gpr_r21_loongarch, gpr_r22_loongarch, gpr_r23_loongarch,
+ gpr_r24_loongarch, gpr_r25_loongarch, gpr_r26_loongarch,
+ gpr_r27_loongarch, gpr_r28_loongarch, gpr_r29_loongarch,
+ gpr_r30_loongarch, gpr_r31_loongarch, gpr_orig_a0_loongarch,
+ gpr_pc_loongarch, gpr_badv_loongarch, gpr_reserved0_loongarch,
+ gpr_reserved1_loongarch, gpr_reserved2_loongarch, gpr_reserved3_loongarch,
+ gpr_reserved4_loongarch, gpr_reserved5_loongarch, gpr_reserved6_loongarch,
+ gpr_reserved7_loongarch, gpr_reserved8_loongarch, gpr_reserved9_loongarch,
+ LLDB_INVALID_REGNUM};
+
+static_assert(((sizeof g_gpr_regnums_loongarch64 /
+ sizeof g_gpr_regnums_loongarch64[0]) -
+ 1) == k_num_gpr_registers,
+ "g_gpr_regnums_loongarch64 has wrong number of register infos");
+
+// LoongArch64 floating point registers.
+static const uint32_t g_fpr_regnums_loongarch64[] = {
+ fpr_f0_loongarch, fpr_f1_loongarch, fpr_f2_loongarch,
+ fpr_f3_loongarch, fpr_f4_loongarch, fpr_f5_loongarch,
+ fpr_f6_loongarch, fpr_f7_loongarch, fpr_f8_loongarch,
+ fpr_f9_loongarch, fpr_f10_loongarch, fpr_f11_loongarch,
+ fpr_f12_loongarch, fpr_f13_loongarch, fpr_f14_loongarch,
+ fpr_f15_loongarch, fpr_f16_loongarch, fpr_f17_loongarch,
+ fpr_f18_loongarch, fpr_f19_loongarch, fpr_f20_loongarch,
+ fpr_f21_loongarch, fpr_f22_loongarch, fpr_f23_loongarch,
+ fpr_f24_loongarch, fpr_f25_loongarch, fpr_f26_loongarch,
+ fpr_f27_loongarch, fpr_f28_loongarch, fpr_f29_loongarch,
+ fpr_f30_loongarch, fpr_f31_loongarch, fpr_fcc0_loongarch,
+ fpr_fcc1_loongarch, fpr_fcc2_loongarch, fpr_fcc3_loongarch,
+ fpr_fcc4_loongarch, fpr_fcc5_loongarch, fpr_fcc6_loongarch,
+ fpr_fcc7_loongarch, fpr_fcsr_loongarch, LLDB_INVALID_REGNUM};
+
+static_assert(((sizeof g_fpr_regnums_loongarch64 /
+ sizeof g_fpr_regnums_loongarch64[0]) -
+ 1) == k_num_fpr_registers,
+ "g_fpr_regnums_loongarch64 has wrong number of register infos");
+
+// Register sets for LoongArch64.
+static const lldb_private::RegisterSet
+ g_reg_sets_loongarch64[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers,
+ g_gpr_regnums_loongarch64},
+ {"Floating Point Registers", "fpr", k_num_fpr_registers,
+ g_fpr_regnums_loongarch64}};
+
+RegisterInfoPOSIX_loongarch64::RegisterInfoPOSIX_loongarch64(
+ const lldb_private::ArchSpec &target_arch, lldb_private::Flags flags)
+ : lldb_private::RegisterInfoAndSetInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch)) {}
+
+uint32_t RegisterInfoPOSIX_loongarch64::GetRegisterCount() const {
+ return m_register_info_count;
+}
+
+size_t RegisterInfoPOSIX_loongarch64::GetGPRSize() const {
+ return sizeof(struct RegisterInfoPOSIX_loongarch64::GPR);
+}
+
+size_t RegisterInfoPOSIX_loongarch64::GetFPRSize() const {
+ return sizeof(struct RegisterInfoPOSIX_loongarch64::FPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterInfoPOSIX_loongarch64::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+size_t RegisterInfoPOSIX_loongarch64::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
+size_t RegisterInfoPOSIX_loongarch64::GetRegisterSetFromRegisterIndex(
+ uint32_t reg_index) const {
+ // coverity[unsigned_compare]
+ if (reg_index >= gpr_first_loongarch && reg_index <= gpr_last_loongarch)
+ return GPRegSet;
+ if (reg_index >= fpr_first_loongarch && reg_index <= fpr_last_loongarch)
+ return FPRegSet;
+ return LLDB_INVALID_REGNUM;
+}
+
+const lldb_private::RegisterSet *
+RegisterInfoPOSIX_loongarch64::GetRegisterSet(size_t set_index) const {
+ if (set_index < GetRegisterSetCount())
+ return &g_reg_sets_loongarch64[set_index];
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h
new file mode 100644
index 000000000000..a3338acbbc97
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h
@@ -0,0 +1,69 @@
+//===-- RegisterInfoPOSIX_loongarch64.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_LOONGARCH64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_LOONGARCH64_H
+
+#include "RegisterInfoAndSetInterface.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+#include <map>
+
+class RegisterInfoPOSIX_loongarch64
+ : public lldb_private::RegisterInfoAndSetInterface {
+public:
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch);
+ static uint32_t
+ GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch);
+
+public:
+ enum RegSetKind {
+ GPRegSet,
+ FPRegSet,
+ };
+
+ struct GPR {
+ uint64_t gpr[32];
+
+ uint64_t orig_a0;
+ uint64_t csr_era;
+ uint64_t csr_badv;
+ uint64_t reserved[10];
+ };
+
+ struct FPR {
+ uint64_t fpr[32];
+ uint64_t fcc;
+ uint32_t fcsr;
+ };
+
+ RegisterInfoPOSIX_loongarch64(const lldb_private::ArchSpec &target_arch,
+ lldb_private::Flags flags);
+
+ size_t GetGPRSize() const override;
+
+ size_t GetFPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t reg_set) const override;
+
+ size_t GetRegisterSetCount() const override;
+
+ size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp
new file mode 100644
index 000000000000..159fd2856443
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp
@@ -0,0 +1,63 @@
+//===-- RegisterInfoPOSIX_ppc64le.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include <cassert>
+#include <cstddef>
+#include <vector>
+
+#include "lldb/lldb-defines.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterInfoPOSIX_ppc64le.h"
+
+// Include RegisterInfoPOSIX_ppc64le to declare our g_register_infos_ppc64le
+#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
+#include "RegisterInfos_ppc64le.h"
+#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
+
+static const lldb_private::RegisterInfo *
+GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::ppc64le:
+ return g_register_infos_ppc64le;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::ppc64le:
+ return static_cast<uint32_t>(sizeof(g_register_infos_ppc64le) /
+ sizeof(g_register_infos_ppc64le[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterInfoPOSIX_ppc64le::RegisterInfoPOSIX_ppc64le(
+ const lldb_private::ArchSpec &target_arch)
+ : lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch)) {}
+
+size_t RegisterInfoPOSIX_ppc64le::GetGPRSize() const {
+ return sizeof(GPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterInfoPOSIX_ppc64le::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+uint32_t RegisterInfoPOSIX_ppc64le::GetRegisterCount() const {
+ return m_register_info_count;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h
new file mode 100644
index 000000000000..98549ac0dda4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h
@@ -0,0 +1,31 @@
+//===-- RegisterInfoPOSIX_ppc64le.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_PPC64LE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_PPC64LE_H
+
+#include "RegisterInfoInterface.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+
+class RegisterInfoPOSIX_ppc64le : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterInfoPOSIX_ppc64le(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.cpp
new file mode 100644
index 000000000000..3819401c543b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.cpp
@@ -0,0 +1,142 @@
+//===-- RegisterInfoPOSIX_riscv64.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include <cassert>
+#include <lldb/Utility/Flags.h>
+#include <stddef.h>
+
+#include "lldb/lldb-defines.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterInfoPOSIX_riscv64.h"
+
+#define GPR_OFFSET(idx) ((idx)*8 + 0)
+#define FPR_OFFSET(idx) ((idx)*8 + sizeof(RegisterInfoPOSIX_riscv64::GPR))
+
+#define REG_CONTEXT_SIZE \
+ (sizeof(RegisterInfoPOSIX_riscv64::GPR) + \
+ sizeof(RegisterInfoPOSIX_riscv64::FPR))
+
+#define DECLARE_REGISTER_INFOS_RISCV64_STRUCT
+#include "RegisterInfos_riscv64.h"
+#undef DECLARE_REGISTER_INFOS_RISCV64_STRUCT
+
+const lldb_private::RegisterInfo *RegisterInfoPOSIX_riscv64::GetRegisterInfoPtr(
+ const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::riscv64:
+ return g_register_infos_riscv64_le;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+uint32_t RegisterInfoPOSIX_riscv64::GetRegisterInfoCount(
+ const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::riscv64:
+ return static_cast<uint32_t>(sizeof(g_register_infos_riscv64_le) /
+ sizeof(g_register_infos_riscv64_le[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+// Number of register sets provided by this context.
+enum {
+ k_num_gpr_registers = gpr_last_riscv - gpr_first_riscv + 1,
+ k_num_fpr_registers = fpr_last_riscv - fpr_first_riscv + 1,
+ k_num_register_sets = 2
+};
+
+// RISC-V64 general purpose registers.
+static const uint32_t g_gpr_regnums_riscv64[] = {
+ gpr_pc_riscv, gpr_ra_riscv, gpr_sp_riscv, gpr_x3_riscv,
+ gpr_x4_riscv, gpr_x5_riscv, gpr_x6_riscv, gpr_x7_riscv,
+ gpr_fp_riscv, gpr_x9_riscv, gpr_x10_riscv, gpr_x11_riscv,
+ gpr_x12_riscv, gpr_x13_riscv, gpr_x14_riscv, gpr_x15_riscv,
+ gpr_x16_riscv, gpr_x17_riscv, gpr_x18_riscv, gpr_x19_riscv,
+ gpr_x20_riscv, gpr_x21_riscv, gpr_x22_riscv, gpr_x23_riscv,
+ gpr_x24_riscv, gpr_x25_riscv, gpr_x26_riscv, gpr_x27_riscv,
+ gpr_x28_riscv, gpr_x29_riscv, gpr_x30_riscv, gpr_x31_riscv,
+ gpr_x0_riscv, LLDB_INVALID_REGNUM};
+
+static_assert(((sizeof g_gpr_regnums_riscv64 /
+ sizeof g_gpr_regnums_riscv64[0]) -
+ 1) == k_num_gpr_registers,
+ "g_gpr_regnums_riscv64 has wrong number of register infos");
+
+// RISC-V64 floating point registers.
+static const uint32_t g_fpr_regnums_riscv64[] = {
+ fpr_f0_riscv, fpr_f1_riscv, fpr_f2_riscv, fpr_f3_riscv,
+ fpr_f4_riscv, fpr_f5_riscv, fpr_f6_riscv, fpr_f7_riscv,
+ fpr_f8_riscv, fpr_f9_riscv, fpr_f10_riscv, fpr_f11_riscv,
+ fpr_f12_riscv, fpr_f13_riscv, fpr_f14_riscv, fpr_f15_riscv,
+ fpr_f16_riscv, fpr_f17_riscv, fpr_f18_riscv, fpr_f19_riscv,
+ fpr_f20_riscv, fpr_f21_riscv, fpr_f22_riscv, fpr_f23_riscv,
+ fpr_f24_riscv, fpr_f25_riscv, fpr_f26_riscv, fpr_f27_riscv,
+ fpr_f28_riscv, fpr_f29_riscv, fpr_f30_riscv, fpr_f31_riscv,
+ fpr_fcsr_riscv, LLDB_INVALID_REGNUM};
+
+static_assert(((sizeof g_fpr_regnums_riscv64 /
+ sizeof g_fpr_regnums_riscv64[0]) -
+ 1) == k_num_fpr_registers,
+ "g_fpr_regnums_riscv64 has wrong number of register infos");
+
+// Register sets for RISC-V64.
+static const lldb_private::RegisterSet g_reg_sets_riscv64[k_num_register_sets] =
+ {{"General Purpose Registers", "gpr", k_num_gpr_registers,
+ g_gpr_regnums_riscv64},
+ {"Floating Point Registers", "fpr", k_num_fpr_registers,
+ g_fpr_regnums_riscv64}};
+
+RegisterInfoPOSIX_riscv64::RegisterInfoPOSIX_riscv64(
+ const lldb_private::ArchSpec &target_arch, lldb_private::Flags flags)
+ : lldb_private::RegisterInfoAndSetInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch)) {}
+
+uint32_t RegisterInfoPOSIX_riscv64::GetRegisterCount() const {
+ return m_register_info_count;
+}
+
+size_t RegisterInfoPOSIX_riscv64::GetGPRSize() const {
+ return sizeof(struct RegisterInfoPOSIX_riscv64::GPR);
+}
+
+size_t RegisterInfoPOSIX_riscv64::GetFPRSize() const {
+ return sizeof(struct RegisterInfoPOSIX_riscv64::FPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterInfoPOSIX_riscv64::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+size_t RegisterInfoPOSIX_riscv64::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
+size_t RegisterInfoPOSIX_riscv64::GetRegisterSetFromRegisterIndex(
+ uint32_t reg_index) const {
+ // coverity[unsigned_compare]
+ if (reg_index >= gpr_first_riscv && reg_index <= gpr_last_riscv)
+ return GPRegSet;
+ if (reg_index >= fpr_first_riscv && reg_index <= fpr_last_riscv)
+ return FPRegSet;
+ return LLDB_INVALID_REGNUM;
+}
+
+const lldb_private::RegisterSet *
+RegisterInfoPOSIX_riscv64::GetRegisterSet(size_t set_index) const {
+ if (set_index < GetRegisterSetCount())
+ return &g_reg_sets_riscv64[set_index];
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h
new file mode 100644
index 000000000000..4bf4bede0132
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h
@@ -0,0 +1,66 @@
+//===-- RegisterInfoPOSIX_riscv64.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_RISCV64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_RISCV64_H
+
+#include "RegisterInfoAndSetInterface.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+#include <map>
+
+class RegisterInfoPOSIX_riscv64
+ : public lldb_private::RegisterInfoAndSetInterface {
+public:
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch);
+ static uint32_t
+ GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch);
+
+public:
+ enum { GPRegSet = 0, FPRegSet };
+
+ struct GPR {
+ // note: gpr[0] is pc, not x0
+ uint64_t gpr[32];
+ };
+
+ struct FPR {
+ uint64_t fpr[32];
+ uint32_t fcsr;
+ };
+
+ struct VPR {
+ // The size should be VLEN*32 in bits, but we don't have VLEN here.
+ void *vpr;
+ };
+
+ RegisterInfoPOSIX_riscv64(const lldb_private::ArchSpec &target_arch,
+ lldb_private::Flags flags);
+
+ size_t GetGPRSize() const override;
+
+ size_t GetFPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t reg_set) const override;
+
+ size_t GetRegisterSetCount() const override;
+
+ size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+};
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h
new file mode 100644
index 000000000000..ae6a442d7a1d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h
@@ -0,0 +1,800 @@
+//===-- RegisterInfos_arm.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_ARM_STRUCT
+
+#include <cstddef>
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private.h"
+
+#include "Utility/ARM_DWARF_Registers.h"
+#include "Utility/ARM_ehframe_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#ifndef GPR_OFFSET
+#error GPR_OFFSET must be defined before including this header file
+#endif
+
+#ifndef FPU_OFFSET
+#error FPU_OFFSET must be defined before including this header file
+#endif
+
+#ifndef FPSCR_OFFSET
+#error FPSCR_OFFSET must be defined before including this header file
+#endif
+
+#ifndef EXC_OFFSET
+#error EXC_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef DEFINE_DBG
+#error DEFINE_DBG must be defined before including this header file
+#endif
+
+enum {
+ gpr_r0 = 0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_sp = gpr_r13,
+ gpr_r14,
+ gpr_lr = gpr_r14,
+ gpr_r15,
+ gpr_pc = gpr_r15,
+ gpr_cpsr,
+
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+
+ fpu_d0,
+ fpu_d1,
+ fpu_d2,
+ fpu_d3,
+ fpu_d4,
+ fpu_d5,
+ fpu_d6,
+ fpu_d7,
+ fpu_d8,
+ fpu_d9,
+ fpu_d10,
+ fpu_d11,
+ fpu_d12,
+ fpu_d13,
+ fpu_d14,
+ fpu_d15,
+ fpu_d16,
+ fpu_d17,
+ fpu_d18,
+ fpu_d19,
+ fpu_d20,
+ fpu_d21,
+ fpu_d22,
+ fpu_d23,
+ fpu_d24,
+ fpu_d25,
+ fpu_d26,
+ fpu_d27,
+ fpu_d28,
+ fpu_d29,
+ fpu_d30,
+ fpu_d31,
+
+ fpu_q0,
+ fpu_q1,
+ fpu_q2,
+ fpu_q3,
+ fpu_q4,
+ fpu_q5,
+ fpu_q6,
+ fpu_q7,
+ fpu_q8,
+ fpu_q9,
+ fpu_q10,
+ fpu_q11,
+ fpu_q12,
+ fpu_q13,
+ fpu_q14,
+ fpu_q15,
+
+ exc_exception,
+ exc_fsr,
+ exc_far,
+
+ dbg_bvr0,
+ dbg_bvr1,
+ dbg_bvr2,
+ dbg_bvr3,
+ dbg_bvr4,
+ dbg_bvr5,
+ dbg_bvr6,
+ dbg_bvr7,
+ dbg_bvr8,
+ dbg_bvr9,
+ dbg_bvr10,
+ dbg_bvr11,
+ dbg_bvr12,
+ dbg_bvr13,
+ dbg_bvr14,
+ dbg_bvr15,
+
+ dbg_bcr0,
+ dbg_bcr1,
+ dbg_bcr2,
+ dbg_bcr3,
+ dbg_bcr4,
+ dbg_bcr5,
+ dbg_bcr6,
+ dbg_bcr7,
+ dbg_bcr8,
+ dbg_bcr9,
+ dbg_bcr10,
+ dbg_bcr11,
+ dbg_bcr12,
+ dbg_bcr13,
+ dbg_bcr14,
+ dbg_bcr15,
+
+ dbg_wvr0,
+ dbg_wvr1,
+ dbg_wvr2,
+ dbg_wvr3,
+ dbg_wvr4,
+ dbg_wvr5,
+ dbg_wvr6,
+ dbg_wvr7,
+ dbg_wvr8,
+ dbg_wvr9,
+ dbg_wvr10,
+ dbg_wvr11,
+ dbg_wvr12,
+ dbg_wvr13,
+ dbg_wvr14,
+ dbg_wvr15,
+
+ dbg_wcr0,
+ dbg_wcr1,
+ dbg_wcr2,
+ dbg_wcr3,
+ dbg_wcr4,
+ dbg_wcr5,
+ dbg_wcr6,
+ dbg_wcr7,
+ dbg_wcr8,
+ dbg_wcr9,
+ dbg_wcr10,
+ dbg_wcr11,
+ dbg_wcr12,
+ dbg_wcr13,
+ dbg_wcr14,
+ dbg_wcr15,
+
+ k_num_registers
+};
+
+static uint32_t g_s0_invalidates[] = {fpu_d0, fpu_q0, LLDB_INVALID_REGNUM};
+static uint32_t g_s1_invalidates[] = {fpu_d0, fpu_q0, LLDB_INVALID_REGNUM};
+static uint32_t g_s2_invalidates[] = {fpu_d1, fpu_q0, LLDB_INVALID_REGNUM};
+static uint32_t g_s3_invalidates[] = {fpu_d1, fpu_q0, LLDB_INVALID_REGNUM};
+static uint32_t g_s4_invalidates[] = {fpu_d2, fpu_q1, LLDB_INVALID_REGNUM};
+static uint32_t g_s5_invalidates[] = {fpu_d2, fpu_q1, LLDB_INVALID_REGNUM};
+static uint32_t g_s6_invalidates[] = {fpu_d3, fpu_q1, LLDB_INVALID_REGNUM};
+static uint32_t g_s7_invalidates[] = {fpu_d3, fpu_q1, LLDB_INVALID_REGNUM};
+static uint32_t g_s8_invalidates[] = {fpu_d4, fpu_q2, LLDB_INVALID_REGNUM};
+static uint32_t g_s9_invalidates[] = {fpu_d4, fpu_q2, LLDB_INVALID_REGNUM};
+static uint32_t g_s10_invalidates[] = {fpu_d5, fpu_q2, LLDB_INVALID_REGNUM};
+static uint32_t g_s11_invalidates[] = {fpu_d5, fpu_q2, LLDB_INVALID_REGNUM};
+static uint32_t g_s12_invalidates[] = {fpu_d6, fpu_q3, LLDB_INVALID_REGNUM};
+static uint32_t g_s13_invalidates[] = {fpu_d6, fpu_q3, LLDB_INVALID_REGNUM};
+static uint32_t g_s14_invalidates[] = {fpu_d7, fpu_q3, LLDB_INVALID_REGNUM};
+static uint32_t g_s15_invalidates[] = {fpu_d7, fpu_q3, LLDB_INVALID_REGNUM};
+static uint32_t g_s16_invalidates[] = {fpu_d8, fpu_q4, LLDB_INVALID_REGNUM};
+static uint32_t g_s17_invalidates[] = {fpu_d8, fpu_q4, LLDB_INVALID_REGNUM};
+static uint32_t g_s18_invalidates[] = {fpu_d9, fpu_q4, LLDB_INVALID_REGNUM};
+static uint32_t g_s19_invalidates[] = {fpu_d9, fpu_q4, LLDB_INVALID_REGNUM};
+static uint32_t g_s20_invalidates[] = {fpu_d10, fpu_q5, LLDB_INVALID_REGNUM};
+static uint32_t g_s21_invalidates[] = {fpu_d10, fpu_q5, LLDB_INVALID_REGNUM};
+static uint32_t g_s22_invalidates[] = {fpu_d11, fpu_q5, LLDB_INVALID_REGNUM};
+static uint32_t g_s23_invalidates[] = {fpu_d11, fpu_q5, LLDB_INVALID_REGNUM};
+static uint32_t g_s24_invalidates[] = {fpu_d12, fpu_q6, LLDB_INVALID_REGNUM};
+static uint32_t g_s25_invalidates[] = {fpu_d12, fpu_q6, LLDB_INVALID_REGNUM};
+static uint32_t g_s26_invalidates[] = {fpu_d13, fpu_q6, LLDB_INVALID_REGNUM};
+static uint32_t g_s27_invalidates[] = {fpu_d13, fpu_q6, LLDB_INVALID_REGNUM};
+static uint32_t g_s28_invalidates[] = {fpu_d14, fpu_q7, LLDB_INVALID_REGNUM};
+static uint32_t g_s29_invalidates[] = {fpu_d14, fpu_q7, LLDB_INVALID_REGNUM};
+static uint32_t g_s30_invalidates[] = {fpu_d15, fpu_q7, LLDB_INVALID_REGNUM};
+static uint32_t g_s31_invalidates[] = {fpu_d15, fpu_q7, LLDB_INVALID_REGNUM};
+
+static uint32_t g_d0_invalidates[] = {fpu_q0, fpu_s0, fpu_s1,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d1_invalidates[] = {fpu_q0, fpu_s2, fpu_s3,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d2_invalidates[] = {fpu_q1, fpu_s4, fpu_s5,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d3_invalidates[] = {fpu_q1, fpu_s6, fpu_s7,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d4_invalidates[] = {fpu_q2, fpu_s8, fpu_s9,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d5_invalidates[] = {fpu_q2, fpu_s10, fpu_s11,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d6_invalidates[] = {fpu_q3, fpu_s12, fpu_s13,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d7_invalidates[] = {fpu_q3, fpu_s14, fpu_s15,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d8_invalidates[] = {fpu_q4, fpu_s16, fpu_s17,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d9_invalidates[] = {fpu_q4, fpu_s18, fpu_s19,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d10_invalidates[] = {fpu_q5, fpu_s20, fpu_s21,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d11_invalidates[] = {fpu_q5, fpu_s22, fpu_s23,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d12_invalidates[] = {fpu_q6, fpu_s24, fpu_s25,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d13_invalidates[] = {fpu_q6, fpu_s26, fpu_s27,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d14_invalidates[] = {fpu_q7, fpu_s28, fpu_s29,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d15_invalidates[] = {fpu_q7, fpu_s30, fpu_s31,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_d16_invalidates[] = {fpu_q8, LLDB_INVALID_REGNUM};
+static uint32_t g_d17_invalidates[] = {fpu_q8, LLDB_INVALID_REGNUM};
+static uint32_t g_d18_invalidates[] = {fpu_q9, LLDB_INVALID_REGNUM};
+static uint32_t g_d19_invalidates[] = {fpu_q9, LLDB_INVALID_REGNUM};
+static uint32_t g_d20_invalidates[] = {fpu_q10, LLDB_INVALID_REGNUM};
+static uint32_t g_d21_invalidates[] = {fpu_q10, LLDB_INVALID_REGNUM};
+static uint32_t g_d22_invalidates[] = {fpu_q11, LLDB_INVALID_REGNUM};
+static uint32_t g_d23_invalidates[] = {fpu_q11, LLDB_INVALID_REGNUM};
+static uint32_t g_d24_invalidates[] = {fpu_q12, LLDB_INVALID_REGNUM};
+static uint32_t g_d25_invalidates[] = {fpu_q12, LLDB_INVALID_REGNUM};
+static uint32_t g_d26_invalidates[] = {fpu_q13, LLDB_INVALID_REGNUM};
+static uint32_t g_d27_invalidates[] = {fpu_q13, LLDB_INVALID_REGNUM};
+static uint32_t g_d28_invalidates[] = {fpu_q14, LLDB_INVALID_REGNUM};
+static uint32_t g_d29_invalidates[] = {fpu_q14, LLDB_INVALID_REGNUM};
+static uint32_t g_d30_invalidates[] = {fpu_q15, LLDB_INVALID_REGNUM};
+static uint32_t g_d31_invalidates[] = {fpu_q15, LLDB_INVALID_REGNUM};
+
+static uint32_t g_q0_invalidates[] = {
+ fpu_d0, fpu_d1, fpu_s0, fpu_s1, fpu_s2, fpu_s3, LLDB_INVALID_REGNUM};
+static uint32_t g_q1_invalidates[] = {
+ fpu_d2, fpu_d3, fpu_s4, fpu_s5, fpu_s6, fpu_s7, LLDB_INVALID_REGNUM};
+static uint32_t g_q2_invalidates[] = {
+ fpu_d4, fpu_d5, fpu_s8, fpu_s9, fpu_s10, fpu_s11, LLDB_INVALID_REGNUM};
+static uint32_t g_q3_invalidates[] = {
+ fpu_d6, fpu_d7, fpu_s12, fpu_s13, fpu_s14, fpu_s15, LLDB_INVALID_REGNUM};
+static uint32_t g_q4_invalidates[] = {
+ fpu_d8, fpu_d9, fpu_s16, fpu_s17, fpu_s18, fpu_s19, LLDB_INVALID_REGNUM};
+static uint32_t g_q5_invalidates[] = {
+ fpu_d10, fpu_d11, fpu_s20, fpu_s21, fpu_s22, fpu_s23, LLDB_INVALID_REGNUM};
+static uint32_t g_q6_invalidates[] = {
+ fpu_d12, fpu_d13, fpu_s24, fpu_s25, fpu_s26, fpu_s27, LLDB_INVALID_REGNUM};
+static uint32_t g_q7_invalidates[] = {
+ fpu_d14, fpu_d15, fpu_s28, fpu_s29, fpu_s30, fpu_s31, LLDB_INVALID_REGNUM};
+static uint32_t g_q8_invalidates[] = {fpu_d16, fpu_d17, LLDB_INVALID_REGNUM};
+static uint32_t g_q9_invalidates[] = {fpu_d18, fpu_d19, LLDB_INVALID_REGNUM};
+static uint32_t g_q10_invalidates[] = {fpu_d20, fpu_d21, LLDB_INVALID_REGNUM};
+static uint32_t g_q11_invalidates[] = {fpu_d22, fpu_d23, LLDB_INVALID_REGNUM};
+static uint32_t g_q12_invalidates[] = {fpu_d24, fpu_d25, LLDB_INVALID_REGNUM};
+static uint32_t g_q13_invalidates[] = {fpu_d26, fpu_d27, LLDB_INVALID_REGNUM};
+static uint32_t g_q14_invalidates[] = {fpu_d28, fpu_d29, LLDB_INVALID_REGNUM};
+static uint32_t g_q15_invalidates[] = {fpu_d30, fpu_d31, LLDB_INVALID_REGNUM};
+
+static uint32_t g_q0_contained[] = {fpu_q0, LLDB_INVALID_REGNUM};
+static uint32_t g_q1_contained[] = {fpu_q1, LLDB_INVALID_REGNUM};
+static uint32_t g_q2_contained[] = {fpu_q2, LLDB_INVALID_REGNUM};
+static uint32_t g_q3_contained[] = {fpu_q3, LLDB_INVALID_REGNUM};
+static uint32_t g_q4_contained[] = {fpu_q4, LLDB_INVALID_REGNUM};
+static uint32_t g_q5_contained[] = {fpu_q5, LLDB_INVALID_REGNUM};
+static uint32_t g_q6_contained[] = {fpu_q6, LLDB_INVALID_REGNUM};
+static uint32_t g_q7_contained[] = {fpu_q7, LLDB_INVALID_REGNUM};
+static uint32_t g_q8_contained[] = {fpu_q8, LLDB_INVALID_REGNUM};
+static uint32_t g_q9_contained[] = {fpu_q9, LLDB_INVALID_REGNUM};
+static uint32_t g_q10_contained[] = {fpu_q10, LLDB_INVALID_REGNUM};
+static uint32_t g_q11_contained[] = {fpu_q11, LLDB_INVALID_REGNUM};
+static uint32_t g_q12_contained[] = {fpu_q12, LLDB_INVALID_REGNUM};
+static uint32_t g_q13_contained[] = {fpu_q13, LLDB_INVALID_REGNUM};
+static uint32_t g_q14_contained[] = {fpu_q14, LLDB_INVALID_REGNUM};
+static uint32_t g_q15_contained[] = {fpu_q15, LLDB_INVALID_REGNUM};
+
+#define FPU_REG(name, size, offset, qreg) \
+ { \
+ #name, nullptr, size, FPU_OFFSET(offset), eEncodingIEEE754, eFormatFloat, \
+ {LLDB_INVALID_REGNUM, dwarf_##name, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, fpu_##name }, \
+ g_##qreg##_contained, g_##name##_invalidates, nullptr, \
+ }
+
+#define FPU_QREG(name, offset) \
+ { \
+ #name, nullptr, 16, FPU_OFFSET(offset), eEncodingVector, \
+ eFormatVectorOfUInt8, \
+ {LLDB_INVALID_REGNUM, dwarf_##name, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, fpu_##name }, \
+ nullptr, g_##name##_invalidates, nullptr, \
+ }
+
+static RegisterInfo g_register_infos_arm[] = {
+ // NAME ALT SZ OFFSET ENCODING FORMAT
+ // EH_FRAME DWARF GENERIC
+ // PROCESS PLUGIN LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // =========== ======= == ============== ================
+ // ==================== =================== ===================
+ // ========================== =================== =============
+ // ============== =================
+ {
+ "r0",
+ nullptr,
+ 4,
+ GPR_OFFSET(0),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM,
+ gpr_r0},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r1",
+ nullptr,
+ 4,
+ GPR_OFFSET(1),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM,
+ gpr_r1},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r2",
+ nullptr,
+ 4,
+ GPR_OFFSET(2),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM,
+ gpr_r2},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r3",
+ nullptr,
+ 4,
+ GPR_OFFSET(3),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM,
+ gpr_r3},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r4",
+ nullptr,
+ 4,
+ GPR_OFFSET(4),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r4, dwarf_r4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r4},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r5",
+ nullptr,
+ 4,
+ GPR_OFFSET(5),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r5, dwarf_r5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r5},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r6",
+ nullptr,
+ 4,
+ GPR_OFFSET(6),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r6, dwarf_r6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r6},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r7",
+ nullptr,
+ 4,
+ GPR_OFFSET(7),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r7, dwarf_r7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r7},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r8",
+ nullptr,
+ 4,
+ GPR_OFFSET(8),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r8, dwarf_r8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r8},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r9",
+ nullptr,
+ 4,
+ GPR_OFFSET(9),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r9, dwarf_r9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r9},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r10",
+ nullptr,
+ 4,
+ GPR_OFFSET(10),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r10},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r11",
+ nullptr,
+ 4,
+ GPR_OFFSET(11),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM,
+ gpr_r11},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "r12",
+ nullptr,
+ 4,
+ GPR_OFFSET(12),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_r12},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "sp",
+ "r13",
+ 4,
+ GPR_OFFSET(13),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM,
+ gpr_sp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "lr",
+ "r14",
+ 4,
+ GPR_OFFSET(14),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM,
+ gpr_lr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "pc",
+ "r15",
+ 4,
+ GPR_OFFSET(15),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM,
+ gpr_pc},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "cpsr",
+ "psr",
+ 4,
+ GPR_OFFSET(16),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS,
+ LLDB_INVALID_REGNUM, gpr_cpsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+
+ FPU_REG(s0, 4, 0, q0),
+ FPU_REG(s1, 4, 1, q0),
+ FPU_REG(s2, 4, 2, q0),
+ FPU_REG(s3, 4, 3, q0),
+ FPU_REG(s4, 4, 4, q1),
+ FPU_REG(s5, 4, 5, q1),
+ FPU_REG(s6, 4, 6, q1),
+ FPU_REG(s7, 4, 7, q1),
+ FPU_REG(s8, 4, 8, q2),
+ FPU_REG(s9, 4, 9, q2),
+ FPU_REG(s10, 4, 10, q2),
+ FPU_REG(s11, 4, 11, q2),
+ FPU_REG(s12, 4, 12, q3),
+ FPU_REG(s13, 4, 13, q3),
+ FPU_REG(s14, 4, 14, q3),
+ FPU_REG(s15, 4, 15, q3),
+ FPU_REG(s16, 4, 16, q4),
+ FPU_REG(s17, 4, 17, q4),
+ FPU_REG(s18, 4, 18, q4),
+ FPU_REG(s19, 4, 19, q4),
+ FPU_REG(s20, 4, 20, q5),
+ FPU_REG(s21, 4, 21, q5),
+ FPU_REG(s22, 4, 22, q5),
+ FPU_REG(s23, 4, 23, q5),
+ FPU_REG(s24, 4, 24, q6),
+ FPU_REG(s25, 4, 25, q6),
+ FPU_REG(s26, 4, 26, q6),
+ FPU_REG(s27, 4, 27, q6),
+ FPU_REG(s28, 4, 28, q7),
+ FPU_REG(s29, 4, 29, q7),
+ FPU_REG(s30, 4, 30, q7),
+ FPU_REG(s31, 4, 31, q7),
+
+ {
+ "fpscr",
+ nullptr,
+ 4,
+ FPSCR_OFFSET,
+ eEncodingUint,
+ eFormatHex,
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, fpu_fpscr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+
+ FPU_REG(d0, 8, 0, q0),
+ FPU_REG(d1, 8, 2, q0),
+ FPU_REG(d2, 8, 4, q1),
+ FPU_REG(d3, 8, 6, q1),
+ FPU_REG(d4, 8, 8, q2),
+ FPU_REG(d5, 8, 10, q2),
+ FPU_REG(d6, 8, 12, q3),
+ FPU_REG(d7, 8, 14, q3),
+ FPU_REG(d8, 8, 16, q4),
+ FPU_REG(d9, 8, 18, q4),
+ FPU_REG(d10, 8, 20, q5),
+ FPU_REG(d11, 8, 22, q5),
+ FPU_REG(d12, 8, 24, q6),
+ FPU_REG(d13, 8, 26, q6),
+ FPU_REG(d14, 8, 28, q7),
+ FPU_REG(d15, 8, 30, q7),
+ FPU_REG(d16, 8, 32, q8),
+ FPU_REG(d17, 8, 34, q8),
+ FPU_REG(d18, 8, 36, q9),
+ FPU_REG(d19, 8, 38, q9),
+ FPU_REG(d20, 8, 40, q10),
+ FPU_REG(d21, 8, 42, q10),
+ FPU_REG(d22, 8, 44, q11),
+ FPU_REG(d23, 8, 46, q11),
+ FPU_REG(d24, 8, 48, q12),
+ FPU_REG(d25, 8, 50, q12),
+ FPU_REG(d26, 8, 52, q13),
+ FPU_REG(d27, 8, 54, q13),
+ FPU_REG(d28, 8, 56, q14),
+ FPU_REG(d29, 8, 58, q14),
+ FPU_REG(d30, 8, 60, q15),
+ FPU_REG(d31, 8, 62, q15),
+
+ FPU_QREG(q0, 0),
+ FPU_QREG(q1, 4),
+ FPU_QREG(q2, 8),
+ FPU_QREG(q3, 12),
+ FPU_QREG(q4, 16),
+ FPU_QREG(q5, 20),
+ FPU_QREG(q6, 24),
+ FPU_QREG(q7, 28),
+ FPU_QREG(q8, 32),
+ FPU_QREG(q9, 36),
+ FPU_QREG(q10, 40),
+ FPU_QREG(q11, 44),
+ FPU_QREG(q12, 48),
+ FPU_QREG(q13, 52),
+ FPU_QREG(q14, 56),
+ FPU_QREG(q15, 60),
+
+ {
+ "exception",
+ nullptr,
+ 4,
+ EXC_OFFSET(0),
+ eEncodingUint,
+ eFormatHex,
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_exception},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "fsr",
+ nullptr,
+ 4,
+ EXC_OFFSET(1),
+ eEncodingUint,
+ eFormatHex,
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_fsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {
+ "far",
+ nullptr,
+ 4,
+ EXC_OFFSET(2),
+ eEncodingUint,
+ eFormatHex,
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, exc_far},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+
+ {DEFINE_DBG(bvr, 0)},
+ {DEFINE_DBG(bvr, 1)},
+ {DEFINE_DBG(bvr, 2)},
+ {DEFINE_DBG(bvr, 3)},
+ {DEFINE_DBG(bvr, 4)},
+ {DEFINE_DBG(bvr, 5)},
+ {DEFINE_DBG(bvr, 6)},
+ {DEFINE_DBG(bvr, 7)},
+ {DEFINE_DBG(bvr, 8)},
+ {DEFINE_DBG(bvr, 9)},
+ {DEFINE_DBG(bvr, 10)},
+ {DEFINE_DBG(bvr, 11)},
+ {DEFINE_DBG(bvr, 12)},
+ {DEFINE_DBG(bvr, 13)},
+ {DEFINE_DBG(bvr, 14)},
+ {DEFINE_DBG(bvr, 15)},
+
+ {DEFINE_DBG(bcr, 0)},
+ {DEFINE_DBG(bcr, 1)},
+ {DEFINE_DBG(bcr, 2)},
+ {DEFINE_DBG(bcr, 3)},
+ {DEFINE_DBG(bcr, 4)},
+ {DEFINE_DBG(bcr, 5)},
+ {DEFINE_DBG(bcr, 6)},
+ {DEFINE_DBG(bcr, 7)},
+ {DEFINE_DBG(bcr, 8)},
+ {DEFINE_DBG(bcr, 9)},
+ {DEFINE_DBG(bcr, 10)},
+ {DEFINE_DBG(bcr, 11)},
+ {DEFINE_DBG(bcr, 12)},
+ {DEFINE_DBG(bcr, 13)},
+ {DEFINE_DBG(bcr, 14)},
+ {DEFINE_DBG(bcr, 15)},
+
+ {DEFINE_DBG(wvr, 0)},
+ {DEFINE_DBG(wvr, 1)},
+ {DEFINE_DBG(wvr, 2)},
+ {DEFINE_DBG(wvr, 3)},
+ {DEFINE_DBG(wvr, 4)},
+ {DEFINE_DBG(wvr, 5)},
+ {DEFINE_DBG(wvr, 6)},
+ {DEFINE_DBG(wvr, 7)},
+ {DEFINE_DBG(wvr, 8)},
+ {DEFINE_DBG(wvr, 9)},
+ {DEFINE_DBG(wvr, 10)},
+ {DEFINE_DBG(wvr, 11)},
+ {DEFINE_DBG(wvr, 12)},
+ {DEFINE_DBG(wvr, 13)},
+ {DEFINE_DBG(wvr, 14)},
+ {DEFINE_DBG(wvr, 15)},
+
+ {DEFINE_DBG(wcr, 0)},
+ {DEFINE_DBG(wcr, 1)},
+ {DEFINE_DBG(wcr, 2)},
+ {DEFINE_DBG(wcr, 3)},
+ {DEFINE_DBG(wcr, 4)},
+ {DEFINE_DBG(wcr, 5)},
+ {DEFINE_DBG(wcr, 6)},
+ {DEFINE_DBG(wcr, 7)},
+ {DEFINE_DBG(wcr, 8)},
+ {DEFINE_DBG(wcr, 9)},
+ {DEFINE_DBG(wcr, 10)},
+ {DEFINE_DBG(wcr, 11)},
+ {DEFINE_DBG(wcr, 12)},
+ {DEFINE_DBG(wcr, 13)},
+ {DEFINE_DBG(wcr, 14)},
+ {DEFINE_DBG(wcr, 15)}};
+
+#endif // DECLARE_REGISTER_INFOS_ARM_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h
new file mode 100644
index 000000000000..c9c4d7ceae55
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h
@@ -0,0 +1,793 @@
+//===-- RegisterInfos_arm64.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+#include <cstddef>
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private.h"
+
+#include "Utility/ARM64_DWARF_Registers.h"
+#include "Utility/ARM64_ehframe_Registers.h"
+
+#ifndef GPR_OFFSET
+#error GPR_OFFSET must be defined before including this header file
+#endif
+
+#ifndef GPR_OFFSET_NAME
+#error GPR_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef FPU_OFFSET
+#error FPU_OFFSET must be defined before including this header file
+#endif
+
+#ifndef FPU_OFFSET_NAME
+#error FPU_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef EXC_OFFSET_NAME
+#error EXC_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef DBG_OFFSET_NAME
+#error DBG_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef DEFINE_DBG
+#error DEFINE_DBG must be defined before including this header file
+#endif
+
+// Offsets for a little-endian layout of the register context
+#define GPR_W_PSEUDO_REG_ENDIAN_OFFSET 0
+#define FPU_S_PSEUDO_REG_ENDIAN_OFFSET 0
+#define FPU_D_PSEUDO_REG_ENDIAN_OFFSET 0
+
+enum {
+ gpr_x0 = 0,
+ gpr_x1,
+ gpr_x2,
+ gpr_x3,
+ gpr_x4,
+ gpr_x5,
+ gpr_x6,
+ gpr_x7,
+ gpr_x8,
+ gpr_x9,
+ gpr_x10,
+ gpr_x11,
+ gpr_x12,
+ gpr_x13,
+ gpr_x14,
+ gpr_x15,
+ gpr_x16,
+ gpr_x17,
+ gpr_x18,
+ gpr_x19,
+ gpr_x20,
+ gpr_x21,
+ gpr_x22,
+ gpr_x23,
+ gpr_x24,
+ gpr_x25,
+ gpr_x26,
+ gpr_x27,
+ gpr_x28,
+ gpr_x29 = 29,
+ gpr_fp = gpr_x29,
+ gpr_x30 = 30,
+ gpr_lr = gpr_x30,
+ gpr_ra = gpr_x30,
+ gpr_x31 = 31,
+ gpr_sp = gpr_x31,
+ gpr_pc = 32,
+ gpr_cpsr,
+
+ gpr_w0,
+ gpr_w1,
+ gpr_w2,
+ gpr_w3,
+ gpr_w4,
+ gpr_w5,
+ gpr_w6,
+ gpr_w7,
+ gpr_w8,
+ gpr_w9,
+ gpr_w10,
+ gpr_w11,
+ gpr_w12,
+ gpr_w13,
+ gpr_w14,
+ gpr_w15,
+ gpr_w16,
+ gpr_w17,
+ gpr_w18,
+ gpr_w19,
+ gpr_w20,
+ gpr_w21,
+ gpr_w22,
+ gpr_w23,
+ gpr_w24,
+ gpr_w25,
+ gpr_w26,
+ gpr_w27,
+ gpr_w28,
+
+ fpu_v0,
+ fpu_v1,
+ fpu_v2,
+ fpu_v3,
+ fpu_v4,
+ fpu_v5,
+ fpu_v6,
+ fpu_v7,
+ fpu_v8,
+ fpu_v9,
+ fpu_v10,
+ fpu_v11,
+ fpu_v12,
+ fpu_v13,
+ fpu_v14,
+ fpu_v15,
+ fpu_v16,
+ fpu_v17,
+ fpu_v18,
+ fpu_v19,
+ fpu_v20,
+ fpu_v21,
+ fpu_v22,
+ fpu_v23,
+ fpu_v24,
+ fpu_v25,
+ fpu_v26,
+ fpu_v27,
+ fpu_v28,
+ fpu_v29,
+ fpu_v30,
+ fpu_v31,
+
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+
+ fpu_d0,
+ fpu_d1,
+ fpu_d2,
+ fpu_d3,
+ fpu_d4,
+ fpu_d5,
+ fpu_d6,
+ fpu_d7,
+ fpu_d8,
+ fpu_d9,
+ fpu_d10,
+ fpu_d11,
+ fpu_d12,
+ fpu_d13,
+ fpu_d14,
+ fpu_d15,
+ fpu_d16,
+ fpu_d17,
+ fpu_d18,
+ fpu_d19,
+ fpu_d20,
+ fpu_d21,
+ fpu_d22,
+ fpu_d23,
+ fpu_d24,
+ fpu_d25,
+ fpu_d26,
+ fpu_d27,
+ fpu_d28,
+ fpu_d29,
+ fpu_d30,
+ fpu_d31,
+
+ fpu_fpsr,
+ fpu_fpcr,
+
+ exc_far,
+ exc_esr,
+ exc_exception,
+
+ dbg_bvr0,
+ dbg_bvr1,
+ dbg_bvr2,
+ dbg_bvr3,
+ dbg_bvr4,
+ dbg_bvr5,
+ dbg_bvr6,
+ dbg_bvr7,
+ dbg_bvr8,
+ dbg_bvr9,
+ dbg_bvr10,
+ dbg_bvr11,
+ dbg_bvr12,
+ dbg_bvr13,
+ dbg_bvr14,
+ dbg_bvr15,
+
+ dbg_bcr0,
+ dbg_bcr1,
+ dbg_bcr2,
+ dbg_bcr3,
+ dbg_bcr4,
+ dbg_bcr5,
+ dbg_bcr6,
+ dbg_bcr7,
+ dbg_bcr8,
+ dbg_bcr9,
+ dbg_bcr10,
+ dbg_bcr11,
+ dbg_bcr12,
+ dbg_bcr13,
+ dbg_bcr14,
+ dbg_bcr15,
+
+ dbg_wvr0,
+ dbg_wvr1,
+ dbg_wvr2,
+ dbg_wvr3,
+ dbg_wvr4,
+ dbg_wvr5,
+ dbg_wvr6,
+ dbg_wvr7,
+ dbg_wvr8,
+ dbg_wvr9,
+ dbg_wvr10,
+ dbg_wvr11,
+ dbg_wvr12,
+ dbg_wvr13,
+ dbg_wvr14,
+ dbg_wvr15,
+
+ dbg_wcr0,
+ dbg_wcr1,
+ dbg_wcr2,
+ dbg_wcr3,
+ dbg_wcr4,
+ dbg_wcr5,
+ dbg_wcr6,
+ dbg_wcr7,
+ dbg_wcr8,
+ dbg_wcr9,
+ dbg_wcr10,
+ dbg_wcr11,
+ dbg_wcr12,
+ dbg_wcr13,
+ dbg_wcr14,
+ dbg_wcr15,
+
+ k_num_registers
+};
+
+static uint32_t g_contained_x0[] = {gpr_x0, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x1[] = {gpr_x1, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x2[] = {gpr_x2, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x3[] = {gpr_x3, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x4[] = {gpr_x4, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x5[] = {gpr_x5, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x6[] = {gpr_x6, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x7[] = {gpr_x7, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x8[] = {gpr_x8, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x9[] = {gpr_x9, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x10[] = {gpr_x10, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x11[] = {gpr_x11, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x12[] = {gpr_x12, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x13[] = {gpr_x13, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x14[] = {gpr_x14, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x15[] = {gpr_x15, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x16[] = {gpr_x16, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x17[] = {gpr_x17, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x18[] = {gpr_x18, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x19[] = {gpr_x19, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x20[] = {gpr_x20, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x21[] = {gpr_x21, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x22[] = {gpr_x22, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x23[] = {gpr_x23, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x24[] = {gpr_x24, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x25[] = {gpr_x25, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x26[] = {gpr_x26, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x27[] = {gpr_x27, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_x28[] = {gpr_x28, LLDB_INVALID_REGNUM};
+
+static uint32_t g_w0_invalidates[] = {gpr_x0, LLDB_INVALID_REGNUM};
+static uint32_t g_w1_invalidates[] = {gpr_x1, LLDB_INVALID_REGNUM};
+static uint32_t g_w2_invalidates[] = {gpr_x2, LLDB_INVALID_REGNUM};
+static uint32_t g_w3_invalidates[] = {gpr_x3, LLDB_INVALID_REGNUM};
+static uint32_t g_w4_invalidates[] = {gpr_x4, LLDB_INVALID_REGNUM};
+static uint32_t g_w5_invalidates[] = {gpr_x5, LLDB_INVALID_REGNUM};
+static uint32_t g_w6_invalidates[] = {gpr_x6, LLDB_INVALID_REGNUM};
+static uint32_t g_w7_invalidates[] = {gpr_x7, LLDB_INVALID_REGNUM};
+static uint32_t g_w8_invalidates[] = {gpr_x8, LLDB_INVALID_REGNUM};
+static uint32_t g_w9_invalidates[] = {gpr_x9, LLDB_INVALID_REGNUM};
+static uint32_t g_w10_invalidates[] = {gpr_x10, LLDB_INVALID_REGNUM};
+static uint32_t g_w11_invalidates[] = {gpr_x11, LLDB_INVALID_REGNUM};
+static uint32_t g_w12_invalidates[] = {gpr_x12, LLDB_INVALID_REGNUM};
+static uint32_t g_w13_invalidates[] = {gpr_x13, LLDB_INVALID_REGNUM};
+static uint32_t g_w14_invalidates[] = {gpr_x14, LLDB_INVALID_REGNUM};
+static uint32_t g_w15_invalidates[] = {gpr_x15, LLDB_INVALID_REGNUM};
+static uint32_t g_w16_invalidates[] = {gpr_x16, LLDB_INVALID_REGNUM};
+static uint32_t g_w17_invalidates[] = {gpr_x17, LLDB_INVALID_REGNUM};
+static uint32_t g_w18_invalidates[] = {gpr_x18, LLDB_INVALID_REGNUM};
+static uint32_t g_w19_invalidates[] = {gpr_x19, LLDB_INVALID_REGNUM};
+static uint32_t g_w20_invalidates[] = {gpr_x20, LLDB_INVALID_REGNUM};
+static uint32_t g_w21_invalidates[] = {gpr_x21, LLDB_INVALID_REGNUM};
+static uint32_t g_w22_invalidates[] = {gpr_x22, LLDB_INVALID_REGNUM};
+static uint32_t g_w23_invalidates[] = {gpr_x23, LLDB_INVALID_REGNUM};
+static uint32_t g_w24_invalidates[] = {gpr_x24, LLDB_INVALID_REGNUM};
+static uint32_t g_w25_invalidates[] = {gpr_x25, LLDB_INVALID_REGNUM};
+static uint32_t g_w26_invalidates[] = {gpr_x26, LLDB_INVALID_REGNUM};
+static uint32_t g_w27_invalidates[] = {gpr_x27, LLDB_INVALID_REGNUM};
+static uint32_t g_w28_invalidates[] = {gpr_x28, LLDB_INVALID_REGNUM};
+
+static uint32_t g_contained_v0[] = {fpu_v0, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v1[] = {fpu_v1, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v2[] = {fpu_v2, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v3[] = {fpu_v3, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v4[] = {fpu_v4, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v5[] = {fpu_v5, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v6[] = {fpu_v6, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v7[] = {fpu_v7, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v8[] = {fpu_v8, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v9[] = {fpu_v9, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v10[] = {fpu_v10, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v11[] = {fpu_v11, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v12[] = {fpu_v12, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v13[] = {fpu_v13, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v14[] = {fpu_v14, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v15[] = {fpu_v15, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v16[] = {fpu_v16, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v17[] = {fpu_v17, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v18[] = {fpu_v18, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v19[] = {fpu_v19, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v20[] = {fpu_v20, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v21[] = {fpu_v21, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v22[] = {fpu_v22, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v23[] = {fpu_v23, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v24[] = {fpu_v24, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v25[] = {fpu_v25, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v26[] = {fpu_v26, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v27[] = {fpu_v27, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v28[] = {fpu_v28, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v29[] = {fpu_v29, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v30[] = {fpu_v30, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_v31[] = {fpu_v31, LLDB_INVALID_REGNUM};
+
+static uint32_t g_s0_invalidates[] = {fpu_v0, fpu_d0, LLDB_INVALID_REGNUM};
+static uint32_t g_s1_invalidates[] = {fpu_v1, fpu_d1, LLDB_INVALID_REGNUM};
+static uint32_t g_s2_invalidates[] = {fpu_v2, fpu_d2, LLDB_INVALID_REGNUM};
+static uint32_t g_s3_invalidates[] = {fpu_v3, fpu_d3, LLDB_INVALID_REGNUM};
+static uint32_t g_s4_invalidates[] = {fpu_v4, fpu_d4, LLDB_INVALID_REGNUM};
+static uint32_t g_s5_invalidates[] = {fpu_v5, fpu_d5, LLDB_INVALID_REGNUM};
+static uint32_t g_s6_invalidates[] = {fpu_v6, fpu_d6, LLDB_INVALID_REGNUM};
+static uint32_t g_s7_invalidates[] = {fpu_v7, fpu_d7, LLDB_INVALID_REGNUM};
+static uint32_t g_s8_invalidates[] = {fpu_v8, fpu_d8, LLDB_INVALID_REGNUM};
+static uint32_t g_s9_invalidates[] = {fpu_v9, fpu_d9, LLDB_INVALID_REGNUM};
+static uint32_t g_s10_invalidates[] = {fpu_v10, fpu_d10, LLDB_INVALID_REGNUM};
+static uint32_t g_s11_invalidates[] = {fpu_v11, fpu_d11, LLDB_INVALID_REGNUM};
+static uint32_t g_s12_invalidates[] = {fpu_v12, fpu_d12, LLDB_INVALID_REGNUM};
+static uint32_t g_s13_invalidates[] = {fpu_v13, fpu_d13, LLDB_INVALID_REGNUM};
+static uint32_t g_s14_invalidates[] = {fpu_v14, fpu_d14, LLDB_INVALID_REGNUM};
+static uint32_t g_s15_invalidates[] = {fpu_v15, fpu_d15, LLDB_INVALID_REGNUM};
+static uint32_t g_s16_invalidates[] = {fpu_v16, fpu_d16, LLDB_INVALID_REGNUM};
+static uint32_t g_s17_invalidates[] = {fpu_v17, fpu_d17, LLDB_INVALID_REGNUM};
+static uint32_t g_s18_invalidates[] = {fpu_v18, fpu_d18, LLDB_INVALID_REGNUM};
+static uint32_t g_s19_invalidates[] = {fpu_v19, fpu_d19, LLDB_INVALID_REGNUM};
+static uint32_t g_s20_invalidates[] = {fpu_v20, fpu_d20, LLDB_INVALID_REGNUM};
+static uint32_t g_s21_invalidates[] = {fpu_v21, fpu_d21, LLDB_INVALID_REGNUM};
+static uint32_t g_s22_invalidates[] = {fpu_v22, fpu_d22, LLDB_INVALID_REGNUM};
+static uint32_t g_s23_invalidates[] = {fpu_v23, fpu_d23, LLDB_INVALID_REGNUM};
+static uint32_t g_s24_invalidates[] = {fpu_v24, fpu_d24, LLDB_INVALID_REGNUM};
+static uint32_t g_s25_invalidates[] = {fpu_v25, fpu_d25, LLDB_INVALID_REGNUM};
+static uint32_t g_s26_invalidates[] = {fpu_v26, fpu_d26, LLDB_INVALID_REGNUM};
+static uint32_t g_s27_invalidates[] = {fpu_v27, fpu_d27, LLDB_INVALID_REGNUM};
+static uint32_t g_s28_invalidates[] = {fpu_v28, fpu_d28, LLDB_INVALID_REGNUM};
+static uint32_t g_s29_invalidates[] = {fpu_v29, fpu_d29, LLDB_INVALID_REGNUM};
+static uint32_t g_s30_invalidates[] = {fpu_v30, fpu_d30, LLDB_INVALID_REGNUM};
+static uint32_t g_s31_invalidates[] = {fpu_v31, fpu_d31, LLDB_INVALID_REGNUM};
+
+static uint32_t g_d0_invalidates[] = {fpu_v0, fpu_s0, LLDB_INVALID_REGNUM};
+static uint32_t g_d1_invalidates[] = {fpu_v1, fpu_s1, LLDB_INVALID_REGNUM};
+static uint32_t g_d2_invalidates[] = {fpu_v2, fpu_s2, LLDB_INVALID_REGNUM};
+static uint32_t g_d3_invalidates[] = {fpu_v3, fpu_s3, LLDB_INVALID_REGNUM};
+static uint32_t g_d4_invalidates[] = {fpu_v4, fpu_s4, LLDB_INVALID_REGNUM};
+static uint32_t g_d5_invalidates[] = {fpu_v5, fpu_s5, LLDB_INVALID_REGNUM};
+static uint32_t g_d6_invalidates[] = {fpu_v6, fpu_s6, LLDB_INVALID_REGNUM};
+static uint32_t g_d7_invalidates[] = {fpu_v7, fpu_s7, LLDB_INVALID_REGNUM};
+static uint32_t g_d8_invalidates[] = {fpu_v8, fpu_s8, LLDB_INVALID_REGNUM};
+static uint32_t g_d9_invalidates[] = {fpu_v9, fpu_s9, LLDB_INVALID_REGNUM};
+static uint32_t g_d10_invalidates[] = {fpu_v10, fpu_s10, LLDB_INVALID_REGNUM};
+static uint32_t g_d11_invalidates[] = {fpu_v11, fpu_s11, LLDB_INVALID_REGNUM};
+static uint32_t g_d12_invalidates[] = {fpu_v12, fpu_s12, LLDB_INVALID_REGNUM};
+static uint32_t g_d13_invalidates[] = {fpu_v13, fpu_s13, LLDB_INVALID_REGNUM};
+static uint32_t g_d14_invalidates[] = {fpu_v14, fpu_s14, LLDB_INVALID_REGNUM};
+static uint32_t g_d15_invalidates[] = {fpu_v15, fpu_s15, LLDB_INVALID_REGNUM};
+static uint32_t g_d16_invalidates[] = {fpu_v16, fpu_s16, LLDB_INVALID_REGNUM};
+static uint32_t g_d17_invalidates[] = {fpu_v17, fpu_s17, LLDB_INVALID_REGNUM};
+static uint32_t g_d18_invalidates[] = {fpu_v18, fpu_s18, LLDB_INVALID_REGNUM};
+static uint32_t g_d19_invalidates[] = {fpu_v19, fpu_s19, LLDB_INVALID_REGNUM};
+static uint32_t g_d20_invalidates[] = {fpu_v20, fpu_s20, LLDB_INVALID_REGNUM};
+static uint32_t g_d21_invalidates[] = {fpu_v21, fpu_s21, LLDB_INVALID_REGNUM};
+static uint32_t g_d22_invalidates[] = {fpu_v22, fpu_s22, LLDB_INVALID_REGNUM};
+static uint32_t g_d23_invalidates[] = {fpu_v23, fpu_s23, LLDB_INVALID_REGNUM};
+static uint32_t g_d24_invalidates[] = {fpu_v24, fpu_s24, LLDB_INVALID_REGNUM};
+static uint32_t g_d25_invalidates[] = {fpu_v25, fpu_s25, LLDB_INVALID_REGNUM};
+static uint32_t g_d26_invalidates[] = {fpu_v26, fpu_s26, LLDB_INVALID_REGNUM};
+static uint32_t g_d27_invalidates[] = {fpu_v27, fpu_s27, LLDB_INVALID_REGNUM};
+static uint32_t g_d28_invalidates[] = {fpu_v28, fpu_s28, LLDB_INVALID_REGNUM};
+static uint32_t g_d29_invalidates[] = {fpu_v29, fpu_s29, LLDB_INVALID_REGNUM};
+static uint32_t g_d30_invalidates[] = {fpu_v30, fpu_s30, LLDB_INVALID_REGNUM};
+static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM};
+
+// Generates register kinds array with DWARF, EH frame and generic kind
+#define MISC_KIND(reg, type, generic_kind) \
+ { \
+ arm64_ehframe::reg, arm64_dwarf::reg, generic_kind, LLDB_INVALID_REGNUM, \
+ type##_##reg \
+ }
+
+// Generates register kinds array for registers with only lldb kind
+#define LLDB_KIND(lldb_kind) \
+ { \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_kind \
+ }
+
+// Generates register kinds array for registers with only lldb kind
+#define KIND_ALL_INVALID \
+ { \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM \
+ }
+
+// Generates register kinds array for vector registers
+#define GPR64_KIND(reg, generic_kind) MISC_KIND(reg, gpr, generic_kind)
+#define VREG_KIND(reg) MISC_KIND(reg, fpu, LLDB_INVALID_REGNUM)
+#define MISC_GPR_KIND(lldb_kind) MISC_KIND(cpsr, gpr, LLDB_REGNUM_GENERIC_FLAGS)
+#define MISC_FPU_KIND(lldb_kind) LLDB_KIND(lldb_kind)
+#define MISC_EXC_KIND(lldb_kind) LLDB_KIND(lldb_kind)
+
+// clang-format off
+
+// Defines a 64-bit general purpose register
+#define DEFINE_GPR64(reg, generic_kind) \
+ { \
+ #reg, nullptr, 8, GPR_OFFSET(gpr_##reg), lldb::eEncodingUint, \
+ lldb::eFormatHex, GPR64_KIND(reg, generic_kind), nullptr, nullptr, \
+ nullptr, \
+ }
+
+// Defines a 64-bit general purpose register
+#define DEFINE_GPR64_ALT(reg, alt, generic_kind) \
+ { \
+ #reg, #alt, 8, GPR_OFFSET(gpr_##reg), lldb::eEncodingUint, \
+ lldb::eFormatHex, GPR64_KIND(reg, generic_kind), nullptr, nullptr, \
+ nullptr, \
+ }
+
+// Defines a 32-bit general purpose pseudo register
+#define DEFINE_GPR32(wreg, xreg) \
+ { \
+ #wreg, nullptr, 4, \
+ GPR_OFFSET(gpr_##xreg) + GPR_W_PSEUDO_REG_ENDIAN_OFFSET, \
+ lldb::eEncodingUint, lldb::eFormatHex, LLDB_KIND(gpr_##wreg), \
+ g_contained_##xreg, g_##wreg##_invalidates, nullptr, \
+ }
+
+// Defines a vector register with 16-byte size
+#define DEFINE_VREG(reg) \
+ { \
+ #reg, nullptr, 16, FPU_OFFSET(fpu_##reg - fpu_v0), lldb::eEncodingVector, \
+ lldb::eFormatVectorOfUInt8, VREG_KIND(reg), nullptr, nullptr, nullptr, \
+ }
+
+// Defines S and D pseudo registers mapping over corresponding vector register
+#define DEFINE_FPU_PSEUDO(reg, size, offset, vreg) \
+ { \
+ #reg, nullptr, size, FPU_OFFSET(fpu_##vreg - fpu_v0) + offset, \
+ lldb::eEncodingIEEE754, lldb::eFormatFloat, LLDB_KIND(fpu_##reg), \
+ g_contained_##vreg, g_##reg##_invalidates, nullptr, \
+ }
+
+// Defines miscellaneous status and control registers like cpsr, fpsr etc
+#define DEFINE_MISC_REGS(reg, size, TYPE, lldb_kind) \
+ { \
+ #reg, nullptr, size, TYPE##_OFFSET_NAME(reg), lldb::eEncodingUint, \
+ lldb::eFormatHex, MISC_##TYPE##_KIND(lldb_kind), nullptr, nullptr, \
+ nullptr, \
+ }
+
+// Defines pointer authentication mask registers
+#define DEFINE_EXTENSION_REG(reg) \
+ { \
+ #reg, nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \
+ KIND_ALL_INVALID, nullptr, nullptr, nullptr, \
+ }
+
+static lldb_private::RegisterInfo g_register_infos_arm64_le[] = {
+ // DEFINE_GPR64(name, GENERIC KIND)
+ DEFINE_GPR64(x0, LLDB_REGNUM_GENERIC_ARG1),
+ DEFINE_GPR64(x1, LLDB_REGNUM_GENERIC_ARG2),
+ DEFINE_GPR64(x2, LLDB_REGNUM_GENERIC_ARG3),
+ DEFINE_GPR64(x3, LLDB_REGNUM_GENERIC_ARG4),
+ DEFINE_GPR64(x4, LLDB_REGNUM_GENERIC_ARG5),
+ DEFINE_GPR64(x5, LLDB_REGNUM_GENERIC_ARG6),
+ DEFINE_GPR64(x6, LLDB_REGNUM_GENERIC_ARG7),
+ DEFINE_GPR64(x7, LLDB_REGNUM_GENERIC_ARG8),
+ DEFINE_GPR64(x8, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x9, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x10, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x11, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x12, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x13, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x14, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x15, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x16, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x17, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x18, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x19, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x20, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x21, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x22, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x23, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x24, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x25, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x26, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x27, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x28, LLDB_INVALID_REGNUM),
+ // DEFINE_GPR64(name, GENERIC KIND)
+ DEFINE_GPR64_ALT(fp, x29, LLDB_REGNUM_GENERIC_FP),
+ DEFINE_GPR64_ALT(lr, x30, LLDB_REGNUM_GENERIC_RA),
+ DEFINE_GPR64_ALT(sp, x31, LLDB_REGNUM_GENERIC_SP),
+ DEFINE_GPR64(pc, LLDB_REGNUM_GENERIC_PC),
+
+ // DEFINE_MISC_REGS(name, size, TYPE, lldb kind)
+ DEFINE_MISC_REGS(cpsr, 4, GPR, gpr_cpsr),
+
+ // DEFINE_GPR32(name, parent name)
+ DEFINE_GPR32(w0, x0),
+ DEFINE_GPR32(w1, x1),
+ DEFINE_GPR32(w2, x2),
+ DEFINE_GPR32(w3, x3),
+ DEFINE_GPR32(w4, x4),
+ DEFINE_GPR32(w5, x5),
+ DEFINE_GPR32(w6, x6),
+ DEFINE_GPR32(w7, x7),
+ DEFINE_GPR32(w8, x8),
+ DEFINE_GPR32(w9, x9),
+ DEFINE_GPR32(w10, x10),
+ DEFINE_GPR32(w11, x11),
+ DEFINE_GPR32(w12, x12),
+ DEFINE_GPR32(w13, x13),
+ DEFINE_GPR32(w14, x14),
+ DEFINE_GPR32(w15, x15),
+ DEFINE_GPR32(w16, x16),
+ DEFINE_GPR32(w17, x17),
+ DEFINE_GPR32(w18, x18),
+ DEFINE_GPR32(w19, x19),
+ DEFINE_GPR32(w20, x20),
+ DEFINE_GPR32(w21, x21),
+ DEFINE_GPR32(w22, x22),
+ DEFINE_GPR32(w23, x23),
+ DEFINE_GPR32(w24, x24),
+ DEFINE_GPR32(w25, x25),
+ DEFINE_GPR32(w26, x26),
+ DEFINE_GPR32(w27, x27),
+ DEFINE_GPR32(w28, x28),
+
+ // DEFINE_VREG(name)
+ DEFINE_VREG(v0),
+ DEFINE_VREG(v1),
+ DEFINE_VREG(v2),
+ DEFINE_VREG(v3),
+ DEFINE_VREG(v4),
+ DEFINE_VREG(v5),
+ DEFINE_VREG(v6),
+ DEFINE_VREG(v7),
+ DEFINE_VREG(v8),
+ DEFINE_VREG(v9),
+ DEFINE_VREG(v10),
+ DEFINE_VREG(v11),
+ DEFINE_VREG(v12),
+ DEFINE_VREG(v13),
+ DEFINE_VREG(v14),
+ DEFINE_VREG(v15),
+ DEFINE_VREG(v16),
+ DEFINE_VREG(v17),
+ DEFINE_VREG(v18),
+ DEFINE_VREG(v19),
+ DEFINE_VREG(v20),
+ DEFINE_VREG(v21),
+ DEFINE_VREG(v22),
+ DEFINE_VREG(v23),
+ DEFINE_VREG(v24),
+ DEFINE_VREG(v25),
+ DEFINE_VREG(v26),
+ DEFINE_VREG(v27),
+ DEFINE_VREG(v28),
+ DEFINE_VREG(v29),
+ DEFINE_VREG(v30),
+ DEFINE_VREG(v31),
+
+ // DEFINE_FPU_PSEUDO(name, size, ENDIAN OFFSET, parent register)
+ DEFINE_FPU_PSEUDO(s0, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v0),
+ DEFINE_FPU_PSEUDO(s1, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v1),
+ DEFINE_FPU_PSEUDO(s2, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v2),
+ DEFINE_FPU_PSEUDO(s3, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v3),
+ DEFINE_FPU_PSEUDO(s4, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v4),
+ DEFINE_FPU_PSEUDO(s5, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v5),
+ DEFINE_FPU_PSEUDO(s6, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v6),
+ DEFINE_FPU_PSEUDO(s7, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v7),
+ DEFINE_FPU_PSEUDO(s8, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v8),
+ DEFINE_FPU_PSEUDO(s9, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v9),
+ DEFINE_FPU_PSEUDO(s10, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v10),
+ DEFINE_FPU_PSEUDO(s11, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v11),
+ DEFINE_FPU_PSEUDO(s12, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v12),
+ DEFINE_FPU_PSEUDO(s13, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v13),
+ DEFINE_FPU_PSEUDO(s14, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v14),
+ DEFINE_FPU_PSEUDO(s15, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v15),
+ DEFINE_FPU_PSEUDO(s16, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v16),
+ DEFINE_FPU_PSEUDO(s17, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v17),
+ DEFINE_FPU_PSEUDO(s18, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v18),
+ DEFINE_FPU_PSEUDO(s19, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v19),
+ DEFINE_FPU_PSEUDO(s20, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v20),
+ DEFINE_FPU_PSEUDO(s21, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v21),
+ DEFINE_FPU_PSEUDO(s22, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v22),
+ DEFINE_FPU_PSEUDO(s23, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v23),
+ DEFINE_FPU_PSEUDO(s24, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v24),
+ DEFINE_FPU_PSEUDO(s25, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v25),
+ DEFINE_FPU_PSEUDO(s26, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v26),
+ DEFINE_FPU_PSEUDO(s27, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v27),
+ DEFINE_FPU_PSEUDO(s28, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v28),
+ DEFINE_FPU_PSEUDO(s29, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v29),
+ DEFINE_FPU_PSEUDO(s30, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v30),
+ DEFINE_FPU_PSEUDO(s31, 4, FPU_S_PSEUDO_REG_ENDIAN_OFFSET, v31),
+
+ DEFINE_FPU_PSEUDO(d0, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v0),
+ DEFINE_FPU_PSEUDO(d1, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v1),
+ DEFINE_FPU_PSEUDO(d2, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v2),
+ DEFINE_FPU_PSEUDO(d3, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v3),
+ DEFINE_FPU_PSEUDO(d4, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v4),
+ DEFINE_FPU_PSEUDO(d5, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v5),
+ DEFINE_FPU_PSEUDO(d6, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v6),
+ DEFINE_FPU_PSEUDO(d7, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v7),
+ DEFINE_FPU_PSEUDO(d8, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v8),
+ DEFINE_FPU_PSEUDO(d9, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v9),
+ DEFINE_FPU_PSEUDO(d10, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v10),
+ DEFINE_FPU_PSEUDO(d11, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v11),
+ DEFINE_FPU_PSEUDO(d12, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v12),
+ DEFINE_FPU_PSEUDO(d13, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v13),
+ DEFINE_FPU_PSEUDO(d14, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v14),
+ DEFINE_FPU_PSEUDO(d15, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v15),
+ DEFINE_FPU_PSEUDO(d16, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v16),
+ DEFINE_FPU_PSEUDO(d17, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v17),
+ DEFINE_FPU_PSEUDO(d18, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v18),
+ DEFINE_FPU_PSEUDO(d19, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v19),
+ DEFINE_FPU_PSEUDO(d20, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v20),
+ DEFINE_FPU_PSEUDO(d21, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v21),
+ DEFINE_FPU_PSEUDO(d22, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v22),
+ DEFINE_FPU_PSEUDO(d23, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v23),
+ DEFINE_FPU_PSEUDO(d24, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v24),
+ DEFINE_FPU_PSEUDO(d25, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v25),
+ DEFINE_FPU_PSEUDO(d26, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v26),
+ DEFINE_FPU_PSEUDO(d27, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v27),
+ DEFINE_FPU_PSEUDO(d28, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v28),
+ DEFINE_FPU_PSEUDO(d29, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v29),
+ DEFINE_FPU_PSEUDO(d30, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v30),
+ DEFINE_FPU_PSEUDO(d31, 8, FPU_D_PSEUDO_REG_ENDIAN_OFFSET, v31),
+
+ // DEFINE_MISC_REGS(name, size, TYPE, lldb kind)
+ DEFINE_MISC_REGS(fpsr, 4, FPU, fpu_fpsr),
+ DEFINE_MISC_REGS(fpcr, 4, FPU, fpu_fpcr),
+ DEFINE_MISC_REGS(far, 8, EXC, exc_far),
+ DEFINE_MISC_REGS(esr, 4, EXC, exc_esr),
+ DEFINE_MISC_REGS(exception, 4, EXC, exc_exception),
+
+ {DEFINE_DBG(bvr, 0)},
+ {DEFINE_DBG(bvr, 1)},
+ {DEFINE_DBG(bvr, 2)},
+ {DEFINE_DBG(bvr, 3)},
+ {DEFINE_DBG(bvr, 4)},
+ {DEFINE_DBG(bvr, 5)},
+ {DEFINE_DBG(bvr, 6)},
+ {DEFINE_DBG(bvr, 7)},
+ {DEFINE_DBG(bvr, 8)},
+ {DEFINE_DBG(bvr, 9)},
+ {DEFINE_DBG(bvr, 10)},
+ {DEFINE_DBG(bvr, 11)},
+ {DEFINE_DBG(bvr, 12)},
+ {DEFINE_DBG(bvr, 13)},
+ {DEFINE_DBG(bvr, 14)},
+ {DEFINE_DBG(bvr, 15)},
+
+ {DEFINE_DBG(bcr, 0)},
+ {DEFINE_DBG(bcr, 1)},
+ {DEFINE_DBG(bcr, 2)},
+ {DEFINE_DBG(bcr, 3)},
+ {DEFINE_DBG(bcr, 4)},
+ {DEFINE_DBG(bcr, 5)},
+ {DEFINE_DBG(bcr, 6)},
+ {DEFINE_DBG(bcr, 7)},
+ {DEFINE_DBG(bcr, 8)},
+ {DEFINE_DBG(bcr, 9)},
+ {DEFINE_DBG(bcr, 10)},
+ {DEFINE_DBG(bcr, 11)},
+ {DEFINE_DBG(bcr, 12)},
+ {DEFINE_DBG(bcr, 13)},
+ {DEFINE_DBG(bcr, 14)},
+ {DEFINE_DBG(bcr, 15)},
+
+ {DEFINE_DBG(wvr, 0)},
+ {DEFINE_DBG(wvr, 1)},
+ {DEFINE_DBG(wvr, 2)},
+ {DEFINE_DBG(wvr, 3)},
+ {DEFINE_DBG(wvr, 4)},
+ {DEFINE_DBG(wvr, 5)},
+ {DEFINE_DBG(wvr, 6)},
+ {DEFINE_DBG(wvr, 7)},
+ {DEFINE_DBG(wvr, 8)},
+ {DEFINE_DBG(wvr, 9)},
+ {DEFINE_DBG(wvr, 10)},
+ {DEFINE_DBG(wvr, 11)},
+ {DEFINE_DBG(wvr, 12)},
+ {DEFINE_DBG(wvr, 13)},
+ {DEFINE_DBG(wvr, 14)},
+ {DEFINE_DBG(wvr, 15)},
+
+ {DEFINE_DBG(wcr, 0)},
+ {DEFINE_DBG(wcr, 1)},
+ {DEFINE_DBG(wcr, 2)},
+ {DEFINE_DBG(wcr, 3)},
+ {DEFINE_DBG(wcr, 4)},
+ {DEFINE_DBG(wcr, 5)},
+ {DEFINE_DBG(wcr, 6)},
+ {DEFINE_DBG(wcr, 7)},
+ {DEFINE_DBG(wcr, 8)},
+ {DEFINE_DBG(wcr, 9)},
+ {DEFINE_DBG(wcr, 10)},
+ {DEFINE_DBG(wcr, 11)},
+ {DEFINE_DBG(wcr, 12)},
+ {DEFINE_DBG(wcr, 13)},
+ {DEFINE_DBG(wcr, 14)},
+ {DEFINE_DBG(wcr, 15)}
+};
+// clang-format on
+
+#endif // DECLARE_REGISTER_INFOS_ARM64_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h
new file mode 100644
index 000000000000..283c4c17e760
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h
@@ -0,0 +1,573 @@
+//===-- RegisterInfos_arm64_sve.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+enum {
+ sve_vg = exc_far,
+
+ sve_z0,
+ sve_z1,
+ sve_z2,
+ sve_z3,
+ sve_z4,
+ sve_z5,
+ sve_z6,
+ sve_z7,
+ sve_z8,
+ sve_z9,
+ sve_z10,
+ sve_z11,
+ sve_z12,
+ sve_z13,
+ sve_z14,
+ sve_z15,
+ sve_z16,
+ sve_z17,
+ sve_z18,
+ sve_z19,
+ sve_z20,
+ sve_z21,
+ sve_z22,
+ sve_z23,
+ sve_z24,
+ sve_z25,
+ sve_z26,
+ sve_z27,
+ sve_z28,
+ sve_z29,
+ sve_z30,
+ sve_z31,
+
+ sve_p0,
+ sve_p1,
+ sve_p2,
+ sve_p3,
+ sve_p4,
+ sve_p5,
+ sve_p6,
+ sve_p7,
+ sve_p8,
+ sve_p9,
+ sve_p10,
+ sve_p11,
+ sve_p12,
+ sve_p13,
+ sve_p14,
+ sve_p15,
+
+ sve_ffr,
+};
+
+#ifndef SVE_OFFSET_VG
+#error SVE_OFFSET_VG must be defined before including this header file
+#endif
+
+static uint32_t g_sve_s0_invalidates[] = {sve_z0, fpu_v0, fpu_d0,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s1_invalidates[] = {sve_z1, fpu_v1, fpu_d1,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s2_invalidates[] = {sve_z2, fpu_v2, fpu_d2,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s3_invalidates[] = {sve_z3, fpu_v3, fpu_d3,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s4_invalidates[] = {sve_z4, fpu_v4, fpu_d4,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s5_invalidates[] = {sve_z5, fpu_v5, fpu_d5,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s6_invalidates[] = {sve_z6, fpu_v6, fpu_d6,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s7_invalidates[] = {sve_z7, fpu_v7, fpu_d7,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s8_invalidates[] = {sve_z8, fpu_v8, fpu_d8,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s9_invalidates[] = {sve_z9, fpu_v9, fpu_d9,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s10_invalidates[] = {sve_z10, fpu_v10, fpu_d10,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s11_invalidates[] = {sve_z11, fpu_v11, fpu_d11,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s12_invalidates[] = {sve_z12, fpu_v12, fpu_d12,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s13_invalidates[] = {sve_z13, fpu_v13, fpu_d13,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s14_invalidates[] = {sve_z14, fpu_v14, fpu_d14,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s15_invalidates[] = {sve_z15, fpu_v15, fpu_d15,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s16_invalidates[] = {sve_z16, fpu_v16, fpu_d16,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s17_invalidates[] = {sve_z17, fpu_v17, fpu_d17,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s18_invalidates[] = {sve_z18, fpu_v18, fpu_d18,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s19_invalidates[] = {sve_z19, fpu_v19, fpu_d19,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s20_invalidates[] = {sve_z20, fpu_v20, fpu_d20,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s21_invalidates[] = {sve_z21, fpu_v21, fpu_d21,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s22_invalidates[] = {sve_z22, fpu_v22, fpu_d22,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s23_invalidates[] = {sve_z23, fpu_v23, fpu_d23,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s24_invalidates[] = {sve_z24, fpu_v24, fpu_d24,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s25_invalidates[] = {sve_z25, fpu_v25, fpu_d25,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s26_invalidates[] = {sve_z26, fpu_v26, fpu_d26,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s27_invalidates[] = {sve_z27, fpu_v27, fpu_d27,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s28_invalidates[] = {sve_z28, fpu_v28, fpu_d28,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s29_invalidates[] = {sve_z29, fpu_v29, fpu_d29,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s30_invalidates[] = {sve_z30, fpu_v30, fpu_d30,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s31_invalidates[] = {sve_z31, fpu_v31, fpu_d31,
+ LLDB_INVALID_REGNUM};
+
+static uint32_t g_sve_d0_invalidates[] = {sve_z0, fpu_v0, fpu_s0,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d1_invalidates[] = {sve_z1, fpu_v1, fpu_s1,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d2_invalidates[] = {sve_z2, fpu_v2, fpu_s2,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d3_invalidates[] = {sve_z3, fpu_v3, fpu_s3,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d4_invalidates[] = {sve_z4, fpu_v4, fpu_s4,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d5_invalidates[] = {sve_z5, fpu_v5, fpu_s5,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d6_invalidates[] = {sve_z6, fpu_v6, fpu_s6,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d7_invalidates[] = {sve_z7, fpu_v7, fpu_s7,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d8_invalidates[] = {sve_z8, fpu_v8, fpu_s8,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d9_invalidates[] = {sve_z9, fpu_v9, fpu_s9,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d10_invalidates[] = {sve_z10, fpu_v10, fpu_s10,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d11_invalidates[] = {sve_z11, fpu_v11, fpu_s11,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d12_invalidates[] = {sve_z12, fpu_v12, fpu_s12,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d13_invalidates[] = {sve_z13, fpu_v13, fpu_s13,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d14_invalidates[] = {sve_z14, fpu_v14, fpu_s14,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d15_invalidates[] = {sve_z15, fpu_v15, fpu_s15,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d16_invalidates[] = {sve_z16, fpu_v16, fpu_s16,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d17_invalidates[] = {sve_z17, fpu_v17, fpu_s17,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d18_invalidates[] = {sve_z18, fpu_v18, fpu_s18,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d19_invalidates[] = {sve_z19, fpu_v19, fpu_s19,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d20_invalidates[] = {sve_z20, fpu_v20, fpu_s20,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d21_invalidates[] = {sve_z21, fpu_v21, fpu_s21,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d22_invalidates[] = {sve_z22, fpu_v22, fpu_s22,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d23_invalidates[] = {sve_z23, fpu_v23, fpu_s23,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d24_invalidates[] = {sve_z24, fpu_v24, fpu_s24,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d25_invalidates[] = {sve_z25, fpu_v25, fpu_s25,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d26_invalidates[] = {sve_z26, fpu_v26, fpu_s26,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d27_invalidates[] = {sve_z27, fpu_v27, fpu_s27,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d28_invalidates[] = {sve_z28, fpu_v28, fpu_s28,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d29_invalidates[] = {sve_z29, fpu_v29, fpu_s29,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d30_invalidates[] = {sve_z30, fpu_v30, fpu_s30,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d31_invalidates[] = {sve_z31, fpu_v31, fpu_s31,
+ LLDB_INVALID_REGNUM};
+
+static uint32_t g_sve_v0_invalidates[] = {sve_z0, fpu_d0, fpu_s0,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v1_invalidates[] = {sve_z1, fpu_d1, fpu_s1,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v2_invalidates[] = {sve_z2, fpu_d2, fpu_s2,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v3_invalidates[] = {sve_z3, fpu_d3, fpu_s3,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v4_invalidates[] = {sve_z4, fpu_d4, fpu_s4,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v5_invalidates[] = {sve_z5, fpu_d5, fpu_s5,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v6_invalidates[] = {sve_z6, fpu_d6, fpu_s6,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v7_invalidates[] = {sve_z7, fpu_d7, fpu_s7,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v8_invalidates[] = {sve_z8, fpu_d8, fpu_s8,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v9_invalidates[] = {sve_z9, fpu_d9, fpu_s9,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v10_invalidates[] = {sve_z10, fpu_d10, fpu_s10,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v11_invalidates[] = {sve_z11, fpu_d11, fpu_s11,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v12_invalidates[] = {sve_z12, fpu_d12, fpu_s12,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v13_invalidates[] = {sve_z13, fpu_d13, fpu_s13,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v14_invalidates[] = {sve_z14, fpu_d14, fpu_s14,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v15_invalidates[] = {sve_z15, fpu_d15, fpu_s15,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v16_invalidates[] = {sve_z16, fpu_d16, fpu_s16,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v17_invalidates[] = {sve_z17, fpu_d17, fpu_s17,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v18_invalidates[] = {sve_z18, fpu_d18, fpu_s18,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v19_invalidates[] = {sve_z19, fpu_d19, fpu_s19,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v20_invalidates[] = {sve_z20, fpu_d20, fpu_s20,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v21_invalidates[] = {sve_z21, fpu_d21, fpu_s21,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v22_invalidates[] = {sve_z22, fpu_d22, fpu_s22,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v23_invalidates[] = {sve_z23, fpu_d23, fpu_s23,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v24_invalidates[] = {sve_z24, fpu_d24, fpu_s24,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v25_invalidates[] = {sve_z25, fpu_d25, fpu_s25,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v26_invalidates[] = {sve_z26, fpu_d26, fpu_s26,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v27_invalidates[] = {sve_z27, fpu_d27, fpu_s27,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v28_invalidates[] = {sve_z28, fpu_d28, fpu_s28,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v29_invalidates[] = {sve_z29, fpu_d29, fpu_s29,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v30_invalidates[] = {sve_z30, fpu_d30, fpu_s30,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v31_invalidates[] = {sve_z31, fpu_d31, fpu_s31,
+ LLDB_INVALID_REGNUM};
+
+static uint32_t g_contained_z0[] = {sve_z0, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z1[] = {sve_z1, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z2[] = {sve_z2, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z3[] = {sve_z3, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z4[] = {sve_z4, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z5[] = {sve_z5, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z6[] = {sve_z6, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z7[] = {sve_z7, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z8[] = {sve_z8, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z9[] = {sve_z9, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z10[] = {sve_z10, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z11[] = {sve_z11, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z12[] = {sve_z12, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z13[] = {sve_z13, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z14[] = {sve_z14, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z15[] = {sve_z15, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z16[] = {sve_z16, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z17[] = {sve_z17, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z18[] = {sve_z18, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z19[] = {sve_z19, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z20[] = {sve_z20, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z21[] = {sve_z21, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z22[] = {sve_z22, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z23[] = {sve_z23, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z24[] = {sve_z24, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z25[] = {sve_z25, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z26[] = {sve_z26, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z27[] = {sve_z27, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z28[] = {sve_z28, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z29[] = {sve_z29, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z30[] = {sve_z30, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z31[] = {sve_z31, LLDB_INVALID_REGNUM};
+
+#define VG_OFFSET_NAME(reg) SVE_OFFSET_VG
+
+#define SVE_REG_KIND(reg) MISC_KIND(reg, sve, LLDB_INVALID_REGNUM)
+#define MISC_VG_KIND(lldb_kind) MISC_KIND(vg, sve, LLDB_INVALID_REGNUM)
+
+// Default offset SVE Z registers and all corresponding pseudo registers
+// ( S, D and V registers) is zero and will be configured during execution.
+
+// clang-format off
+
+// Defines sve pseudo vector (V) register with 16-byte size
+#define DEFINE_VREG_SVE(vreg, zreg) \
+ { \
+ #vreg, nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \
+ VREG_KIND(vreg), g_contained_##zreg, g_sve_##vreg##_invalidates, \
+ nullptr, \
+ }
+
+// Defines S and D pseudo registers mapping over corresponding vector register
+#define DEFINE_FPU_PSEUDO_SVE(reg, size, zreg) \
+ { \
+ #reg, nullptr, size, 0, lldb::eEncodingIEEE754, lldb::eFormatFloat, \
+ LLDB_KIND(fpu_##reg), g_contained_##zreg, g_sve_##reg##_invalidates, \
+ nullptr, \
+ }
+
+// Defines a Z vector register with 16-byte default size
+#define DEFINE_ZREG(reg) \
+ { \
+ #reg, nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \
+ SVE_REG_KIND(reg), nullptr, nullptr, nullptr, \
+ }
+
+// Defines a P vector register with 2-byte default size
+#define DEFINE_PREG(reg) \
+ { \
+ #reg, nullptr, 2, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \
+ SVE_REG_KIND(reg), nullptr, nullptr, nullptr, \
+ }
+
+static lldb_private::RegisterInfo g_register_infos_arm64_sve_le[] = {
+ // DEFINE_GPR64(name, GENERIC KIND)
+ DEFINE_GPR64(x0, LLDB_REGNUM_GENERIC_ARG1),
+ DEFINE_GPR64(x1, LLDB_REGNUM_GENERIC_ARG2),
+ DEFINE_GPR64(x2, LLDB_REGNUM_GENERIC_ARG3),
+ DEFINE_GPR64(x3, LLDB_REGNUM_GENERIC_ARG4),
+ DEFINE_GPR64(x4, LLDB_REGNUM_GENERIC_ARG5),
+ DEFINE_GPR64(x5, LLDB_REGNUM_GENERIC_ARG6),
+ DEFINE_GPR64(x6, LLDB_REGNUM_GENERIC_ARG7),
+ DEFINE_GPR64(x7, LLDB_REGNUM_GENERIC_ARG8),
+ DEFINE_GPR64(x8, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x9, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x10, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x11, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x12, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x13, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x14, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x15, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x16, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x17, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x18, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x19, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x20, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x21, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x22, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x23, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x24, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x25, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x26, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x27, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x28, LLDB_INVALID_REGNUM),
+ // DEFINE_GPR64(name, GENERIC KIND)
+ DEFINE_GPR64_ALT(fp, x29, LLDB_REGNUM_GENERIC_FP),
+ DEFINE_GPR64_ALT(lr, x30, LLDB_REGNUM_GENERIC_RA),
+ DEFINE_GPR64_ALT(sp, x31, LLDB_REGNUM_GENERIC_SP),
+ DEFINE_GPR64(pc, LLDB_REGNUM_GENERIC_PC),
+
+ // DEFINE_MISC_REGS(name, size, TYPE, lldb kind)
+ DEFINE_MISC_REGS(cpsr, 4, GPR, gpr_cpsr),
+
+ // DEFINE_GPR32(name, parent name)
+ DEFINE_GPR32(w0, x0),
+ DEFINE_GPR32(w1, x1),
+ DEFINE_GPR32(w2, x2),
+ DEFINE_GPR32(w3, x3),
+ DEFINE_GPR32(w4, x4),
+ DEFINE_GPR32(w5, x5),
+ DEFINE_GPR32(w6, x6),
+ DEFINE_GPR32(w7, x7),
+ DEFINE_GPR32(w8, x8),
+ DEFINE_GPR32(w9, x9),
+ DEFINE_GPR32(w10, x10),
+ DEFINE_GPR32(w11, x11),
+ DEFINE_GPR32(w12, x12),
+ DEFINE_GPR32(w13, x13),
+ DEFINE_GPR32(w14, x14),
+ DEFINE_GPR32(w15, x15),
+ DEFINE_GPR32(w16, x16),
+ DEFINE_GPR32(w17, x17),
+ DEFINE_GPR32(w18, x18),
+ DEFINE_GPR32(w19, x19),
+ DEFINE_GPR32(w20, x20),
+ DEFINE_GPR32(w21, x21),
+ DEFINE_GPR32(w22, x22),
+ DEFINE_GPR32(w23, x23),
+ DEFINE_GPR32(w24, x24),
+ DEFINE_GPR32(w25, x25),
+ DEFINE_GPR32(w26, x26),
+ DEFINE_GPR32(w27, x27),
+ DEFINE_GPR32(w28, x28),
+
+ // DEFINE_VREG_SVE(v register, z register)
+ DEFINE_VREG_SVE(v0, z0),
+ DEFINE_VREG_SVE(v1, z1),
+ DEFINE_VREG_SVE(v2, z2),
+ DEFINE_VREG_SVE(v3, z3),
+ DEFINE_VREG_SVE(v4, z4),
+ DEFINE_VREG_SVE(v5, z5),
+ DEFINE_VREG_SVE(v6, z6),
+ DEFINE_VREG_SVE(v7, z7),
+ DEFINE_VREG_SVE(v8, z8),
+ DEFINE_VREG_SVE(v9, z9),
+ DEFINE_VREG_SVE(v10, z10),
+ DEFINE_VREG_SVE(v11, z11),
+ DEFINE_VREG_SVE(v12, z12),
+ DEFINE_VREG_SVE(v13, z13),
+ DEFINE_VREG_SVE(v14, z14),
+ DEFINE_VREG_SVE(v15, z15),
+ DEFINE_VREG_SVE(v16, z16),
+ DEFINE_VREG_SVE(v17, z17),
+ DEFINE_VREG_SVE(v18, z18),
+ DEFINE_VREG_SVE(v19, z19),
+ DEFINE_VREG_SVE(v20, z20),
+ DEFINE_VREG_SVE(v21, z21),
+ DEFINE_VREG_SVE(v22, z22),
+ DEFINE_VREG_SVE(v23, z23),
+ DEFINE_VREG_SVE(v24, z24),
+ DEFINE_VREG_SVE(v25, z25),
+ DEFINE_VREG_SVE(v26, z26),
+ DEFINE_VREG_SVE(v27, z27),
+ DEFINE_VREG_SVE(v28, z28),
+ DEFINE_VREG_SVE(v29, z29),
+ DEFINE_VREG_SVE(v30, z30),
+ DEFINE_VREG_SVE(v31, z31),
+
+ // DEFINE_FPU_PSEUDO(name, size, ENDIAN OFFSET, parent register)
+ DEFINE_FPU_PSEUDO_SVE(s0, 4, z0),
+ DEFINE_FPU_PSEUDO_SVE(s1, 4, z1),
+ DEFINE_FPU_PSEUDO_SVE(s2, 4, z2),
+ DEFINE_FPU_PSEUDO_SVE(s3, 4, z3),
+ DEFINE_FPU_PSEUDO_SVE(s4, 4, z4),
+ DEFINE_FPU_PSEUDO_SVE(s5, 4, z5),
+ DEFINE_FPU_PSEUDO_SVE(s6, 4, z6),
+ DEFINE_FPU_PSEUDO_SVE(s7, 4, z7),
+ DEFINE_FPU_PSEUDO_SVE(s8, 4, z8),
+ DEFINE_FPU_PSEUDO_SVE(s9, 4, z9),
+ DEFINE_FPU_PSEUDO_SVE(s10, 4, z10),
+ DEFINE_FPU_PSEUDO_SVE(s11, 4, z11),
+ DEFINE_FPU_PSEUDO_SVE(s12, 4, z12),
+ DEFINE_FPU_PSEUDO_SVE(s13, 4, z13),
+ DEFINE_FPU_PSEUDO_SVE(s14, 4, z14),
+ DEFINE_FPU_PSEUDO_SVE(s15, 4, z15),
+ DEFINE_FPU_PSEUDO_SVE(s16, 4, z16),
+ DEFINE_FPU_PSEUDO_SVE(s17, 4, z17),
+ DEFINE_FPU_PSEUDO_SVE(s18, 4, z18),
+ DEFINE_FPU_PSEUDO_SVE(s19, 4, z19),
+ DEFINE_FPU_PSEUDO_SVE(s20, 4, z20),
+ DEFINE_FPU_PSEUDO_SVE(s21, 4, z21),
+ DEFINE_FPU_PSEUDO_SVE(s22, 4, z22),
+ DEFINE_FPU_PSEUDO_SVE(s23, 4, z23),
+ DEFINE_FPU_PSEUDO_SVE(s24, 4, z24),
+ DEFINE_FPU_PSEUDO_SVE(s25, 4, z25),
+ DEFINE_FPU_PSEUDO_SVE(s26, 4, z26),
+ DEFINE_FPU_PSEUDO_SVE(s27, 4, z27),
+ DEFINE_FPU_PSEUDO_SVE(s28, 4, z28),
+ DEFINE_FPU_PSEUDO_SVE(s29, 4, z29),
+ DEFINE_FPU_PSEUDO_SVE(s30, 4, z30),
+ DEFINE_FPU_PSEUDO_SVE(s31, 4, z31),
+
+ DEFINE_FPU_PSEUDO_SVE(d0, 8, z0),
+ DEFINE_FPU_PSEUDO_SVE(d1, 8, z1),
+ DEFINE_FPU_PSEUDO_SVE(d2, 8, z2),
+ DEFINE_FPU_PSEUDO_SVE(d3, 8, z3),
+ DEFINE_FPU_PSEUDO_SVE(d4, 8, z4),
+ DEFINE_FPU_PSEUDO_SVE(d5, 8, z5),
+ DEFINE_FPU_PSEUDO_SVE(d6, 8, z6),
+ DEFINE_FPU_PSEUDO_SVE(d7, 8, z7),
+ DEFINE_FPU_PSEUDO_SVE(d8, 8, z8),
+ DEFINE_FPU_PSEUDO_SVE(d9, 8, z9),
+ DEFINE_FPU_PSEUDO_SVE(d10, 8, z10),
+ DEFINE_FPU_PSEUDO_SVE(d11, 8, z11),
+ DEFINE_FPU_PSEUDO_SVE(d12, 8, z12),
+ DEFINE_FPU_PSEUDO_SVE(d13, 8, z13),
+ DEFINE_FPU_PSEUDO_SVE(d14, 8, z14),
+ DEFINE_FPU_PSEUDO_SVE(d15, 8, z15),
+ DEFINE_FPU_PSEUDO_SVE(d16, 8, z16),
+ DEFINE_FPU_PSEUDO_SVE(d17, 8, z17),
+ DEFINE_FPU_PSEUDO_SVE(d18, 8, z18),
+ DEFINE_FPU_PSEUDO_SVE(d19, 8, z19),
+ DEFINE_FPU_PSEUDO_SVE(d20, 8, z20),
+ DEFINE_FPU_PSEUDO_SVE(d21, 8, z21),
+ DEFINE_FPU_PSEUDO_SVE(d22, 8, z22),
+ DEFINE_FPU_PSEUDO_SVE(d23, 8, z23),
+ DEFINE_FPU_PSEUDO_SVE(d24, 8, z24),
+ DEFINE_FPU_PSEUDO_SVE(d25, 8, z25),
+ DEFINE_FPU_PSEUDO_SVE(d26, 8, z26),
+ DEFINE_FPU_PSEUDO_SVE(d27, 8, z27),
+ DEFINE_FPU_PSEUDO_SVE(d28, 8, z28),
+ DEFINE_FPU_PSEUDO_SVE(d29, 8, z29),
+ DEFINE_FPU_PSEUDO_SVE(d30, 8, z30),
+ DEFINE_FPU_PSEUDO_SVE(d31, 8, z31),
+
+ // DEFINE_MISC_REGS(name, size, TYPE, lldb kind)
+ DEFINE_MISC_REGS(fpsr, 4, FPU, fpu_fpsr),
+ DEFINE_MISC_REGS(fpcr, 4, FPU, fpu_fpcr),
+
+ DEFINE_MISC_REGS(vg, 8, VG, sve_vg),
+ // DEFINE_ZREG(name)
+ DEFINE_ZREG(z0),
+ DEFINE_ZREG(z1),
+ DEFINE_ZREG(z2),
+ DEFINE_ZREG(z3),
+ DEFINE_ZREG(z4),
+ DEFINE_ZREG(z5),
+ DEFINE_ZREG(z6),
+ DEFINE_ZREG(z7),
+ DEFINE_ZREG(z8),
+ DEFINE_ZREG(z9),
+ DEFINE_ZREG(z10),
+ DEFINE_ZREG(z11),
+ DEFINE_ZREG(z12),
+ DEFINE_ZREG(z13),
+ DEFINE_ZREG(z14),
+ DEFINE_ZREG(z15),
+ DEFINE_ZREG(z16),
+ DEFINE_ZREG(z17),
+ DEFINE_ZREG(z18),
+ DEFINE_ZREG(z19),
+ DEFINE_ZREG(z20),
+ DEFINE_ZREG(z21),
+ DEFINE_ZREG(z22),
+ DEFINE_ZREG(z23),
+ DEFINE_ZREG(z24),
+ DEFINE_ZREG(z25),
+ DEFINE_ZREG(z26),
+ DEFINE_ZREG(z27),
+ DEFINE_ZREG(z28),
+ DEFINE_ZREG(z29),
+ DEFINE_ZREG(z30),
+ DEFINE_ZREG(z31),
+
+ // DEFINE_PREG(name)
+ DEFINE_PREG(p0),
+ DEFINE_PREG(p1),
+ DEFINE_PREG(p2),
+ DEFINE_PREG(p3),
+ DEFINE_PREG(p4),
+ DEFINE_PREG(p5),
+ DEFINE_PREG(p6),
+ DEFINE_PREG(p7),
+ DEFINE_PREG(p8),
+ DEFINE_PREG(p9),
+ DEFINE_PREG(p10),
+ DEFINE_PREG(p11),
+ DEFINE_PREG(p12),
+ DEFINE_PREG(p13),
+ DEFINE_PREG(p14),
+ DEFINE_PREG(p15),
+
+ // DEFINE FFR
+ DEFINE_PREG(ffr)
+ // clang-format on
+};
+
+#endif // DECLARE_REGISTER_INFOS_ARM64_SVE_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h
new file mode 100644
index 000000000000..e9f8065bffd8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h
@@ -0,0 +1,310 @@
+//===-- RegisterInfos_i386.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Compiler.h"
+#include <cstddef>
+#include <cstdint>
+
+
+#ifdef DECLARE_REGISTER_INFOS_I386_STRUCT
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) (LLVM_EXTENSION offsetof(GPR, regname))
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, i387) + \
+ LLVM_EXTENSION offsetof(FPR_i386, regname))
+
+// Computes the offset of the YMM register assembled from register halves.
+// Based on DNBArchImplI386.cpp from debugserver
+#define YMM_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, i387) + \
+ LLVM_EXTENSION offsetof(FPR, fxsave) + \
+ LLVM_EXTENSION offsetof(FXSAVE, xmm[7]) + sizeof(XMMReg) + \
+ (32 * reg_index))
+
+#define BNDR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, i387) + \
+ LLVM_EXTENSION offsetof(FPR, xsave) + \
+ LLVM_EXTENSION offsetof(XSAVE, mpxr[reg_index]))
+
+#define BNDC_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, i387) + \
+ LLVM_EXTENSION offsetof(FPR, xsave) + \
+ LLVM_EXTENSION offsetof(XSAVE, mpxc[reg_index]))
+
+// Number of bytes needed to represent a FPR.
+#if !defined(FPR_SIZE)
+#define FPR_SIZE(reg) sizeof(((FXSAVE *)nullptr)->reg)
+#endif
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((MMSReg *)nullptr)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(XMMReg)
+
+// Number of bytes needed to represent a YMM register.
+#define YMM_SIZE sizeof(YMMReg)
+
+// Number of bytes needed to represent MPX registers.
+#define BNDR_SIZE sizeof(MPXReg)
+#define BNDC_SIZE sizeof(MPXCsr)
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { \
+ #reg, alt, sizeof(((GPR *)nullptr)->reg), \
+ GPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, kind4, \
+ lldb_##reg##_i386 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \
+ { \
+ #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, kind4, \
+ lldb_##name##_i386 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+// RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB
+
+#define DEFINE_FP_ST(reg, i) \
+ { \
+ #reg #i, nullptr, FP_SIZE, \
+ LLVM_EXTENSION FPR_OFFSET( \
+ stmm[i]), eEncodingVector, eFormatVectorOfUInt8, \
+ {ehframe_st##i##_i386, dwarf_st##i##_i386, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_st##i##_i386 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_FP_MM(reg, i, streg) \
+ { \
+ #reg #i, nullptr, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
+ eEncodingUint, eFormatHex, \
+ {dwarf_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_mm##i##_i386 }, \
+ RegisterContextPOSIX_x86::g_contained_##streg##_32, \
+ RegisterContextPOSIX_x86::g_invalidate_##streg##_32, \
+ nullptr, \
+ }
+
+#define DEFINE_XMM(reg, i) \
+ { \
+ #reg #i, nullptr, XMM_SIZE, \
+ LLVM_EXTENSION FPR_OFFSET( \
+ reg[i]), eEncodingVector, eFormatVectorOfUInt8, \
+ {ehframe_##reg##i##_i386, dwarf_##reg##i##_i386, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg##i##_i386 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+// I believe the YMM registers use dwarf_xmm_%_i386 register numbers and then
+// differentiate based on register size.
+#define DEFINE_YMM(reg, i) \
+ { \
+ #reg #i, nullptr, YMM_SIZE, \
+ LLVM_EXTENSION YMM_OFFSET(i), eEncodingVector, eFormatVectorOfUInt8, \
+ {LLDB_INVALID_REGNUM, dwarf_xmm##i##_i386, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg##i##_i386 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_BNDR(reg, i) \
+ { \
+ #reg #i, nullptr, BNDR_SIZE, \
+ LLVM_EXTENSION BNDR_OFFSET(i), eEncodingVector, eFormatVectorOfUInt64, \
+ {dwarf_##reg##i##_i386, dwarf_##reg##i##_i386, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_##reg##i##_i386 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_BNDC(name, i) \
+ { \
+ #name, nullptr, BNDC_SIZE, \
+ LLVM_EXTENSION BNDC_OFFSET(i), eEncodingVector, \
+ eFormatVectorOfUInt8, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_##name##_i386 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_DR(reg, i) \
+ { \
+ #reg #i, nullptr, DR_SIZE, \
+ DR_OFFSET(i), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg##i##_i386 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_16(reg16, reg32) \
+ { \
+ #reg16, nullptr, 2, \
+ GPR_OFFSET(reg32), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg16##_i386 }, \
+ RegisterContextPOSIX_x86::g_contained_##reg32, \
+ RegisterContextPOSIX_x86::g_invalidate_##reg32, \
+ nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_8H(reg8, reg32) \
+ { \
+ #reg8, nullptr, 1, \
+ GPR_OFFSET(reg32) + 1, eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg8##_i386 }, \
+ RegisterContextPOSIX_x86::g_contained_##reg32, \
+ RegisterContextPOSIX_x86::g_invalidate_##reg32, \
+ nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_8L(reg8, reg32) \
+ { \
+ #reg8, nullptr, 1, \
+ GPR_OFFSET(reg32), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg8##_i386 }, \
+ RegisterContextPOSIX_x86::g_contained_##reg32, \
+ RegisterContextPOSIX_x86::g_invalidate_##reg32, \
+ nullptr, \
+ }
+
+static RegisterInfo g_register_infos_i386[] = {
+ // General purpose registers.
+ DEFINE_GPR(eax, nullptr, ehframe_eax_i386, dwarf_eax_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ebx, nullptr, ehframe_ebx_i386, dwarf_ebx_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ecx, nullptr, ehframe_ecx_i386, dwarf_ecx_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(edx, nullptr, ehframe_edx_i386, dwarf_edx_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(edi, nullptr, ehframe_edi_i386, dwarf_edi_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(esi, nullptr, ehframe_esi_i386, dwarf_esi_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ebp, "fp", ehframe_ebp_i386, dwarf_ebp_i386,
+ LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(esp, "sp", ehframe_esp_i386, dwarf_esp_i386,
+ LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(eip, "pc", ehframe_eip_i386, dwarf_eip_i386,
+ LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(eflags, "flags", ehframe_eflags_i386, dwarf_eflags_i386,
+ LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(cs, nullptr, LLDB_INVALID_REGNUM, dwarf_cs_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(fs, nullptr, LLDB_INVALID_REGNUM, dwarf_fs_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(gs, nullptr, LLDB_INVALID_REGNUM, dwarf_gs_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ss, nullptr, LLDB_INVALID_REGNUM, dwarf_ss_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ds, nullptr, LLDB_INVALID_REGNUM, dwarf_ds_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(es, nullptr, LLDB_INVALID_REGNUM, dwarf_es_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ DEFINE_GPR_PSEUDO_16(ax, eax), DEFINE_GPR_PSEUDO_16(bx, ebx),
+ DEFINE_GPR_PSEUDO_16(cx, ecx), DEFINE_GPR_PSEUDO_16(dx, edx),
+ DEFINE_GPR_PSEUDO_16(di, edi), DEFINE_GPR_PSEUDO_16(si, esi),
+ DEFINE_GPR_PSEUDO_16(bp, ebp), DEFINE_GPR_PSEUDO_16(sp, esp),
+ DEFINE_GPR_PSEUDO_8H(ah, eax), DEFINE_GPR_PSEUDO_8H(bh, ebx),
+ DEFINE_GPR_PSEUDO_8H(ch, ecx), DEFINE_GPR_PSEUDO_8H(dh, edx),
+ DEFINE_GPR_PSEUDO_8L(al, eax), DEFINE_GPR_PSEUDO_8L(bl, ebx),
+ DEFINE_GPR_PSEUDO_8L(cl, ecx), DEFINE_GPR_PSEUDO_8L(dl, edx),
+
+ // i387 Floating point registers.
+ DEFINE_FPR(fctrl, fctrl, LLDB_INVALID_REGNUM, dwarf_fctrl_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(fstat, fstat, LLDB_INVALID_REGNUM, dwarf_fstat_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(mxcsr, mxcsr, LLDB_INVALID_REGNUM, dwarf_mxcsr_i386,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ // FP registers.
+ DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2),
+ DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5),
+ DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7),
+
+ DEFINE_FP_MM(mm, 0, st0), DEFINE_FP_MM(mm, 1, st1),
+ DEFINE_FP_MM(mm, 2, st2), DEFINE_FP_MM(mm, 3, st3),
+ DEFINE_FP_MM(mm, 4, st4), DEFINE_FP_MM(mm, 5, st5),
+ DEFINE_FP_MM(mm, 6, st6), DEFINE_FP_MM(mm, 7, st7),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3), DEFINE_XMM(xmm, 4), DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6), DEFINE_XMM(xmm, 7),
+
+ // Copy of YMM registers assembled from xmm and ymmh
+ DEFINE_YMM(ymm, 0), DEFINE_YMM(ymm, 1), DEFINE_YMM(ymm, 2),
+ DEFINE_YMM(ymm, 3), DEFINE_YMM(ymm, 4), DEFINE_YMM(ymm, 5),
+ DEFINE_YMM(ymm, 6), DEFINE_YMM(ymm, 7),
+
+ // MPX registers
+ DEFINE_BNDR(bnd, 0),
+ DEFINE_BNDR(bnd, 1),
+ DEFINE_BNDR(bnd, 2),
+ DEFINE_BNDR(bnd, 3),
+
+ DEFINE_BNDC(bndcfgu, 0),
+ DEFINE_BNDC(bndstatus, 1),
+
+ // Debug registers for lldb internal use
+ DEFINE_DR(dr, 0), DEFINE_DR(dr, 1), DEFINE_DR(dr, 2), DEFINE_DR(dr, 3),
+ DEFINE_DR(dr, 4), DEFINE_DR(dr, 5), DEFINE_DR(dr, 6), DEFINE_DR(dr, 7)};
+
+static_assert((sizeof(g_register_infos_i386) /
+ sizeof(g_register_infos_i386[0])) == k_num_registers_i386,
+ "g_register_infos_x86_64 has wrong number of register infos");
+
+#undef GPR_OFFSET
+#undef FPR_OFFSET
+#undef YMM_OFFSET
+#undef FPR_SIZE
+#undef FP_SIZE
+#undef XMM_SIZE
+#undef YMM_SIZE
+#undef DEFINE_GPR
+#undef DEFINE_FPR
+#undef DEFINE_FP
+#undef DEFINE_XMM
+#undef DEFINE_YMM
+#undef DEFINE_BNDR
+#undef DEFINE_BNDC
+#undef DEFINE_DR
+#undef DEFINE_GPR_PSEUDO_16
+#undef DEFINE_GPR_PSEUDO_8H
+#undef DEFINE_GPR_PSEUDO_8L
+
+#endif // DECLARE_REGISTER_INFOS_I386_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_loongarch64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_loongarch64.h
new file mode 100644
index 000000000000..3fb1e6a5fbef
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_loongarch64.h
@@ -0,0 +1,171 @@
+//===-- RegisterInfos_loongarch64.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_LOONGARCH64_STRUCT
+
+#include <stddef.h>
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private.h"
+
+#include "Utility/LoongArch_DWARF_Registers.h"
+#include "lldb-loongarch-register-enums.h"
+
+#ifndef GPR_OFFSET
+#error GPR_OFFSET must be defined before including this header file
+#endif
+
+#ifndef FPR_OFFSET
+#error FPR_OFFSET must be defined before including this header file
+#endif
+
+using namespace loongarch_dwarf;
+
+// clang-format off
+
+// I suppose EHFrame and DWARF are the same.
+#define KIND_HELPER(reg, generic_kind) \
+ { \
+ loongarch_dwarf::dwarf_##reg, loongarch_dwarf::dwarf_##reg, generic_kind, \
+ LLDB_INVALID_REGNUM, reg##_loongarch \
+ }
+
+// Generates register kinds array for generic purpose registers
+#define GPR64_KIND(reg, generic_kind) KIND_HELPER(reg, generic_kind)
+
+// Generates register kinds array for floating point registers
+#define FPR64_KIND(reg, generic_kind) KIND_HELPER(reg, generic_kind)
+
+// Defines a 64-bit general purpose register
+#define DEFINE_GPR64(reg, generic_kind) DEFINE_GPR64_ALT(reg, reg, generic_kind)
+#define DEFINE_GPR64_ALT(reg, alt, generic_kind) \
+ { \
+ #reg, #alt, 8, GPR_OFFSET(gpr_##reg##_loongarch - gpr_first_loongarch), \
+ lldb::eEncodingUint, lldb::eFormatHex, \
+ GPR64_KIND(gpr_##reg, generic_kind), nullptr, nullptr, nullptr, \
+ }
+
+// Defines a 64-bit floating point register
+#define DEFINE_FPR64(reg, generic_kind) DEFINE_FPR64_ALT(reg, reg, generic_kind)
+#define DEFINE_FPR64_ALT(reg, alt, generic_kind) \
+ { \
+ #reg, #alt, 8, FPR_OFFSET(fpr_##reg##_loongarch - fpr_first_loongarch), \
+ lldb::eEncodingUint, lldb::eFormatHex, \
+ FPR64_KIND(fpr_##reg, generic_kind), nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_FCC(reg, generic_kind) \
+ { \
+ #reg, nullptr, 1, FCC_OFFSET(fpr_##reg##_loongarch - fpr_fcc0_loongarch), \
+ lldb::eEncodingUint, lldb::eFormatHex, \
+ FPR64_KIND(fpr_##reg, generic_kind), nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_FCSR(reg, generic_kind) \
+ { \
+ #reg, nullptr, 4, FCSR_OFFSET, \
+ lldb::eEncodingUint, lldb::eFormatHex, \
+ FPR64_KIND(fpr_##reg, generic_kind), nullptr, nullptr, nullptr, \
+ }
+
+// clang-format on
+
+static lldb_private::RegisterInfo g_register_infos_loongarch64[] = {
+ DEFINE_GPR64_ALT(r0, zero, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r1, ra, LLDB_REGNUM_GENERIC_RA),
+ DEFINE_GPR64_ALT(r2, tp, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r3, sp, LLDB_REGNUM_GENERIC_SP),
+ DEFINE_GPR64_ALT(r4, a0, LLDB_REGNUM_GENERIC_ARG1),
+ DEFINE_GPR64_ALT(r5, a1, LLDB_REGNUM_GENERIC_ARG2),
+ DEFINE_GPR64_ALT(r6, a2, LLDB_REGNUM_GENERIC_ARG3),
+ DEFINE_GPR64_ALT(r7, a3, LLDB_REGNUM_GENERIC_ARG4),
+ DEFINE_GPR64_ALT(r8, a4, LLDB_REGNUM_GENERIC_ARG5),
+ DEFINE_GPR64_ALT(r9, a5, LLDB_REGNUM_GENERIC_ARG6),
+ DEFINE_GPR64_ALT(r10, a6, LLDB_REGNUM_GENERIC_ARG7),
+ DEFINE_GPR64_ALT(r11, a7, LLDB_REGNUM_GENERIC_ARG8),
+ DEFINE_GPR64_ALT(r12, t0, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r13, t1, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r14, t2, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r15, t3, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r16, t4, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r17, t5, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r18, t6, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r19, t7, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r20, t8, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(r21, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r22, fp, LLDB_REGNUM_GENERIC_FP),
+ DEFINE_GPR64_ALT(r23, s0, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r24, s1, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r25, s2, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r26, s3, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r27, s4, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r28, s5, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r29, s6, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r30, s7, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(r31, s8, LLDB_INVALID_REGNUM),
+
+ DEFINE_GPR64(orig_a0, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(pc, LLDB_REGNUM_GENERIC_PC),
+ DEFINE_GPR64(badv, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(reserved0, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(reserved1, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(reserved2, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(reserved3, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(reserved4, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(reserved5, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(reserved6, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(reserved7, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(reserved8, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(reserved9, LLDB_INVALID_REGNUM),
+
+ DEFINE_FPR64_ALT(f0, fa0, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f1, fa1, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f2, fa2, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f3, fa3, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f4, fa4, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f5, fa5, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f6, fa6, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f7, fa7, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f8, ft0, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f9, ft1, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f10, ft2, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f11, ft3, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f12, ft4, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f13, ft5, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f14, ft6, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f15, ft7, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f16, ft8, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f17, ft9, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f18, ft10, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f19, ft11, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f20, ft12, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f21, ft13, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f22, ft14, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f23, ft15, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f24, fs0, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f25, fs1, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f26, fs2, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f27, fs3, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f28, fs4, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f29, fs5, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f30, fs6, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(f31, fs7, LLDB_INVALID_REGNUM),
+
+ DEFINE_FCC(fcc0, LLDB_INVALID_REGNUM),
+ DEFINE_FCC(fcc1, LLDB_INVALID_REGNUM),
+ DEFINE_FCC(fcc2, LLDB_INVALID_REGNUM),
+ DEFINE_FCC(fcc3, LLDB_INVALID_REGNUM),
+ DEFINE_FCC(fcc4, LLDB_INVALID_REGNUM),
+ DEFINE_FCC(fcc5, LLDB_INVALID_REGNUM),
+ DEFINE_FCC(fcc6, LLDB_INVALID_REGNUM),
+ DEFINE_FCC(fcc7, LLDB_INVALID_REGNUM),
+ DEFINE_FCSR(fcsr, LLDB_INVALID_REGNUM),
+};
+
+#endif // DECLARE_REGISTER_INFOS_LOONGARCH64_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h
new file mode 100644
index 000000000000..93f93d56fda2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h
@@ -0,0 +1,305 @@
+//===-- RegisterInfos_mips.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include <cstddef>
+
+#include "lldb/Core/dwarf.h"
+#include "llvm/Support/Compiler.h"
+
+
+#ifdef DECLARE_REGISTER_INFOS_MIPS_STRUCT
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, gpr) + \
+ LLVM_EXTENSION offsetof(GPR_linux_mips, regname))
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR_linux_mips, regname))
+
+// Computes the offset of the given MSA in the extended data area.
+#define MSA_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, msa) + \
+ LLVM_EXTENSION offsetof(MSA_linux_mips, regname))
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3) \
+ { \
+ #reg, alt, sizeof(((GPR_linux_mips *) NULL)->reg) / 2, \
+ GPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, ptrace_##reg##_mips, \
+ gpr_##reg##_mips }, \
+ NULL, NULL, NULL, 0 \
+ }
+
+const uint8_t dwarf_opcode_mips[] = {
+ llvm::dwarf::DW_OP_regx, dwarf_sr_mips, llvm::dwarf::DW_OP_lit1,
+ llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shl, llvm::dwarf::DW_OP_and,
+ llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shr};
+
+#define DEFINE_FPR(reg, alt, kind1, kind2, kind3) \
+ { \
+ #reg, alt, sizeof(((FPR_linux_mips *) NULL)->reg), \
+ FPR_OFFSET(reg), eEncodingIEEE754, eFormatFloat, \
+ {kind1, kind2, kind3, ptrace_##reg##_mips, \
+ fpr_##reg##_mips }, \
+ NULL, NULL, dwarf_opcode_mips, \
+ sizeof(dwarf_opcode_mips) \
+ }
+
+#define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3) \
+ { \
+ #reg, alt, sizeof(((FPR_linux_mips *) NULL)->reg), \
+ FPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, ptrace_##reg##_mips, \
+ fpr_##reg##_mips }, \
+ NULL, NULL, NULL, 0 \
+ }
+
+#define DEFINE_MSA(reg, alt, kind1, kind2, kind3, kind4) \
+ { \
+ #reg, alt, sizeof(((MSA_linux_mips *) 0)->reg), \
+ MSA_OFFSET(reg), eEncodingVector, eFormatVectorOfUInt8, \
+ {kind1, kind2, kind3, kind4, \
+ msa_##reg##_mips }, \
+ NULL, NULL, NULL, 0 \
+ }
+
+#define DEFINE_MSA_INFO(reg, alt, kind1, kind2, kind3, kind4) \
+ { \
+ #reg, alt, sizeof(((MSA_linux_mips *) 0)->reg), \
+ MSA_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, kind4, \
+ msa_##reg##_mips }, \
+ NULL, NULL, NULL, 0 \
+ }
+
+// RegisterKind: EH_Frame, DWARF, Generic, Procss Plugin, LLDB
+
+static RegisterInfo g_register_infos_mips[] = {
+ DEFINE_GPR(zero, "zero", dwarf_zero_mips, dwarf_zero_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r1, "at", dwarf_r1_mips, dwarf_r1_mips, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r2, nullptr, dwarf_r2_mips, dwarf_r2_mips, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r3, nullptr, dwarf_r3_mips, dwarf_r3_mips, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r4, nullptr, dwarf_r4_mips, dwarf_r4_mips,
+ LLDB_REGNUM_GENERIC_ARG1),
+ DEFINE_GPR(r5, nullptr, dwarf_r5_mips, dwarf_r5_mips,
+ LLDB_REGNUM_GENERIC_ARG2),
+ DEFINE_GPR(r6, nullptr, dwarf_r6_mips, dwarf_r6_mips,
+ LLDB_REGNUM_GENERIC_ARG3),
+ DEFINE_GPR(r7, nullptr, dwarf_r7_mips, dwarf_r7_mips,
+ LLDB_REGNUM_GENERIC_ARG4),
+ DEFINE_GPR(r8, nullptr, dwarf_r8_mips, dwarf_r8_mips, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r9, nullptr, dwarf_r9_mips, dwarf_r9_mips, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r10, nullptr, dwarf_r10_mips, dwarf_r10_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r11, nullptr, dwarf_r11_mips, dwarf_r11_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r12, nullptr, dwarf_r12_mips, dwarf_r12_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r13, nullptr, dwarf_r13_mips, dwarf_r13_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r14, nullptr, dwarf_r14_mips, dwarf_r14_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r15, nullptr, dwarf_r15_mips, dwarf_r15_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r16, nullptr, dwarf_r16_mips, dwarf_r16_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r17, nullptr, dwarf_r17_mips, dwarf_r17_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r18, nullptr, dwarf_r18_mips, dwarf_r18_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r19, nullptr, dwarf_r19_mips, dwarf_r19_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r20, nullptr, dwarf_r20_mips, dwarf_r20_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r21, nullptr, dwarf_r21_mips, dwarf_r21_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r22, nullptr, dwarf_r22_mips, dwarf_r22_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r23, nullptr, dwarf_r23_mips, dwarf_r23_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r24, nullptr, dwarf_r24_mips, dwarf_r24_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r25, nullptr, dwarf_r25_mips, dwarf_r25_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r26, nullptr, dwarf_r26_mips, dwarf_r26_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r27, nullptr, dwarf_r27_mips, dwarf_r27_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(gp, "gp", dwarf_gp_mips, dwarf_gp_mips, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(sp, "sp", dwarf_sp_mips, dwarf_sp_mips, LLDB_REGNUM_GENERIC_SP),
+ DEFINE_GPR(r30, "fp", dwarf_r30_mips, dwarf_r30_mips,
+ LLDB_REGNUM_GENERIC_FP),
+ DEFINE_GPR(ra, "ra", dwarf_ra_mips, dwarf_ra_mips, LLDB_REGNUM_GENERIC_RA),
+ DEFINE_GPR(sr, "status", dwarf_sr_mips, dwarf_sr_mips,
+ LLDB_REGNUM_GENERIC_FLAGS),
+ DEFINE_GPR(mullo, nullptr, dwarf_lo_mips, dwarf_lo_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(mulhi, nullptr, dwarf_hi_mips, dwarf_hi_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(badvaddr, nullptr, dwarf_bad_mips, dwarf_bad_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(cause, nullptr, dwarf_cause_mips, dwarf_cause_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(pc, nullptr, dwarf_pc_mips, dwarf_pc_mips,
+ LLDB_REGNUM_GENERIC_PC),
+ DEFINE_GPR(config5, nullptr, dwarf_config5_mips, dwarf_config5_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f0, nullptr, dwarf_f0_mips, dwarf_f0_mips, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f1, nullptr, dwarf_f1_mips, dwarf_f1_mips, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f2, nullptr, dwarf_f2_mips, dwarf_f2_mips, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f3, nullptr, dwarf_f3_mips, dwarf_f3_mips, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f4, nullptr, dwarf_f4_mips, dwarf_f4_mips, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f5, nullptr, dwarf_f5_mips, dwarf_f5_mips, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f6, nullptr, dwarf_f6_mips, dwarf_f6_mips, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f7, nullptr, dwarf_f7_mips, dwarf_f7_mips, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f8, nullptr, dwarf_f8_mips, dwarf_f8_mips, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f9, nullptr, dwarf_f9_mips, dwarf_f9_mips, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f10, nullptr, dwarf_f10_mips, dwarf_f10_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f11, nullptr, dwarf_f11_mips, dwarf_f11_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f12, nullptr, dwarf_f12_mips, dwarf_f12_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f13, nullptr, dwarf_f13_mips, dwarf_f13_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f14, nullptr, dwarf_f14_mips, dwarf_f14_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f15, nullptr, dwarf_f15_mips, dwarf_f15_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f16, nullptr, dwarf_f16_mips, dwarf_f16_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f17, nullptr, dwarf_f17_mips, dwarf_f17_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f18, nullptr, dwarf_f18_mips, dwarf_f18_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f19, nullptr, dwarf_f19_mips, dwarf_f19_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f20, nullptr, dwarf_f20_mips, dwarf_f20_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f21, nullptr, dwarf_f21_mips, dwarf_f21_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f22, nullptr, dwarf_f22_mips, dwarf_f22_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f23, nullptr, dwarf_f23_mips, dwarf_f23_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f24, nullptr, dwarf_f24_mips, dwarf_f24_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f25, nullptr, dwarf_f25_mips, dwarf_f25_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f26, nullptr, dwarf_f26_mips, dwarf_f26_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f27, nullptr, dwarf_f27_mips, dwarf_f27_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f28, nullptr, dwarf_f28_mips, dwarf_f28_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f29, nullptr, dwarf_f29_mips, dwarf_f29_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f30, nullptr, dwarf_f30_mips, dwarf_f30_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f31, nullptr, dwarf_f31_mips, dwarf_f31_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR_INFO(fcsr, nullptr, dwarf_fcsr_mips, dwarf_fcsr_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR_INFO(fir, nullptr, dwarf_fir_mips, dwarf_fir_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR_INFO(config5, nullptr, dwarf_config5_mips, dwarf_config5_mips,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w0, nullptr, dwarf_w0_mips, dwarf_w0_mips, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w1, nullptr, dwarf_w1_mips, dwarf_w1_mips, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w2, nullptr, dwarf_w2_mips, dwarf_w2_mips, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w3, nullptr, dwarf_w3_mips, dwarf_w3_mips, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w4, nullptr, dwarf_w4_mips, dwarf_w4_mips, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w5, nullptr, dwarf_w5_mips, dwarf_w5_mips, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w6, nullptr, dwarf_w6_mips, dwarf_w6_mips, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w7, nullptr, dwarf_w7_mips, dwarf_w7_mips, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w8, nullptr, dwarf_w8_mips, dwarf_w8_mips, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w9, nullptr, dwarf_w9_mips, dwarf_w9_mips, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w10, nullptr, dwarf_w10_mips, dwarf_w10_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w11, nullptr, dwarf_w11_mips, dwarf_w11_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w12, nullptr, dwarf_w12_mips, dwarf_w12_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w13, nullptr, dwarf_w13_mips, dwarf_w13_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w14, nullptr, dwarf_w14_mips, dwarf_w14_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w15, nullptr, dwarf_w15_mips, dwarf_w15_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w16, nullptr, dwarf_w16_mips, dwarf_w16_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w17, nullptr, dwarf_w17_mips, dwarf_w17_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w18, nullptr, dwarf_w18_mips, dwarf_w18_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w19, nullptr, dwarf_w19_mips, dwarf_w19_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w20, nullptr, dwarf_w10_mips, dwarf_w20_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w21, nullptr, dwarf_w21_mips, dwarf_w21_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w22, nullptr, dwarf_w22_mips, dwarf_w22_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w23, nullptr, dwarf_w23_mips, dwarf_w23_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w24, nullptr, dwarf_w24_mips, dwarf_w24_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w25, nullptr, dwarf_w25_mips, dwarf_w25_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w26, nullptr, dwarf_w26_mips, dwarf_w26_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w27, nullptr, dwarf_w27_mips, dwarf_w27_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w28, nullptr, dwarf_w28_mips, dwarf_w28_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w29, nullptr, dwarf_w29_mips, dwarf_w29_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w30, nullptr, dwarf_w30_mips, dwarf_w30_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA(w31, nullptr, dwarf_w31_mips, dwarf_w31_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA_INFO(mcsr, nullptr, dwarf_mcsr_mips, dwarf_mcsr_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA_INFO(mir, nullptr, dwarf_mir_mips, dwarf_mir_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA_INFO(fcsr, nullptr, dwarf_fcsr_mips, dwarf_fcsr_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA_INFO(fir, nullptr, dwarf_fir_mips, dwarf_fir_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_MSA_INFO(config5, nullptr, dwarf_config5_mips, dwarf_config5_mips,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM)};
+
+static_assert((sizeof(g_register_infos_mips) /
+ sizeof(g_register_infos_mips[0])) == k_num_registers_mips,
+ "g_register_infos_mips has wrong number of register infos");
+
+#undef GPR_OFFSET
+#undef FPR_OFFSET
+#undef MSA_OFFSET
+#undef DEFINE_GPR
+#undef DEFINE_FPR
+#undef DEFINE_FPR_INFO
+#undef DEFINE_MSA
+#undef DEFINE_MSA_INFO
+
+#endif // DECLARE_REGISTER_INFOS_MIPS_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h
new file mode 100644
index 000000000000..0a382032ac8b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h
@@ -0,0 +1,223 @@
+//===-- RegisterInfos_mips64.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstddef>
+
+#include "lldb/Core/dwarf.h"
+#include "llvm/Support/Compiler.h"
+
+#ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) (LLVM_EXTENSION offsetof(GPR_freebsd_mips, regname))
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (sizeof(GPR_freebsd_mips) + \
+ LLVM_EXTENSION offsetof(FPR_freebsd_mips, regname))
+
+// RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { \
+ #reg, alt, sizeof(((GPR_freebsd_mips *) 0)->reg), \
+ GPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, kind4, \
+ gpr_##reg##_mips64 }, \
+ NULL, NULL, NULL, \
+ }
+
+#define DEFINE_FPR(reg, alt, kind1, kind2, kind3) \
+ { \
+ #reg, alt, sizeof(((FPR_freebsd_mips *) 0)->reg), \
+ FPR_OFFSET(reg), eEncodingIEEE754, eFormatFloat, \
+ {kind1, kind2, kind3, LLDB_INVALID_REGNUM, \
+ fpr_##reg##_mips64 }, \
+ NULL, NULL, NULL, \
+ }
+
+#define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3) \
+ { \
+ #reg, alt, sizeof(((FPR_freebsd_mips *) 0)->reg), \
+ FPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, LLDB_INVALID_REGNUM, \
+ fpr_##reg##_mips64 }, \
+ NULL, NULL, NULL, \
+ }
+
+
+static RegisterInfo g_register_infos_mips64[] = {
+// General purpose registers. EH_Frame, DWARF,
+// Generic, Process Plugin
+ DEFINE_GPR(zero, "r0", dwarf_zero_mips64, dwarf_zero_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r1, nullptr, dwarf_r1_mips64, dwarf_r1_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r2, nullptr, dwarf_r2_mips64, dwarf_r2_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r3, nullptr, dwarf_r3_mips64, dwarf_r3_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r4, nullptr, dwarf_r4_mips64, dwarf_r4_mips64,
+ LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r5, nullptr, dwarf_r5_mips64, dwarf_r5_mips64,
+ LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r6, nullptr, dwarf_r6_mips64, dwarf_r6_mips64,
+ LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r7, nullptr, dwarf_r7_mips64, dwarf_r7_mips64,
+ LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r8, nullptr, dwarf_r8_mips64, dwarf_r8_mips64,
+ LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r9, nullptr, dwarf_r9_mips64, dwarf_r9_mips64,
+ LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r10, nullptr, dwarf_r10_mips64, dwarf_r10_mips64,
+ LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r11, nullptr, dwarf_r11_mips64, dwarf_r11_mips64,
+ LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r12, nullptr, dwarf_r12_mips64, dwarf_r12_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r13, nullptr, dwarf_r13_mips64, dwarf_r13_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r14, nullptr, dwarf_r14_mips64, dwarf_r14_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r15, nullptr, dwarf_r15_mips64, dwarf_r15_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r16, nullptr, dwarf_r16_mips64, dwarf_r16_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r17, nullptr, dwarf_r17_mips64, dwarf_r17_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r18, nullptr, dwarf_r18_mips64, dwarf_r18_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r19, nullptr, dwarf_r19_mips64, dwarf_r19_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r20, nullptr, dwarf_r20_mips64, dwarf_r20_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r21, nullptr, dwarf_r21_mips64, dwarf_r21_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r22, nullptr, dwarf_r22_mips64, dwarf_r22_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r23, nullptr, dwarf_r23_mips64, dwarf_r23_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r24, nullptr, dwarf_r24_mips64, dwarf_r24_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r25, nullptr, dwarf_r25_mips64, dwarf_r25_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r26, nullptr, dwarf_r26_mips64, dwarf_r26_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r27, nullptr, dwarf_r27_mips64, dwarf_r27_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(gp, "r28", dwarf_gp_mips64, dwarf_gp_mips64, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR(sp, "r29", dwarf_sp_mips64, dwarf_sp_mips64,
+ LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r30, nullptr, dwarf_r30_mips64, dwarf_r30_mips64,
+ LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ra, "r31", dwarf_ra_mips64, dwarf_ra_mips64,
+ LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(sr, nullptr, dwarf_sr_mips64, dwarf_sr_mips64,
+ LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(mullo, nullptr, dwarf_lo_mips64, dwarf_lo_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(mulhi, nullptr, dwarf_hi_mips64, dwarf_hi_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(badvaddr, nullptr, dwarf_bad_mips64, dwarf_bad_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(cause, nullptr, dwarf_cause_mips64, dwarf_cause_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(pc, "pc", dwarf_pc_mips64, dwarf_pc_mips64,
+ LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ic, nullptr, dwarf_ic_mips64, dwarf_ic_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(dummy, nullptr, dwarf_dummy_mips64, dwarf_dummy_mips64,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ DEFINE_FPR(f0, nullptr, dwarf_f0_mips64, dwarf_f0_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f1, nullptr, dwarf_f1_mips64, dwarf_f1_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f2, nullptr, dwarf_f2_mips64, dwarf_f2_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f3, nullptr, dwarf_f3_mips64, dwarf_f3_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f4, nullptr, dwarf_f4_mips64, dwarf_f4_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f5, nullptr, dwarf_f5_mips64, dwarf_f5_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f6, nullptr, dwarf_f6_mips64, dwarf_f6_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f7, nullptr, dwarf_f7_mips64, dwarf_f7_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f8, nullptr, dwarf_f8_mips64, dwarf_f8_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f9, nullptr, dwarf_f9_mips64, dwarf_f9_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f10, nullptr, dwarf_f10_mips64, dwarf_f10_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f11, nullptr, dwarf_f11_mips64, dwarf_f11_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f12, nullptr, dwarf_f12_mips64, dwarf_f12_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f13, nullptr, dwarf_f13_mips64, dwarf_f13_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f14, nullptr, dwarf_f14_mips64, dwarf_f14_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f15, nullptr, dwarf_f15_mips64, dwarf_f15_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f16, nullptr, dwarf_f16_mips64, dwarf_f16_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f17, nullptr, dwarf_f17_mips64, dwarf_f17_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f18, nullptr, dwarf_f18_mips64, dwarf_f18_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f19, nullptr, dwarf_f19_mips64, dwarf_f19_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f20, nullptr, dwarf_f20_mips64, dwarf_f20_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f21, nullptr, dwarf_f21_mips64, dwarf_f21_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f22, nullptr, dwarf_f22_mips64, dwarf_f22_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f23, nullptr, dwarf_f23_mips64, dwarf_f23_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f24, nullptr, dwarf_f24_mips64, dwarf_f24_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f25, nullptr, dwarf_f25_mips64, dwarf_f25_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f26, nullptr, dwarf_f26_mips64, dwarf_f26_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f27, nullptr, dwarf_f27_mips64, dwarf_f27_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f28, nullptr, dwarf_f28_mips64, dwarf_f28_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f29, nullptr, dwarf_f29_mips64, dwarf_f29_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f30, nullptr, dwarf_f30_mips64, dwarf_f30_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR(f31, nullptr, dwarf_f31_mips64, dwarf_f31_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR_INFO(fcsr, nullptr, dwarf_fcsr_mips64, dwarf_fcsr_mips64,
+ LLDB_INVALID_REGNUM),
+ DEFINE_FPR_INFO(fir, nullptr, dwarf_fir_mips64, dwarf_fir_mips64,
+ LLDB_INVALID_REGNUM),
+};
+
+static_assert((sizeof(g_register_infos_mips64) /
+ sizeof(g_register_infos_mips64[0])) == k_num_registers_mips64,
+ "g_register_infos_mips64 has wrong number of register infos");
+
+#undef DEFINE_GPR
+#undef DEFINE_GPR_INFO
+#undef DEFINE_FPR
+#undef DEFINE_FPR_INFO
+#undef DEFINE_MSA
+#undef DEFINE_MSA_INFO
+#undef GPR_OFFSET
+#undef FPR_OFFSET
+#undef MSA_OFFSET
+
+#endif // DECLARE_REGISTER_INFOS_MIPS64_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h
new file mode 100644
index 000000000000..31f79f537911
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h
@@ -0,0 +1,228 @@
+//===-- RegisterInfos_powerpc.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include <cstddef>
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) (offsetof(GPR, regname))
+#define FPR_OFFSET(regname) (sizeof(GPR) + offsetof(FPR, regname))
+#define VMX_OFFSET(regname) (sizeof(GPR) + sizeof(FPR) + offsetof(VMX, regname))
+#define GPR_SIZE(regname) (sizeof(((GPR *)NULL)->regname))
+
+#ifdef DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, lldb_kind) \
+ { \
+ #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {dwarf_##reg##_powerpc, \
+ dwarf_##reg##_powerpc, lldb_kind, \
+ LLDB_INVALID_REGNUM, \
+ gpr_##reg##_powerpc }, \
+ NULL, NULL, NULL, \
+ }
+#define DEFINE_FPR(reg, lldb_kind) \
+ { \
+ #reg, NULL, 8, FPR_OFFSET(reg), eEncodingIEEE754, eFormatFloat, \
+ {dwarf_##reg##_powerpc, dwarf_##reg##_powerpc, \
+ lldb_kind, LLDB_INVALID_REGNUM, \
+ fpr_##reg##_powerpc }, \
+ NULL, NULL, NULL, \
+ }
+#define DEFINE_VMX(reg, lldb_kind) \
+ { \
+ #reg, NULL, 16, VMX_OFFSET(reg), eEncodingVector, eFormatVectorOfUInt32, \
+ {dwarf_##reg##_powerpc, dwarf_##reg##_powerpc, \
+ lldb_kind, LLDB_INVALID_REGNUM, \
+ vmx_##reg##_powerpc }, \
+ NULL, NULL, NULL, \
+ }
+
+// General purpose registers. EH_Frame, DWARF,
+// Generic, Process Plugin
+#define POWERPC_REGS \
+ DEFINE_GPR(r0, NULL, LLDB_INVALID_REGNUM) \
+ , DEFINE_GPR(r1, NULL, LLDB_REGNUM_GENERIC_SP), \
+ DEFINE_GPR(r2, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r3, NULL, LLDB_REGNUM_GENERIC_ARG1), \
+ DEFINE_GPR(r4, NULL, LLDB_REGNUM_GENERIC_ARG2), \
+ DEFINE_GPR(r5, NULL, LLDB_REGNUM_GENERIC_ARG3), \
+ DEFINE_GPR(r6, NULL, LLDB_REGNUM_GENERIC_ARG4), \
+ DEFINE_GPR(r7, NULL, LLDB_REGNUM_GENERIC_ARG5), \
+ DEFINE_GPR(r8, NULL, LLDB_REGNUM_GENERIC_ARG6), \
+ DEFINE_GPR(r9, NULL, LLDB_REGNUM_GENERIC_ARG7), \
+ DEFINE_GPR(r10, NULL, LLDB_REGNUM_GENERIC_ARG8), \
+ DEFINE_GPR(r11, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r12, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r13, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r14, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r15, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r16, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r17, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r18, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r19, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r20, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r21, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r22, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r23, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r24, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r25, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r26, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r27, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r28, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r29, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r30, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r31, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(lr, NULL, LLDB_REGNUM_GENERIC_RA), \
+ DEFINE_GPR(cr, NULL, LLDB_REGNUM_GENERIC_FLAGS), \
+ DEFINE_GPR(xer, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(ctr, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(pc, NULL, LLDB_REGNUM_GENERIC_PC), \
+ DEFINE_FPR(f0, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f1, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f2, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f3, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f4, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f5, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f6, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f7, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f8, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f9, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f10, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f11, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f12, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f13, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f14, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f15, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f16, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f17, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f18, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f19, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f20, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f21, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f22, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f23, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f24, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f25, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f26, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f27, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f28, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f29, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f30, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f31, LLDB_INVALID_REGNUM), \
+ {"fpscr", \
+ NULL, \
+ 8, \
+ FPR_OFFSET(fpscr), \
+ eEncodingUint, \
+ eFormatHex, \
+ {dwarf_fpscr_powerpc, dwarf_fpscr_powerpc, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, fpr_fpscr_powerpc}, \
+ NULL, \
+ NULL, \
+ NULL, \
+ }, \
+ DEFINE_VMX(v0, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v1, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v2, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v3, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v4, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v5, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v6, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v7, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v8, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v9, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v10, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v11, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v12, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v13, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v14, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v15, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v16, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v17, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v18, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v19, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v20, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v21, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v22, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v23, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v24, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v25, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v26, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v27, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v28, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v29, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v30, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v31, LLDB_INVALID_REGNUM), \
+ {"vrsave", \
+ NULL, \
+ 4, \
+ VMX_OFFSET(vrsave), \
+ eEncodingUint, \
+ eFormatHex, \
+ {dwarf_vrsave_powerpc, dwarf_vrsave_powerpc, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, vmx_vrsave_powerpc}, \
+ NULL, \
+ NULL, \
+ NULL, \
+ }, \
+ {"vscr", \
+ NULL, \
+ 4, \
+ VMX_OFFSET(vscr), \
+ eEncodingUint, \
+ eFormatHex, \
+ {dwarf_vscr_powerpc, dwarf_vscr_powerpc, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, vmx_vscr_powerpc}, \
+ NULL, \
+ NULL, \
+ NULL, \
+ },
+
+static RegisterInfo g_register_infos_powerpc64[] = {
+#define GPR GPR64
+ POWERPC_REGS
+#undef GPR
+};
+
+static RegisterInfo g_register_infos_powerpc32[] = {
+#define GPR GPR32
+ POWERPC_REGS
+#undef GPR
+};
+
+static RegisterInfo g_register_infos_powerpc64_32[] = {
+#define GPR GPR64
+#undef GPR_SIZE
+#define GPR_SIZE(reg) (sizeof(uint32_t))
+#undef GPR_OFFSET
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname) + (sizeof(((GPR *)NULL)->regname) - GPR_SIZE(reg)))
+ POWERPC_REGS
+#undef GPR
+};
+
+static_assert((sizeof(g_register_infos_powerpc32) /
+ sizeof(g_register_infos_powerpc32[0])) ==
+ k_num_registers_powerpc,
+ "g_register_infos_powerpc32 has wrong number of register infos");
+static_assert((sizeof(g_register_infos_powerpc64) /
+ sizeof(g_register_infos_powerpc64[0])) ==
+ k_num_registers_powerpc,
+ "g_register_infos_powerpc64 has wrong number of register infos");
+static_assert(sizeof(g_register_infos_powerpc64_32) ==
+ sizeof(g_register_infos_powerpc64),
+ "g_register_infos_powerpc64_32 doesn't match size of "
+ "g_register_infos_powerpc64");
+
+#undef DEFINE_FPR
+#undef DEFINE_GPR
+
+#endif // DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+
+#undef GPR_OFFSET
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h
new file mode 100644
index 000000000000..e15e1d5fc4a2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h
@@ -0,0 +1,329 @@
+//===-- RegisterInfos_ppc64.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_PPC64_STRUCT
+
+#include <cstddef>
+
+// Computes the offset of the given GPR_PPC64 in the user data area.
+#define GPR_PPC64_OFFSET(regname) (offsetof(GPR_PPC64, regname))
+#define FPR_PPC64_OFFSET(regname) (offsetof(FPR_PPC64, regname) \
+ + sizeof(GPR_PPC64))
+#define VMX_PPC64_OFFSET(regname) (offsetof(VMX_PPC64, regname) \
+ + sizeof(GPR_PPC64) + sizeof(FPR_PPC64))
+#define GPR_PPC64_SIZE(regname) (sizeof(((GPR_PPC64 *)NULL)->regname))
+
+#include "Utility/PPC64_DWARF_Registers.h"
+#include "lldb-ppc64-register-enums.h"
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR_PPC64(reg, alt, lldb_kind) \
+ { \
+ #reg, alt, GPR_PPC64_SIZE(reg), GPR_PPC64_OFFSET(reg), lldb::eEncodingUint,\
+ lldb::eFormatHex, \
+ {ppc64_dwarf::dwarf_##reg##_ppc64, \
+ ppc64_dwarf::dwarf_##reg##_ppc64, \
+ lldb_kind, \
+ LLDB_INVALID_REGNUM, \
+ gpr_##reg##_ppc64 }, \
+ NULL, NULL, NULL, \
+ }
+#define DEFINE_FPR_PPC64(reg, alt, lldb_kind) \
+ { \
+#reg, alt, 8, FPR_PPC64_OFFSET(reg), lldb::eEncodingIEEE754, \
+ lldb::eFormatFloat, \
+ {ppc64_dwarf::dwarf_##reg##_ppc64, \
+ ppc64_dwarf::dwarf_##reg##_ppc64, lldb_kind, LLDB_INVALID_REGNUM, \
+ fpr_##reg##_ppc64 }, \
+ NULL, NULL, NULL, \
+ }
+#define DEFINE_VMX_PPC64(reg, lldb_kind) \
+ { \
+#reg, NULL, 16, VMX_PPC64_OFFSET(reg), lldb::eEncodingVector, \
+ lldb::eFormatVectorOfUInt32, \
+ {ppc64_dwarf::dwarf_##reg##_ppc64, \
+ ppc64_dwarf::dwarf_##reg##_ppc64, lldb_kind, LLDB_INVALID_REGNUM, \
+ vmx_##reg##_ppc64 }, \
+ NULL, NULL, NULL, \
+ }
+
+// General purpose registers.
+// EH_Frame, Generic, Process Plugin
+#define PPC64_REGS \
+ DEFINE_GPR_PPC64(r0, NULL, LLDB_INVALID_REGNUM) \
+ , DEFINE_GPR_PPC64(r1, NULL, LLDB_REGNUM_GENERIC_SP), \
+ DEFINE_GPR_PPC64(r2, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r3, NULL, LLDB_REGNUM_GENERIC_ARG1), \
+ DEFINE_GPR_PPC64(r4, NULL, LLDB_REGNUM_GENERIC_ARG2), \
+ DEFINE_GPR_PPC64(r5, NULL, LLDB_REGNUM_GENERIC_ARG3), \
+ DEFINE_GPR_PPC64(r6, NULL, LLDB_REGNUM_GENERIC_ARG4), \
+ DEFINE_GPR_PPC64(r7, NULL, LLDB_REGNUM_GENERIC_ARG5), \
+ DEFINE_GPR_PPC64(r8, NULL, LLDB_REGNUM_GENERIC_ARG6), \
+ DEFINE_GPR_PPC64(r9, NULL, LLDB_REGNUM_GENERIC_ARG7), \
+ DEFINE_GPR_PPC64(r10, NULL, LLDB_REGNUM_GENERIC_ARG8), \
+ DEFINE_GPR_PPC64(r11, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r12, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r13, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r14, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r15, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r16, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r17, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r18, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r19, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r20, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r21, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r22, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r23, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r24, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r25, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r26, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r27, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r28, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r29, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r30, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(r31, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(cr, NULL, LLDB_REGNUM_GENERIC_FLAGS), \
+ DEFINE_GPR_PPC64(msr, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(xer, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(lr, NULL, LLDB_REGNUM_GENERIC_RA), \
+ DEFINE_GPR_PPC64(ctr, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR_PPC64(pc, NULL, LLDB_REGNUM_GENERIC_PC), \
+ DEFINE_FPR_PPC64(f0, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f1, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f2, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f3, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f4, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f5, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f6, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f7, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f8, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f9, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f10, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f11, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f12, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f13, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f14, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f15, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f16, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f17, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f18, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f19, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f20, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f21, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f22, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f23, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f24, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f25, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f26, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f27, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f28, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f29, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f30, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR_PPC64(f31, NULL, LLDB_INVALID_REGNUM), \
+ {"fpscr", \
+ NULL, \
+ 8, \
+ FPR_PPC64_OFFSET(fpscr), \
+ lldb::eEncodingUint, \
+ lldb::eFormatHex, \
+ {ppc64_dwarf::dwarf_fpscr_ppc64, \
+ ppc64_dwarf::dwarf_fpscr_ppc64, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, fpr_fpscr_ppc64}, \
+ NULL, \
+ NULL, \
+ NULL, \
+ }, \
+ DEFINE_VMX_PPC64(vr0, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr1, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr2, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr3, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr4, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr5, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr6, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr7, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr8, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr9, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr10, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr11, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr12, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr13, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr14, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr15, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr16, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr17, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr18, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr19, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr20, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr21, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr22, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr23, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr24, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr25, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr26, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr27, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr28, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr29, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr30, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX_PPC64(vr31, LLDB_INVALID_REGNUM), \
+ {"vscr", \
+ NULL, \
+ 4, \
+ VMX_PPC64_OFFSET(vscr), \
+ lldb::eEncodingUint, \
+ lldb::eFormatHex, \
+ {ppc64_dwarf::dwarf_vscr_ppc64, ppc64_dwarf::dwarf_vscr_ppc64, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, vmx_vscr_ppc64}, \
+ NULL, \
+ NULL, \
+ NULL, \
+ }, \
+ {"vrsave", \
+ NULL, \
+ 4, \
+ VMX_PPC64_OFFSET(vrsave), \
+ lldb::eEncodingUint, \
+ lldb::eFormatHex, \
+ {ppc64_dwarf::dwarf_vrsave_ppc64, \
+ ppc64_dwarf::dwarf_vrsave_ppc64, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, vmx_vrsave_ppc64}, \
+ NULL, \
+ NULL, \
+ NULL, \
+ }, /* */
+
+typedef struct _GPR_PPC64 {
+ uint64_t r0;
+ uint64_t r1;
+ uint64_t r2;
+ uint64_t r3;
+ uint64_t r4;
+ uint64_t r5;
+ uint64_t r6;
+ uint64_t r7;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t r16;
+ uint64_t r17;
+ uint64_t r18;
+ uint64_t r19;
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+ uint64_t r28;
+ uint64_t r29;
+ uint64_t r30;
+ uint64_t r31;
+ uint64_t cr;
+ uint64_t msr;
+ uint64_t xer;
+ uint64_t lr;
+ uint64_t ctr;
+ uint64_t pc;
+ uint64_t pad[3];
+} GPR_PPC64;
+
+typedef struct _FPR_PPC64 {
+ uint64_t f0;
+ uint64_t f1;
+ uint64_t f2;
+ uint64_t f3;
+ uint64_t f4;
+ uint64_t f5;
+ uint64_t f6;
+ uint64_t f7;
+ uint64_t f8;
+ uint64_t f9;
+ uint64_t f10;
+ uint64_t f11;
+ uint64_t f12;
+ uint64_t f13;
+ uint64_t f14;
+ uint64_t f15;
+ uint64_t f16;
+ uint64_t f17;
+ uint64_t f18;
+ uint64_t f19;
+ uint64_t f20;
+ uint64_t f21;
+ uint64_t f22;
+ uint64_t f23;
+ uint64_t f24;
+ uint64_t f25;
+ uint64_t f26;
+ uint64_t f27;
+ uint64_t f28;
+ uint64_t f29;
+ uint64_t f30;
+ uint64_t f31;
+ uint64_t fpscr;
+} FPR_PPC64;
+
+typedef struct _VMX_PPC64 {
+ uint32_t vr0[4];
+ uint32_t vr1[4];
+ uint32_t vr2[4];
+ uint32_t vr3[4];
+ uint32_t vr4[4];
+ uint32_t vr5[4];
+ uint32_t vr6[4];
+ uint32_t vr7[4];
+ uint32_t vr8[4];
+ uint32_t vr9[4];
+ uint32_t vr10[4];
+ uint32_t vr11[4];
+ uint32_t vr12[4];
+ uint32_t vr13[4];
+ uint32_t vr14[4];
+ uint32_t vr15[4];
+ uint32_t vr16[4];
+ uint32_t vr17[4];
+ uint32_t vr18[4];
+ uint32_t vr19[4];
+ uint32_t vr20[4];
+ uint32_t vr21[4];
+ uint32_t vr22[4];
+ uint32_t vr23[4];
+ uint32_t vr24[4];
+ uint32_t vr25[4];
+ uint32_t vr26[4];
+ uint32_t vr27[4];
+ uint32_t vr28[4];
+ uint32_t vr29[4];
+ uint32_t vr30[4];
+ uint32_t vr31[4];
+ uint32_t pad[2];
+ uint32_t vscr[2];
+ uint32_t vrsave;
+} VMX_PPC64;
+
+
+static lldb_private::RegisterInfo g_register_infos_ppc64[] = {
+ PPC64_REGS
+};
+
+static_assert((sizeof(g_register_infos_ppc64) /
+ sizeof(g_register_infos_ppc64[0])) ==
+ k_num_registers_ppc64,
+ "g_register_infos_powerpc64 has wrong number of register infos");
+
+#undef DEFINE_FPR_PPC64
+#undef DEFINE_GPR_PPC64
+#undef DEFINE_VMX_PPC64
+
+#endif // DECLARE_REGISTER_INFOS_PPC64_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h
new file mode 100644
index 000000000000..18489fb74f86
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h
@@ -0,0 +1,474 @@
+//===-- RegisterInfos_ppc64le.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
+
+#include <cstddef>
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) (offsetof(GPR, regname))
+#define FPR_OFFSET(regname) (offsetof(FPR, regname) + sizeof(GPR))
+#define VMX_OFFSET(regname) (offsetof(VMX, regname) + sizeof(GPR) + sizeof(FPR))
+#define VSX_OFFSET(regname) \
+ (offsetof(VSX, regname) + sizeof(GPR) + sizeof(FPR) + sizeof(VMX))
+#define GPR_SIZE(regname) (sizeof(((GPR *)NULL)->regname))
+
+#include "Utility/PPC64LE_DWARF_Registers.h"
+#include "lldb-ppc64le-register-enums.h"
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, lldb_kind) \
+ { \
+ #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), lldb::eEncodingUint, \
+ lldb::eFormatHex, \
+ {ppc64le_dwarf::dwarf_##reg##_ppc64le,\
+ ppc64le_dwarf::dwarf_##reg##_ppc64le,\
+ lldb_kind, \
+ LLDB_INVALID_REGNUM, \
+ gpr_##reg##_ppc64le }, \
+ NULL, NULL, NULL, \
+ }
+#define DEFINE_FPR(reg, alt, lldb_kind) \
+ { \
+#reg, alt, 8, FPR_OFFSET(reg), lldb::eEncodingIEEE754, lldb::eFormatFloat, \
+ {ppc64le_dwarf::dwarf_##reg##_ppc64le, \
+ ppc64le_dwarf::dwarf_##reg##_ppc64le, lldb_kind, LLDB_INVALID_REGNUM, \
+ fpr_##reg##_ppc64le }, \
+ NULL, NULL, NULL, \
+ }
+#define DEFINE_VMX(reg, lldb_kind) \
+ { \
+#reg, NULL, 16, VMX_OFFSET(reg), lldb::eEncodingVector, \
+ lldb::eFormatVectorOfUInt32, \
+ {ppc64le_dwarf::dwarf_##reg##_ppc64le, \
+ ppc64le_dwarf::dwarf_##reg##_ppc64le, lldb_kind, LLDB_INVALID_REGNUM, \
+ vmx_##reg##_ppc64le }, \
+ NULL, NULL, NULL, \
+ }
+#define DEFINE_VSX(reg, lldb_kind) \
+ { \
+#reg, NULL, 16, VSX_OFFSET(reg), lldb::eEncodingVector, \
+ lldb::eFormatVectorOfUInt32, \
+ {ppc64le_dwarf::dwarf_##reg##_ppc64le, \
+ ppc64le_dwarf::dwarf_##reg##_ppc64le, lldb_kind, LLDB_INVALID_REGNUM, \
+ vsx_##reg##_ppc64le }, \
+ NULL, NULL, NULL, \
+ }
+
+// General purpose registers.
+// EH_Frame, Generic, Process Plugin
+#define POWERPC_REGS \
+ DEFINE_GPR(r0, NULL, LLDB_INVALID_REGNUM) \
+ , DEFINE_GPR(r1, NULL, LLDB_REGNUM_GENERIC_SP), \
+ DEFINE_GPR(r2, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r3, NULL, LLDB_REGNUM_GENERIC_ARG1), \
+ DEFINE_GPR(r4, NULL, LLDB_REGNUM_GENERIC_ARG2), \
+ DEFINE_GPR(r5, NULL, LLDB_REGNUM_GENERIC_ARG3), \
+ DEFINE_GPR(r6, NULL, LLDB_REGNUM_GENERIC_ARG4), \
+ DEFINE_GPR(r7, NULL, LLDB_REGNUM_GENERIC_ARG5), \
+ DEFINE_GPR(r8, NULL, LLDB_REGNUM_GENERIC_ARG6), \
+ DEFINE_GPR(r9, NULL, LLDB_REGNUM_GENERIC_ARG7), \
+ DEFINE_GPR(r10, NULL, LLDB_REGNUM_GENERIC_ARG8), \
+ DEFINE_GPR(r11, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r12, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r13, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r14, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r15, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r16, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r17, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r18, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r19, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r20, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r21, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r22, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r23, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r24, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r25, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r26, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r27, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r28, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r29, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r30, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r31, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(pc, NULL, LLDB_REGNUM_GENERIC_PC), \
+ DEFINE_GPR(msr, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(origr3, "orig_r3", LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(ctr, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(lr, NULL, LLDB_REGNUM_GENERIC_RA), \
+ DEFINE_GPR(xer, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(cr, NULL, LLDB_REGNUM_GENERIC_FLAGS), \
+ DEFINE_GPR(softe, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(trap, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f0, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f1, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f2, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f3, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f4, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f5, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f6, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f7, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f8, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f9, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f10, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f11, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f12, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f13, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f14, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f15, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f16, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f17, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f18, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f19, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f20, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f21, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f22, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f23, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f24, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f25, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f26, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f27, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f28, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f29, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f30, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f31, NULL, LLDB_INVALID_REGNUM), \
+ {"fpscr", \
+ NULL, \
+ 8, \
+ FPR_OFFSET(fpscr), \
+ lldb::eEncodingUint, \
+ lldb::eFormatHex, \
+ {ppc64le_dwarf::dwarf_fpscr_ppc64le, \
+ ppc64le_dwarf::dwarf_fpscr_ppc64le, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, fpr_fpscr_ppc64le}, \
+ NULL, \
+ NULL, \
+ NULL, \
+ }, \
+ DEFINE_VMX(vr0, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr1, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr2, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr3, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr4, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr5, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr6, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr7, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr8, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr9, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr10, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr11, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr12, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr13, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr14, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr15, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr16, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr17, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr18, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr19, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr20, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr21, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr22, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr23, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr24, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr25, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr26, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr27, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr28, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr29, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr30, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(vr31, LLDB_INVALID_REGNUM), \
+ {"vscr", \
+ NULL, \
+ 4, \
+ VMX_OFFSET(vscr), \
+ lldb::eEncodingUint, \
+ lldb::eFormatHex, \
+ {ppc64le_dwarf::dwarf_vscr_ppc64le, ppc64le_dwarf::dwarf_vscr_ppc64le, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, vmx_vscr_ppc64le}, \
+ NULL, \
+ NULL, \
+ NULL, \
+ }, \
+ {"vrsave", \
+ NULL, \
+ 4, \
+ VMX_OFFSET(vrsave), \
+ lldb::eEncodingUint, \
+ lldb::eFormatHex, \
+ {ppc64le_dwarf::dwarf_vrsave_ppc64le, \
+ ppc64le_dwarf::dwarf_vrsave_ppc64le, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, vmx_vrsave_ppc64le}, \
+ NULL, \
+ NULL, \
+ NULL, \
+ }, \
+ DEFINE_VSX(vs0, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs1, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs2, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs3, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs4, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs5, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs6, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs7, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs8, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs9, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs10, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs11, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs12, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs13, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs14, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs15, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs16, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs17, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs18, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs19, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs20, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs21, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs22, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs23, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs24, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs25, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs26, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs27, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs28, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs29, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs30, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs31, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs32, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs33, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs34, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs35, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs36, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs37, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs38, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs39, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs40, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs41, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs42, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs43, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs44, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs45, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs46, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs47, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs48, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs49, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs50, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs51, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs52, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs53, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs54, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs55, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs56, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs57, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs58, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs59, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs50, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs61, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs62, LLDB_INVALID_REGNUM), \
+ DEFINE_VSX(vs63, LLDB_INVALID_REGNUM), /* */
+
+typedef struct _GPR {
+ uint64_t r0;
+ uint64_t r1;
+ uint64_t r2;
+ uint64_t r3;
+ uint64_t r4;
+ uint64_t r5;
+ uint64_t r6;
+ uint64_t r7;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t r16;
+ uint64_t r17;
+ uint64_t r18;
+ uint64_t r19;
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+ uint64_t r28;
+ uint64_t r29;
+ uint64_t r30;
+ uint64_t r31;
+ uint64_t pc;
+ uint64_t msr;
+ uint64_t origr3;
+ uint64_t ctr;
+ uint64_t lr;
+ uint64_t xer;
+ uint64_t cr;
+ uint64_t softe;
+ uint64_t trap;
+ uint64_t pad[3];
+} GPR;
+
+typedef struct _FPR {
+ uint64_t f0;
+ uint64_t f1;
+ uint64_t f2;
+ uint64_t f3;
+ uint64_t f4;
+ uint64_t f5;
+ uint64_t f6;
+ uint64_t f7;
+ uint64_t f8;
+ uint64_t f9;
+ uint64_t f10;
+ uint64_t f11;
+ uint64_t f12;
+ uint64_t f13;
+ uint64_t f14;
+ uint64_t f15;
+ uint64_t f16;
+ uint64_t f17;
+ uint64_t f18;
+ uint64_t f19;
+ uint64_t f20;
+ uint64_t f21;
+ uint64_t f22;
+ uint64_t f23;
+ uint64_t f24;
+ uint64_t f25;
+ uint64_t f26;
+ uint64_t f27;
+ uint64_t f28;
+ uint64_t f29;
+ uint64_t f30;
+ uint64_t f31;
+ uint64_t fpscr;
+} FPR;
+
+typedef struct _VMX {
+ uint32_t vr0[4];
+ uint32_t vr1[4];
+ uint32_t vr2[4];
+ uint32_t vr3[4];
+ uint32_t vr4[4];
+ uint32_t vr5[4];
+ uint32_t vr6[4];
+ uint32_t vr7[4];
+ uint32_t vr8[4];
+ uint32_t vr9[4];
+ uint32_t vr10[4];
+ uint32_t vr11[4];
+ uint32_t vr12[4];
+ uint32_t vr13[4];
+ uint32_t vr14[4];
+ uint32_t vr15[4];
+ uint32_t vr16[4];
+ uint32_t vr17[4];
+ uint32_t vr18[4];
+ uint32_t vr19[4];
+ uint32_t vr20[4];
+ uint32_t vr21[4];
+ uint32_t vr22[4];
+ uint32_t vr23[4];
+ uint32_t vr24[4];
+ uint32_t vr25[4];
+ uint32_t vr26[4];
+ uint32_t vr27[4];
+ uint32_t vr28[4];
+ uint32_t vr29[4];
+ uint32_t vr30[4];
+ uint32_t vr31[4];
+ uint32_t pad[2];
+ uint32_t vscr[2];
+ uint32_t vrsave;
+} VMX;
+
+typedef struct _VSX {
+ uint32_t vs0[4];
+ uint32_t vs1[4];
+ uint32_t vs2[4];
+ uint32_t vs3[4];
+ uint32_t vs4[4];
+ uint32_t vs5[4];
+ uint32_t vs6[4];
+ uint32_t vs7[4];
+ uint32_t vs8[4];
+ uint32_t vs9[4];
+ uint32_t vs10[4];
+ uint32_t vs11[4];
+ uint32_t vs12[4];
+ uint32_t vs13[4];
+ uint32_t vs14[4];
+ uint32_t vs15[4];
+ uint32_t vs16[4];
+ uint32_t vs17[4];
+ uint32_t vs18[4];
+ uint32_t vs19[4];
+ uint32_t vs20[4];
+ uint32_t vs21[4];
+ uint32_t vs22[4];
+ uint32_t vs23[4];
+ uint32_t vs24[4];
+ uint32_t vs25[4];
+ uint32_t vs26[4];
+ uint32_t vs27[4];
+ uint32_t vs28[4];
+ uint32_t vs29[4];
+ uint32_t vs30[4];
+ uint32_t vs31[4];
+ uint32_t vs32[4];
+ uint32_t vs33[4];
+ uint32_t vs34[4];
+ uint32_t vs35[4];
+ uint32_t vs36[4];
+ uint32_t vs37[4];
+ uint32_t vs38[4];
+ uint32_t vs39[4];
+ uint32_t vs40[4];
+ uint32_t vs41[4];
+ uint32_t vs42[4];
+ uint32_t vs43[4];
+ uint32_t vs44[4];
+ uint32_t vs45[4];
+ uint32_t vs46[4];
+ uint32_t vs47[4];
+ uint32_t vs48[4];
+ uint32_t vs49[4];
+ uint32_t vs50[4];
+ uint32_t vs51[4];
+ uint32_t vs52[4];
+ uint32_t vs53[4];
+ uint32_t vs54[4];
+ uint32_t vs55[4];
+ uint32_t vs56[4];
+ uint32_t vs57[4];
+ uint32_t vs58[4];
+ uint32_t vs59[4];
+ uint32_t vs60[4];
+ uint32_t vs61[4];
+ uint32_t vs62[4];
+ uint32_t vs63[4];
+} VSX;
+
+static lldb_private::RegisterInfo g_register_infos_ppc64le[] = {
+ POWERPC_REGS
+};
+
+static_assert((sizeof(g_register_infos_ppc64le) /
+ sizeof(g_register_infos_ppc64le[0])) ==
+ k_num_registers_ppc64le,
+ "g_register_infos_powerpc64 has wrong number of register infos");
+
+#undef DEFINE_FPR
+#undef DEFINE_GPR
+#undef DEFINE_VMX
+#undef DEFINE_VSX
+
+#endif // DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv64.h
new file mode 100644
index 000000000000..720d900c7b97
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv64.h
@@ -0,0 +1,186 @@
+//===-- RegisterInfos_riscv64.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_RISCV64_STRUCT
+
+#include <stddef.h>
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private.h"
+
+#include "Utility/RISCV_DWARF_Registers.h"
+#include "lldb-riscv-register-enums.h"
+
+#ifndef GPR_OFFSET
+#error GPR_OFFSET must be defined before including this header file
+#endif
+
+#ifndef FPR_OFFSET
+#error FPR_OFFSET must be defined before including this header file
+#endif
+
+using namespace riscv_dwarf;
+
+// clang-format off
+
+// I suppose EHFrame and DWARF are the same.
+#define KIND_HELPER(reg, generic_kind) \
+ { \
+ riscv_dwarf::dwarf_##reg, riscv_dwarf::dwarf_##reg, generic_kind, \
+ LLDB_INVALID_REGNUM, reg##_riscv \
+ }
+
+// Generates register kinds array for vector registers
+#define GPR64_KIND(reg, generic_kind) KIND_HELPER(reg, generic_kind)
+
+// FPR register kinds array for vector registers
+#define FPR64_KIND(reg, generic_kind) KIND_HELPER(reg, generic_kind)
+
+// VPR register kinds array for vector registers
+#define VPR_KIND(reg, generic_kind) KIND_HELPER(reg, generic_kind)
+
+// Defines a 64-bit general purpose register
+#define DEFINE_GPR64(reg, generic_kind) DEFINE_GPR64_ALT(reg, reg, generic_kind)
+
+// Defines a 64-bit general purpose register
+#define DEFINE_GPR64_ALT(reg, alt, generic_kind) \
+ { \
+ #reg, #alt, 8, GPR_OFFSET(gpr_##reg##_riscv - gpr_first_riscv), \
+ lldb::eEncodingUint, lldb::eFormatHex, \
+ GPR64_KIND(gpr_##reg, generic_kind), nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_FPR64(reg, generic_kind) DEFINE_FPR64_ALT(reg, reg, generic_kind)
+
+#define DEFINE_FPR64_ALT(reg, alt, generic_kind) DEFINE_FPR_ALT(reg, alt, 8, generic_kind)
+
+#define DEFINE_FPR_ALT(reg, alt, size, generic_kind) \
+ { \
+ #reg, #alt, size, FPR_OFFSET(fpr_##reg##_riscv - fpr_first_riscv), \
+ lldb::eEncodingUint, lldb::eFormatHex, \
+ FPR64_KIND(fpr_##reg, generic_kind), nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_VPR(reg, generic_kind) DEFINE_VPR_ALT(reg, reg, generic_kind)
+
+// Defines a scalable vector register, with default size 128 bits
+// The byte offset 0 is a placeholder, which should be corrected at runtime.
+#define DEFINE_VPR_ALT(reg, alt, generic_kind) \
+ { \
+ #reg, #alt, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \
+ VPR_KIND(vpr_##reg, generic_kind), nullptr, nullptr, nullptr \
+ }
+
+// clang-format on
+
+static lldb_private::RegisterInfo g_register_infos_riscv64_le[] = {
+ // DEFINE_GPR64(name, GENERIC KIND)
+ DEFINE_GPR64(pc, LLDB_REGNUM_GENERIC_PC),
+ DEFINE_GPR64_ALT(ra, x1, LLDB_REGNUM_GENERIC_RA),
+ DEFINE_GPR64_ALT(sp, x2, LLDB_REGNUM_GENERIC_SP),
+ DEFINE_GPR64_ALT(gp, x3, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(tp, x4, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(t0, x5, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(t1, x6, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(t2, x7, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(fp, x8, LLDB_REGNUM_GENERIC_FP),
+ DEFINE_GPR64_ALT(s1, x9, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(a0, x10, LLDB_REGNUM_GENERIC_ARG1),
+ DEFINE_GPR64_ALT(a1, x11, LLDB_REGNUM_GENERIC_ARG2),
+ DEFINE_GPR64_ALT(a2, x12, LLDB_REGNUM_GENERIC_ARG3),
+ DEFINE_GPR64_ALT(a3, x13, LLDB_REGNUM_GENERIC_ARG4),
+ DEFINE_GPR64_ALT(a4, x14, LLDB_REGNUM_GENERIC_ARG5),
+ DEFINE_GPR64_ALT(a5, x15, LLDB_REGNUM_GENERIC_ARG6),
+ DEFINE_GPR64_ALT(a6, x16, LLDB_REGNUM_GENERIC_ARG7),
+ DEFINE_GPR64_ALT(a7, x17, LLDB_REGNUM_GENERIC_ARG8),
+ DEFINE_GPR64_ALT(s2, x18, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(s3, x19, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(s4, x20, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(s5, x21, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(s6, x22, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(s7, x23, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(s8, x24, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(s9, x25, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(s10, x26, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(s11, x27, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(t3, x28, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(t4, x29, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(t5, x30, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(t6, x31, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64_ALT(zero, x0, LLDB_INVALID_REGNUM),
+
+ DEFINE_FPR64_ALT(ft0, f0, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft1, f1, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft2, f2, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft3, f3, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft4, f4, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft5, f5, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft6, f6, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft7, f7, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs0, f8, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs1, f9, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fa0, f10, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fa1, f11, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fa2, f12, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fa3, f13, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fa4, f14, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fa5, f15, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fa6, f16, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fa7, f17, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs2, f18, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs3, f19, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs4, f20, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs5, f21, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs6, f22, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs7, f23, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs8, f24, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs9, f25, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs10, f26, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(fs11, f27, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft8, f28, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft9, f29, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft10, f30, LLDB_INVALID_REGNUM),
+ DEFINE_FPR64_ALT(ft11, f31, LLDB_INVALID_REGNUM),
+ DEFINE_FPR_ALT(fcsr, nullptr, 4, LLDB_INVALID_REGNUM),
+
+ DEFINE_VPR(v0, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v1, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v2, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v3, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v4, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v5, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v6, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v7, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v8, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v9, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v10, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v11, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v12, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v13, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v14, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v15, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v16, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v17, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v18, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v19, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v20, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v21, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v22, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v23, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v24, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v25, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v26, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v27, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v28, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v29, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v30, LLDB_INVALID_REGNUM),
+ DEFINE_VPR(v31, LLDB_INVALID_REGNUM),
+};
+
+#endif // DECLARE_REGISTER_INFOS_RISCV64_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_s390x.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_s390x.h
new file mode 100644
index 000000000000..7b5f204ebbad
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_s390x.h
@@ -0,0 +1,124 @@
+//===-- RegisterInfos_s390x.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstddef>
+
+#include "llvm/Support/Compiler.h"
+
+
+#ifdef DECLARE_REGISTER_INFOS_S390X_STRUCT
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(num) (16 + 8 * num)
+// Computes the offset of the given ACR in the user data area.
+#define ACR_OFFSET(num) (16 + 8 * 16 + 4 * num)
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(num) (8 + 8 * num)
+
+// RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB
+
+#define DEFINE_GPR(name, size, offset, alt, generic) \
+ { \
+ #name, alt, size, offset, eEncodingUint, eFormatHex, \
+ {dwarf_##name##_s390x, dwarf_##name##_s390x, generic, \
+ LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \
+ NULL, NULL, NULL, \
+ }
+
+#define DEFINE_GPR_NODWARF(name, size, offset, alt, generic) \
+ { \
+ #name, alt, size, offset, eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, generic, \
+ LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \
+ NULL, NULL, NULL, \
+ }
+
+#define DEFINE_FPR(name, size, offset) \
+ { \
+ #name, NULL, size, offset, eEncodingUint, eFormatHex, \
+ {dwarf_##name##_s390x, dwarf_##name##_s390x, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \
+ NULL, NULL, NULL, \
+ }
+
+#define DEFINE_FPR_NODWARF(name, size, offset) \
+ { \
+ #name, NULL, size, offset, eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \
+ NULL, NULL, NULL, \
+ }
+
+static RegisterInfo g_register_infos_s390x[] = {
+ // General purpose registers.
+ DEFINE_GPR(r0, 8, GPR_OFFSET(0), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r1, 8, GPR_OFFSET(1), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r2, 8, GPR_OFFSET(2), nullptr, LLDB_REGNUM_GENERIC_ARG1),
+ DEFINE_GPR(r3, 8, GPR_OFFSET(3), nullptr, LLDB_REGNUM_GENERIC_ARG2),
+ DEFINE_GPR(r4, 8, GPR_OFFSET(4), nullptr, LLDB_REGNUM_GENERIC_ARG3),
+ DEFINE_GPR(r5, 8, GPR_OFFSET(5), nullptr, LLDB_REGNUM_GENERIC_ARG4),
+ DEFINE_GPR(r6, 8, GPR_OFFSET(6), nullptr, LLDB_REGNUM_GENERIC_ARG5),
+ DEFINE_GPR(r7, 8, GPR_OFFSET(7), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r8, 8, GPR_OFFSET(8), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r9, 8, GPR_OFFSET(9), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r10, 8, GPR_OFFSET(10), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r11, 8, GPR_OFFSET(11), nullptr, LLDB_REGNUM_GENERIC_FP),
+ DEFINE_GPR(r12, 8, GPR_OFFSET(12), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r13, 8, GPR_OFFSET(13), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r14, 8, GPR_OFFSET(14), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r15, 8, GPR_OFFSET(15), nullptr, LLDB_REGNUM_GENERIC_SP),
+ DEFINE_GPR(acr0, 4, ACR_OFFSET(0), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr1, 4, ACR_OFFSET(1), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr2, 4, ACR_OFFSET(2), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr3, 4, ACR_OFFSET(3), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr4, 4, ACR_OFFSET(4), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr5, 4, ACR_OFFSET(5), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr6, 4, ACR_OFFSET(6), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr7, 4, ACR_OFFSET(7), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr8, 4, ACR_OFFSET(8), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr9, 4, ACR_OFFSET(9), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr10, 4, ACR_OFFSET(10), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr11, 4, ACR_OFFSET(11), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr12, 4, ACR_OFFSET(12), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr13, 4, ACR_OFFSET(13), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr14, 4, ACR_OFFSET(14), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(acr15, 4, ACR_OFFSET(15), nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(pswm, 8, 0, nullptr, LLDB_REGNUM_GENERIC_FLAGS),
+ DEFINE_GPR(pswa, 8, 8, nullptr, LLDB_REGNUM_GENERIC_PC),
+
+ // Floating point registers.
+ DEFINE_FPR(f0, 8, FPR_OFFSET(0)), DEFINE_FPR(f1, 8, FPR_OFFSET(1)),
+ DEFINE_FPR(f2, 8, FPR_OFFSET(2)), DEFINE_FPR(f3, 8, FPR_OFFSET(3)),
+ DEFINE_FPR(f4, 8, FPR_OFFSET(4)), DEFINE_FPR(f5, 8, FPR_OFFSET(5)),
+ DEFINE_FPR(f6, 8, FPR_OFFSET(6)), DEFINE_FPR(f7, 8, FPR_OFFSET(7)),
+ DEFINE_FPR(f8, 8, FPR_OFFSET(8)), DEFINE_FPR(f9, 8, FPR_OFFSET(9)),
+ DEFINE_FPR(f10, 8, FPR_OFFSET(10)), DEFINE_FPR(f11, 8, FPR_OFFSET(11)),
+ DEFINE_FPR(f12, 8, FPR_OFFSET(12)), DEFINE_FPR(f13, 8, FPR_OFFSET(13)),
+ DEFINE_FPR(f14, 8, FPR_OFFSET(14)), DEFINE_FPR(f15, 8, FPR_OFFSET(15)),
+ DEFINE_FPR_NODWARF(fpc, 4, 0),
+
+ // Linux operating-specific info.
+ DEFINE_GPR_NODWARF(orig_r2, 8, 16 + 16 * 8 + 16 * 4, nullptr,
+ LLDB_INVALID_REGNUM),
+ DEFINE_GPR_NODWARF(last_break, 8, 0, nullptr, LLDB_INVALID_REGNUM),
+ DEFINE_GPR_NODWARF(system_call, 4, 0, nullptr, LLDB_INVALID_REGNUM),
+};
+
+static_assert((sizeof(g_register_infos_s390x) /
+ sizeof(g_register_infos_s390x[0])) == k_num_registers_s390x,
+ "g_register_infos_s390x has wrong number of register infos");
+
+#undef GPR_OFFSET
+#undef ACR_OFFSET
+#undef FPR_OFFSET
+#undef DEFINE_GPR
+#undef DEFINE_GPR_NODWARF
+#undef DEFINE_FPR
+#undef DEFINE_FPR_NODWARF
+
+#endif // DECLARE_REGISTER_INFOS_S390X_STRUCT
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
new file mode 100644
index 000000000000..163438158155
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
@@ -0,0 +1,486 @@
+//===-- RegisterInfos_x86_64.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This file is meant to be textually included. Do not #include modular
+// headers here.
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) (LLVM_EXTENSION offsetof(GPR, regname))
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, fxsave) + \
+ LLVM_EXTENSION offsetof(FXSAVE, regname))
+
+// Computes the offset of the YMM register assembled from register halves.
+// Based on DNBArchImplX86_64.cpp from debugserver
+#define YMM_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, xsave) + \
+ LLVM_EXTENSION offsetof(XSAVE, ymmh[0]) + (32 * reg_index))
+
+// Guarantees BNDR/BNDC offsets do not overlap with YMM offsets.
+#define GDB_REMOTE_OFFSET 128
+
+#define BNDR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, xsave) + \
+ LLVM_EXTENSION offsetof(XSAVE, mpxr[reg_index]) + GDB_REMOTE_OFFSET)
+
+#define BNDC_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, xsave) + \
+ LLVM_EXTENSION offsetof(XSAVE, mpxc[reg_index]) + GDB_REMOTE_OFFSET)
+
+#ifdef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+// Number of bytes needed to represent a FPR.
+#define FPR_SIZE(reg) sizeof(((FXSAVE *)nullptr)->reg)
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((MMSReg *)nullptr)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(XMMReg)
+
+// Number of bytes needed to represent a YMM register.
+#define YMM_SIZE sizeof(YMMReg)
+
+// Number of bytes needed to represent MPX registers.
+#define BNDR_SIZE sizeof(MPXReg)
+#define BNDC_SIZE sizeof(MPXCsr)
+
+#define DR_SIZE sizeof(((DBG *)nullptr)->dr[0])
+
+// RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { \
+ #reg, alt, sizeof(((GPR *)nullptr)->reg), \
+ GPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, kind4, \
+ lldb_##reg##_x86_64 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \
+ { \
+ #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, kind4, \
+ lldb_##name##_x86_64 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_FP_ST(reg, i) \
+ { \
+ #reg #i, nullptr, FP_SIZE, \
+ LLVM_EXTENSION FPR_OFFSET( \
+ stmm[i]), eEncodingVector, eFormatVectorOfUInt8, \
+ {dwarf_st##i##_x86_64, dwarf_st##i##_x86_64, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_st##i##_x86_64 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_FP_MM(reg, i, streg) \
+ { \
+ #reg #i, nullptr, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
+ eEncodingUint, eFormatHex, \
+ {dwarf_mm##i##_x86_64, dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_mm##i##_x86_64 }, \
+ RegisterContextPOSIX_x86::g_contained_##streg##_64, \
+ RegisterContextPOSIX_x86::g_invalidate_##streg##_64, \
+ nullptr, \
+ }
+
+#define DEFINE_XMM(reg, i) \
+ { \
+ #reg #i, nullptr, XMM_SIZE, \
+ LLVM_EXTENSION FPR_OFFSET( \
+ reg[i]), eEncodingVector, eFormatVectorOfUInt8, \
+ {dwarf_##reg##i##_x86_64, dwarf_##reg##i##_x86_64, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg##i##_x86_64 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_YMM(reg, i) \
+ { \
+ #reg #i, nullptr, YMM_SIZE, \
+ LLVM_EXTENSION YMM_OFFSET(i), eEncodingVector, eFormatVectorOfUInt8, \
+ {dwarf_##reg##i##h_x86_64, \
+ dwarf_##reg##i##h_x86_64, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg##i##_x86_64 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_BNDR(reg, i) \
+ { \
+ #reg #i, nullptr, BNDR_SIZE, \
+ LLVM_EXTENSION BNDR_OFFSET(i), eEncodingVector, eFormatVectorOfUInt64, \
+ {dwarf_##reg##i##_x86_64, \
+ dwarf_##reg##i##_x86_64, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg##i##_x86_64 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_BNDC(name, i) \
+ { \
+ #name, nullptr, BNDC_SIZE, \
+ LLVM_EXTENSION BNDC_OFFSET(i), eEncodingVector, eFormatVectorOfUInt8, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_##name##_x86_64 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_DR(reg, i) \
+ { \
+ #reg #i, nullptr, DR_SIZE, \
+ DR_OFFSET(i), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg##i##_x86_64 }, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_32(reg32, reg64) \
+ { \
+ #reg32, nullptr, 4, \
+ GPR_OFFSET(reg64), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg32##_x86_64 }, \
+ RegisterContextPOSIX_x86::g_contained_##reg64, \
+ RegisterContextPOSIX_x86::g_invalidate_##reg64, \
+ nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_16(reg16, reg64) \
+ { \
+ #reg16, nullptr, 2, \
+ GPR_OFFSET(reg64), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg16##_x86_64 }, \
+ RegisterContextPOSIX_x86::g_contained_##reg64, \
+ RegisterContextPOSIX_x86::g_invalidate_##reg64, \
+ nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_8H(reg8, reg64) \
+ { \
+ #reg8, nullptr, 1, \
+ GPR_OFFSET(reg64) + 1, eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg8##_x86_64 }, \
+ RegisterContextPOSIX_x86::g_contained_##reg64, \
+ RegisterContextPOSIX_x86::g_invalidate_##reg64, \
+ nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_8L(reg8, reg64) \
+ { \
+ #reg8, nullptr, 1, \
+ GPR_OFFSET(reg64), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ lldb_##reg8##_x86_64 }, \
+ RegisterContextPOSIX_x86::g_contained_##reg64, \
+ RegisterContextPOSIX_x86::g_invalidate_##reg64, \
+ nullptr \
+ }
+
+#define DEFINE_FPR_32(name, reg, kind1, kind2, kind3, kind4, reg64) \
+ { \
+ #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, kind4, lldb_##name##_x86_64 }, \
+ RegisterContextPOSIX_x86::g_contained_##reg64, \
+ RegisterContextPOSIX_x86::g_invalidate_##reg64, \
+ nullptr, \
+ }
+
+// clang-format off
+static RegisterInfo g_register_infos_x86_64[] = {
+// General purpose registers EH_Frame DWARF Generic Process Plugin
+// =========================== ================== ================ ========================= ====================
+ DEFINE_GPR(rax, nullptr, dwarf_rax_x86_64, dwarf_rax_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rbx, nullptr, dwarf_rbx_x86_64, dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rcx, nullptr, dwarf_rcx_x86_64, dwarf_rcx_x86_64, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rdx, nullptr, dwarf_rdx_x86_64, dwarf_rdx_x86_64, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rdi, nullptr, dwarf_rdi_x86_64, dwarf_rdi_x86_64, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rsi, nullptr, dwarf_rsi_x86_64, dwarf_rsi_x86_64, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rbp, nullptr, dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rsp, nullptr, dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r8, nullptr, dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r9, nullptr, dwarf_r9_x86_64, dwarf_r9_x86_64, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r10, nullptr, dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r11, nullptr, dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r12, nullptr, dwarf_r12_x86_64, dwarf_r12_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r13, nullptr, dwarf_r13_x86_64, dwarf_r13_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r14, nullptr, dwarf_r14_x86_64, dwarf_r14_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r15, nullptr, dwarf_r15_x86_64, dwarf_r15_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rip, nullptr, dwarf_rip_x86_64, dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rflags, nullptr, dwarf_rflags_x86_64, dwarf_rflags_x86_64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(cs, nullptr, dwarf_cs_x86_64, dwarf_cs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(fs, nullptr, dwarf_fs_x86_64, dwarf_fs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(gs, nullptr, dwarf_gs_x86_64, dwarf_gs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ss, nullptr, dwarf_ss_x86_64, dwarf_ss_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ds, nullptr, dwarf_ds_x86_64, dwarf_ds_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(es, nullptr, dwarf_es_x86_64, dwarf_es_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ DEFINE_GPR_PSEUDO_32(eax, rax), DEFINE_GPR_PSEUDO_32(ebx, rbx),
+ DEFINE_GPR_PSEUDO_32(ecx, rcx), DEFINE_GPR_PSEUDO_32(edx, rdx),
+ DEFINE_GPR_PSEUDO_32(edi, rdi), DEFINE_GPR_PSEUDO_32(esi, rsi),
+ DEFINE_GPR_PSEUDO_32(ebp, rbp), DEFINE_GPR_PSEUDO_32(esp, rsp),
+ DEFINE_GPR_PSEUDO_32(r8d, r8), DEFINE_GPR_PSEUDO_32(r9d, r9),
+ DEFINE_GPR_PSEUDO_32(r10d, r10), DEFINE_GPR_PSEUDO_32(r11d, r11),
+ DEFINE_GPR_PSEUDO_32(r12d, r12), DEFINE_GPR_PSEUDO_32(r13d, r13),
+ DEFINE_GPR_PSEUDO_32(r14d, r14), DEFINE_GPR_PSEUDO_32(r15d, r15),
+ DEFINE_GPR_PSEUDO_16(ax, rax), DEFINE_GPR_PSEUDO_16(bx, rbx),
+ DEFINE_GPR_PSEUDO_16(cx, rcx), DEFINE_GPR_PSEUDO_16(dx, rdx),
+ DEFINE_GPR_PSEUDO_16(di, rdi), DEFINE_GPR_PSEUDO_16(si, rsi),
+ DEFINE_GPR_PSEUDO_16(bp, rbp), DEFINE_GPR_PSEUDO_16(sp, rsp),
+ DEFINE_GPR_PSEUDO_16(r8w, r8), DEFINE_GPR_PSEUDO_16(r9w, r9),
+ DEFINE_GPR_PSEUDO_16(r10w, r10), DEFINE_GPR_PSEUDO_16(r11w, r11),
+ DEFINE_GPR_PSEUDO_16(r12w, r12), DEFINE_GPR_PSEUDO_16(r13w, r13),
+ DEFINE_GPR_PSEUDO_16(r14w, r14), DEFINE_GPR_PSEUDO_16(r15w, r15),
+ DEFINE_GPR_PSEUDO_8H(ah, rax), DEFINE_GPR_PSEUDO_8H(bh, rbx),
+ DEFINE_GPR_PSEUDO_8H(ch, rcx), DEFINE_GPR_PSEUDO_8H(dh, rdx),
+ DEFINE_GPR_PSEUDO_8L(al, rax), DEFINE_GPR_PSEUDO_8L(bl, rbx),
+ DEFINE_GPR_PSEUDO_8L(cl, rcx), DEFINE_GPR_PSEUDO_8L(dl, rdx),
+ DEFINE_GPR_PSEUDO_8L(dil, rdi), DEFINE_GPR_PSEUDO_8L(sil, rsi),
+ DEFINE_GPR_PSEUDO_8L(bpl, rbp), DEFINE_GPR_PSEUDO_8L(spl, rsp),
+ DEFINE_GPR_PSEUDO_8L(r8l, r8), DEFINE_GPR_PSEUDO_8L(r9l, r9),
+ DEFINE_GPR_PSEUDO_8L(r10l, r10), DEFINE_GPR_PSEUDO_8L(r11l, r11),
+ DEFINE_GPR_PSEUDO_8L(r12l, r12), DEFINE_GPR_PSEUDO_8L(r13l, r13),
+ DEFINE_GPR_PSEUDO_8L(r14l, r14), DEFINE_GPR_PSEUDO_8L(r15l, r15),
+
+// i387 Floating point registers. EH_frame DWARF Generic Process Plugin reg64
+// ====================================== =============== ================== =================== ==================== =====
+ DEFINE_FPR(fctrl, fctrl, dwarf_fctrl_x86_64, dwarf_fctrl_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(fstat, fstat, dwarf_fstat_x86_64, dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR_32(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fip),
+ DEFINE_FPR_32(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fip),
+ DEFINE_FPR(fip, ptr.x86_64.fip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR_32(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fdp),
+ DEFINE_FPR_32(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fdp),
+ DEFINE_FPR(fdp, ptr.x86_64.fdp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(mxcsr, mxcsr, dwarf_mxcsr_x86_64, dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ // FP registers.
+ DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2),
+ DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5),
+ DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7),
+
+ DEFINE_FP_MM(mm, 0, st0), DEFINE_FP_MM(mm, 1, st1),
+ DEFINE_FP_MM(mm, 2, st2), DEFINE_FP_MM(mm, 3, st3),
+ DEFINE_FP_MM(mm, 4, st4), DEFINE_FP_MM(mm, 5, st5),
+ DEFINE_FP_MM(mm, 6, st6), DEFINE_FP_MM(mm, 7, st7),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3), DEFINE_XMM(xmm, 4), DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6), DEFINE_XMM(xmm, 7), DEFINE_XMM(xmm, 8),
+ DEFINE_XMM(xmm, 9), DEFINE_XMM(xmm, 10), DEFINE_XMM(xmm, 11),
+ DEFINE_XMM(xmm, 12), DEFINE_XMM(xmm, 13), DEFINE_XMM(xmm, 14),
+ DEFINE_XMM(xmm, 15),
+
+ // Copy of YMM registers assembled from xmm and ymmh
+ DEFINE_YMM(ymm, 0), DEFINE_YMM(ymm, 1), DEFINE_YMM(ymm, 2),
+ DEFINE_YMM(ymm, 3), DEFINE_YMM(ymm, 4), DEFINE_YMM(ymm, 5),
+ DEFINE_YMM(ymm, 6), DEFINE_YMM(ymm, 7), DEFINE_YMM(ymm, 8),
+ DEFINE_YMM(ymm, 9), DEFINE_YMM(ymm, 10), DEFINE_YMM(ymm, 11),
+ DEFINE_YMM(ymm, 12), DEFINE_YMM(ymm, 13), DEFINE_YMM(ymm, 14),
+ DEFINE_YMM(ymm, 15),
+
+ // MPX registers
+ DEFINE_BNDR(bnd, 0),
+ DEFINE_BNDR(bnd, 1),
+ DEFINE_BNDR(bnd, 2),
+ DEFINE_BNDR(bnd, 3),
+
+ DEFINE_BNDC(bndcfgu, 0),
+ DEFINE_BNDC(bndstatus, 1),
+
+ // Debug registers for lldb internal use
+ DEFINE_DR(dr, 0), DEFINE_DR(dr, 1), DEFINE_DR(dr, 2), DEFINE_DR(dr, 3),
+ DEFINE_DR(dr, 4), DEFINE_DR(dr, 5), DEFINE_DR(dr, 6), DEFINE_DR(dr, 7)};
+
+// clang-format on
+
+static_assert((sizeof(g_register_infos_x86_64) /
+ sizeof(g_register_infos_x86_64[0])) == k_num_registers_x86_64,
+ "g_register_infos_x86_64 has wrong number of register infos");
+
+#undef FPR_SIZE
+#undef FP_SIZE
+#undef XMM_SIZE
+#undef YMM_SIZE
+#undef DEFINE_GPR
+#undef DEFINE_FPR
+#undef DEFINE_FP
+#undef DEFINE_XMM
+#undef DEFINE_YMM
+#undef DEFINE_BNDR
+#undef DEFINE_BNDC
+#undef DEFINE_DR
+#undef DEFINE_GPR_PSEUDO_32
+#undef DEFINE_GPR_PSEUDO_16
+#undef DEFINE_GPR_PSEUDO_8H
+#undef DEFINE_GPR_PSEUDO_8L
+
+#endif // DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+#ifdef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+
+#define UPDATE_GPR_INFO(reg, reg64) \
+ do { \
+ g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64); \
+ } while (false);
+
+#define UPDATE_GPR_INFO_8H(reg, reg64) \
+ do { \
+ g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64) + 1; \
+ } while (false);
+
+#define UPDATE_FPR_INFO(reg, reg64) \
+ do { \
+ g_register_infos[lldb_##reg##_i386].byte_offset = FPR_OFFSET(reg64); \
+ } while (false);
+
+#define UPDATE_FP_INFO(reg, i) \
+ do { \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(stmm[i]); \
+ } while (false);
+
+#define UPDATE_XMM_INFO(reg, i) \
+ do { \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(reg[i]); \
+ } while (false);
+
+#define UPDATE_YMM_INFO(reg, i) \
+ do { \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = YMM_OFFSET(i); \
+ } while (false);
+
+#define UPDATE_DR_INFO(reg_index) \
+ do { \
+ g_register_infos[lldb_dr##reg_index##_i386].byte_offset = \
+ DR_OFFSET(reg_index); \
+ } while (false);
+
+// Update the register offsets
+UPDATE_GPR_INFO(eax, rax);
+UPDATE_GPR_INFO(ebx, rbx);
+UPDATE_GPR_INFO(ecx, rcx);
+UPDATE_GPR_INFO(edx, rdx);
+UPDATE_GPR_INFO(edi, rdi);
+UPDATE_GPR_INFO(esi, rsi);
+UPDATE_GPR_INFO(ebp, rbp);
+UPDATE_GPR_INFO(esp, rsp);
+UPDATE_GPR_INFO(eip, rip);
+UPDATE_GPR_INFO(eflags, rflags);
+UPDATE_GPR_INFO(cs, cs);
+UPDATE_GPR_INFO(fs, fs);
+UPDATE_GPR_INFO(gs, gs);
+UPDATE_GPR_INFO(ss, ss);
+UPDATE_GPR_INFO(ds, ds);
+UPDATE_GPR_INFO(es, es);
+
+UPDATE_GPR_INFO(ax, rax);
+UPDATE_GPR_INFO(bx, rbx);
+UPDATE_GPR_INFO(cx, rcx);
+UPDATE_GPR_INFO(dx, rdx);
+UPDATE_GPR_INFO(di, rdi);
+UPDATE_GPR_INFO(si, rsi);
+UPDATE_GPR_INFO(bp, rbp);
+UPDATE_GPR_INFO(sp, rsp);
+UPDATE_GPR_INFO_8H(ah, rax);
+UPDATE_GPR_INFO_8H(bh, rbx);
+UPDATE_GPR_INFO_8H(ch, rcx);
+UPDATE_GPR_INFO_8H(dh, rdx);
+UPDATE_GPR_INFO(al, rax);
+UPDATE_GPR_INFO(bl, rbx);
+UPDATE_GPR_INFO(cl, rcx);
+UPDATE_GPR_INFO(dl, rdx);
+
+UPDATE_FPR_INFO(fctrl, fctrl);
+UPDATE_FPR_INFO(fstat, fstat);
+UPDATE_FPR_INFO(ftag, ftag);
+UPDATE_FPR_INFO(fop, fop);
+UPDATE_FPR_INFO(fiseg, ptr.i386_.fiseg);
+UPDATE_FPR_INFO(fioff, ptr.i386_.fioff);
+UPDATE_FPR_INFO(fooff, ptr.i386_.fooff);
+UPDATE_FPR_INFO(foseg, ptr.i386_.foseg);
+UPDATE_FPR_INFO(mxcsr, mxcsr);
+UPDATE_FPR_INFO(mxcsrmask, mxcsrmask);
+
+UPDATE_FP_INFO(st, 0);
+UPDATE_FP_INFO(st, 1);
+UPDATE_FP_INFO(st, 2);
+UPDATE_FP_INFO(st, 3);
+UPDATE_FP_INFO(st, 4);
+UPDATE_FP_INFO(st, 5);
+UPDATE_FP_INFO(st, 6);
+UPDATE_FP_INFO(st, 7);
+UPDATE_FP_INFO(mm, 0);
+UPDATE_FP_INFO(mm, 1);
+UPDATE_FP_INFO(mm, 2);
+UPDATE_FP_INFO(mm, 3);
+UPDATE_FP_INFO(mm, 4);
+UPDATE_FP_INFO(mm, 5);
+UPDATE_FP_INFO(mm, 6);
+UPDATE_FP_INFO(mm, 7);
+
+UPDATE_XMM_INFO(xmm, 0);
+UPDATE_XMM_INFO(xmm, 1);
+UPDATE_XMM_INFO(xmm, 2);
+UPDATE_XMM_INFO(xmm, 3);
+UPDATE_XMM_INFO(xmm, 4);
+UPDATE_XMM_INFO(xmm, 5);
+UPDATE_XMM_INFO(xmm, 6);
+UPDATE_XMM_INFO(xmm, 7);
+
+UPDATE_YMM_INFO(ymm, 0);
+UPDATE_YMM_INFO(ymm, 1);
+UPDATE_YMM_INFO(ymm, 2);
+UPDATE_YMM_INFO(ymm, 3);
+UPDATE_YMM_INFO(ymm, 4);
+UPDATE_YMM_INFO(ymm, 5);
+UPDATE_YMM_INFO(ymm, 6);
+UPDATE_YMM_INFO(ymm, 7);
+
+UPDATE_DR_INFO(0);
+UPDATE_DR_INFO(1);
+UPDATE_DR_INFO(2);
+UPDATE_DR_INFO(3);
+UPDATE_DR_INFO(4);
+UPDATE_DR_INFO(5);
+UPDATE_DR_INFO(6);
+UPDATE_DR_INFO(7);
+
+#undef UPDATE_GPR_INFO
+#undef UPDATE_GPR_INFO_8H
+#undef UPDATE_FPR_INFO
+#undef UPDATE_FP_INFO
+#undef UPDATE_XMM_INFO
+#undef UPDATE_YMM_INFO
+#undef UPDATE_DR_INFO
+
+#endif // UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+
+#undef GPR_OFFSET
+#undef FPR_OFFSET
+#undef YMM_OFFSET
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h
new file mode 100644
index 000000000000..b111d8f62d1f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base.h
@@ -0,0 +1,471 @@
+//===-- RegisterInfos_x86_64_with_base.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterInfos_x86_64_with_base_shared.h"
+
+// This file is meant to be textually included. Do not #include modular
+// headers here.
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) (LLVM_EXTENSION offsetof(GPR, regname))
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, fxsave) + \
+ LLVM_EXTENSION offsetof(FXSAVE, regname))
+
+// Computes the offset of the YMM register assembled from register halves.
+// Based on DNBArchImplX86_64.cpp from debugserver
+#define YMM_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, xsave) + \
+ LLVM_EXTENSION offsetof(XSAVE, ymmh[0]) + (32 * reg_index))
+
+// Guarantees BNDR/BNDC offsets do not overlap with YMM offsets.
+#define GDB_REMOTE_OFFSET 128
+
+#define BNDR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, xsave) + \
+ LLVM_EXTENSION offsetof(XSAVE, mpxr[reg_index]) + GDB_REMOTE_OFFSET)
+
+#define BNDC_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, xsave) + \
+ LLVM_EXTENSION offsetof(XSAVE, mpxc[reg_index]) + GDB_REMOTE_OFFSET)
+
+#ifdef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+// Number of bytes needed to represent a FPR.
+#define FPR_SIZE(reg) sizeof(((FXSAVE *)nullptr)->reg)
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((MMSReg *)nullptr)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(XMMReg)
+
+// Number of bytes needed to represent a YMM register.
+#define YMM_SIZE sizeof(YMMReg)
+
+// Number of bytes needed to represent MPX registers.
+#define BNDR_SIZE sizeof(MPXReg)
+#define BNDC_SIZE sizeof(MPXCsr)
+
+#define DR_SIZE sizeof(((DBG *)nullptr)->dr[0])
+
+// RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { \
+ #reg, alt, sizeof(((GPR *)nullptr)->reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, \
+ {kind1, kind2, kind3, kind4, x86_64_with_base::lldb_##reg}, nullptr, \
+ nullptr, nullptr, \
+ }
+
+#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \
+ { \
+ #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, kind4, x86_64_with_base::lldb_##name}, nullptr, \
+ nullptr, nullptr, \
+ }
+
+#define DEFINE_FP_ST(reg, i) \
+ { \
+ #reg #i, nullptr, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ {dwarf_st##i##_x86_64, dwarf_st##i##_x86_64, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, x86_64_with_base::lldb_st##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_FP_MM(reg, i, streg) \
+ { \
+ #reg #i, nullptr, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
+ eEncodingUint, eFormatHex, \
+ {dwarf_mm##i##_x86_64, dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, x86_64_with_base::lldb_mm##i}, \
+ RegisterInfos_x86_64_with_base_shared::g_contained_##streg##_64, \
+ RegisterInfos_x86_64_with_base_shared::g_invalidate_##streg##_64, \
+ nullptr, \
+ }
+
+#define DEFINE_XMM(reg, i) \
+ { \
+ #reg #i, nullptr, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ {dwarf_##reg##i##_x86_64, dwarf_##reg##i##_x86_64, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ x86_64_with_base::lldb_##reg##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_YMM(reg, i) \
+ { \
+ #reg #i, nullptr, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(i), eEncodingVector, \
+ eFormatVectorOfUInt8, \
+ {dwarf_##reg##i##h_x86_64, dwarf_##reg##i##h_x86_64, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ x86_64_with_base::lldb_##reg##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_BNDR(reg, i) \
+ { \
+ #reg #i, nullptr, BNDR_SIZE, LLVM_EXTENSION BNDR_OFFSET(i), \
+ eEncodingVector, eFormatVectorOfUInt64, \
+ {dwarf_##reg##i##_x86_64, dwarf_##reg##i##_x86_64, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ x86_64_with_base::lldb_##reg##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_BNDC(name, i) \
+ { \
+ #name, nullptr, BNDC_SIZE, LLVM_EXTENSION BNDC_OFFSET(i), eEncodingVector, \
+ eFormatVectorOfUInt8, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, x86_64_with_base::lldb_##name}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_DR(reg, i) \
+ { \
+ #reg #i, nullptr, DR_SIZE, DR_OFFSET(i), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, x86_64_with_base::lldb_##reg##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_32(reg32, reg64) \
+ { \
+ #reg32, nullptr, 4, GPR_OFFSET(reg64), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, x86_64_with_base::lldb_##reg32}, \
+ RegisterInfos_x86_64_with_base_shared::g_contained_##reg64, \
+ RegisterInfos_x86_64_with_base_shared::g_invalidate_##reg64, nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_16(reg16, reg64) \
+ { \
+ #reg16, nullptr, 2, GPR_OFFSET(reg64), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, x86_64_with_base::lldb_##reg16}, \
+ RegisterInfos_x86_64_with_base_shared::g_contained_##reg64, \
+ RegisterInfos_x86_64_with_base_shared::g_invalidate_##reg64, nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_8H(reg8, reg64) \
+ { \
+ #reg8, nullptr, 1, GPR_OFFSET(reg64) + 1, eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, x86_64_with_base::lldb_##reg8}, \
+ RegisterInfos_x86_64_with_base_shared::g_contained_##reg64, \
+ RegisterInfos_x86_64_with_base_shared::g_invalidate_##reg64, nullptr, \
+ }
+
+#define DEFINE_GPR_PSEUDO_8L(reg8, reg64) \
+ { \
+ #reg8, nullptr, 1, GPR_OFFSET(reg64), eEncodingUint, eFormatHex, \
+ {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, x86_64_with_base::lldb_##reg8}, \
+ RegisterInfos_x86_64_with_base_shared::g_contained_##reg64, \
+ RegisterInfos_x86_64_with_base_shared::g_invalidate_##reg64, nullptr \
+ }
+
+#define DEFINE_FPR_32(name, reg, kind1, kind2, kind3, kind4, reg64) \
+ { \
+ #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, kind4, x86_64_with_base::lldb_##name}, \
+ RegisterInfos_x86_64_with_base_shared::g_contained_##reg64, \
+ RegisterInfos_x86_64_with_base_shared::g_invalidate_##reg64, nullptr, \
+ }
+
+// clang-format off
+static RegisterInfo g_register_infos_x86_64_with_base[] = {
+// General purpose registers EH_Frame DWARF Generic Process Plugin
+// =========================== ================== ================ ========================= ====================
+ DEFINE_GPR(rax, nullptr, dwarf_rax_x86_64, dwarf_rax_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rbx, nullptr, dwarf_rbx_x86_64, dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rcx, nullptr, dwarf_rcx_x86_64, dwarf_rcx_x86_64, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rdx, nullptr, dwarf_rdx_x86_64, dwarf_rdx_x86_64, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rdi, nullptr, dwarf_rdi_x86_64, dwarf_rdi_x86_64, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rsi, nullptr, dwarf_rsi_x86_64, dwarf_rsi_x86_64, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rbp, nullptr, dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rsp, nullptr, dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r8, nullptr, dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r9, nullptr, dwarf_r9_x86_64, dwarf_r9_x86_64, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r10, nullptr, dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r11, nullptr, dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r12, nullptr, dwarf_r12_x86_64, dwarf_r12_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r13, nullptr, dwarf_r13_x86_64, dwarf_r13_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r14, nullptr, dwarf_r14_x86_64, dwarf_r14_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(r15, nullptr, dwarf_r15_x86_64, dwarf_r15_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rip, nullptr, dwarf_rip_x86_64, dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(rflags, nullptr, dwarf_rflags_x86_64, dwarf_rflags_x86_64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(cs, nullptr, dwarf_cs_x86_64, dwarf_cs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(fs, nullptr, dwarf_fs_x86_64, dwarf_fs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(gs, nullptr, dwarf_gs_x86_64, dwarf_gs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ss, nullptr, dwarf_ss_x86_64, dwarf_ss_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(fs_base,nullptr, dwarf_fs_base_x86_64, dwarf_fs_base_x86_64, LLDB_REGNUM_GENERIC_TP, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(gs_base,nullptr, dwarf_gs_base_x86_64, dwarf_gs_base_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ds, nullptr, dwarf_ds_x86_64, dwarf_ds_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(es, nullptr, dwarf_es_x86_64, dwarf_es_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ DEFINE_GPR_PSEUDO_32(eax, rax), DEFINE_GPR_PSEUDO_32(ebx, rbx),
+ DEFINE_GPR_PSEUDO_32(ecx, rcx), DEFINE_GPR_PSEUDO_32(edx, rdx),
+ DEFINE_GPR_PSEUDO_32(edi, rdi), DEFINE_GPR_PSEUDO_32(esi, rsi),
+ DEFINE_GPR_PSEUDO_32(ebp, rbp), DEFINE_GPR_PSEUDO_32(esp, rsp),
+ DEFINE_GPR_PSEUDO_32(r8d, r8), DEFINE_GPR_PSEUDO_32(r9d, r9),
+ DEFINE_GPR_PSEUDO_32(r10d, r10), DEFINE_GPR_PSEUDO_32(r11d, r11),
+ DEFINE_GPR_PSEUDO_32(r12d, r12), DEFINE_GPR_PSEUDO_32(r13d, r13),
+ DEFINE_GPR_PSEUDO_32(r14d, r14), DEFINE_GPR_PSEUDO_32(r15d, r15),
+ DEFINE_GPR_PSEUDO_16(ax, rax), DEFINE_GPR_PSEUDO_16(bx, rbx),
+ DEFINE_GPR_PSEUDO_16(cx, rcx), DEFINE_GPR_PSEUDO_16(dx, rdx),
+ DEFINE_GPR_PSEUDO_16(di, rdi), DEFINE_GPR_PSEUDO_16(si, rsi),
+ DEFINE_GPR_PSEUDO_16(bp, rbp), DEFINE_GPR_PSEUDO_16(sp, rsp),
+ DEFINE_GPR_PSEUDO_16(r8w, r8), DEFINE_GPR_PSEUDO_16(r9w, r9),
+ DEFINE_GPR_PSEUDO_16(r10w, r10), DEFINE_GPR_PSEUDO_16(r11w, r11),
+ DEFINE_GPR_PSEUDO_16(r12w, r12), DEFINE_GPR_PSEUDO_16(r13w, r13),
+ DEFINE_GPR_PSEUDO_16(r14w, r14), DEFINE_GPR_PSEUDO_16(r15w, r15),
+ DEFINE_GPR_PSEUDO_8H(ah, rax), DEFINE_GPR_PSEUDO_8H(bh, rbx),
+ DEFINE_GPR_PSEUDO_8H(ch, rcx), DEFINE_GPR_PSEUDO_8H(dh, rdx),
+ DEFINE_GPR_PSEUDO_8L(al, rax), DEFINE_GPR_PSEUDO_8L(bl, rbx),
+ DEFINE_GPR_PSEUDO_8L(cl, rcx), DEFINE_GPR_PSEUDO_8L(dl, rdx),
+ DEFINE_GPR_PSEUDO_8L(dil, rdi), DEFINE_GPR_PSEUDO_8L(sil, rsi),
+ DEFINE_GPR_PSEUDO_8L(bpl, rbp), DEFINE_GPR_PSEUDO_8L(spl, rsp),
+ DEFINE_GPR_PSEUDO_8L(r8l, r8), DEFINE_GPR_PSEUDO_8L(r9l, r9),
+ DEFINE_GPR_PSEUDO_8L(r10l, r10), DEFINE_GPR_PSEUDO_8L(r11l, r11),
+ DEFINE_GPR_PSEUDO_8L(r12l, r12), DEFINE_GPR_PSEUDO_8L(r13l, r13),
+ DEFINE_GPR_PSEUDO_8L(r14l, r14), DEFINE_GPR_PSEUDO_8L(r15l, r15),
+
+// i387 Floating point registers. EH_frame DWARF Generic Process Plugin reg64
+// ====================================== =============== ================== =================== ==================== =====
+ DEFINE_FPR(fctrl, fctrl, dwarf_fctrl_x86_64, dwarf_fctrl_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(fstat, fstat, dwarf_fstat_x86_64, dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR_32(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fip),
+ DEFINE_FPR_32(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fip),
+ DEFINE_FPR(fip, ptr.x86_64.fip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR_32(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fdp),
+ DEFINE_FPR_32(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fdp),
+ DEFINE_FPR(fdp, ptr.x86_64.fdp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(mxcsr, mxcsr, dwarf_mxcsr_x86_64, dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ // FP registers.
+ DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2),
+ DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5),
+ DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7),
+
+ DEFINE_FP_MM(mm, 0, st0), DEFINE_FP_MM(mm, 1, st1),
+ DEFINE_FP_MM(mm, 2, st2), DEFINE_FP_MM(mm, 3, st3),
+ DEFINE_FP_MM(mm, 4, st4), DEFINE_FP_MM(mm, 5, st5),
+ DEFINE_FP_MM(mm, 6, st6), DEFINE_FP_MM(mm, 7, st7),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3), DEFINE_XMM(xmm, 4), DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6), DEFINE_XMM(xmm, 7), DEFINE_XMM(xmm, 8),
+ DEFINE_XMM(xmm, 9), DEFINE_XMM(xmm, 10), DEFINE_XMM(xmm, 11),
+ DEFINE_XMM(xmm, 12), DEFINE_XMM(xmm, 13), DEFINE_XMM(xmm, 14),
+ DEFINE_XMM(xmm, 15),
+
+ // Copy of YMM registers assembled from xmm and ymmh
+ DEFINE_YMM(ymm, 0), DEFINE_YMM(ymm, 1), DEFINE_YMM(ymm, 2),
+ DEFINE_YMM(ymm, 3), DEFINE_YMM(ymm, 4), DEFINE_YMM(ymm, 5),
+ DEFINE_YMM(ymm, 6), DEFINE_YMM(ymm, 7), DEFINE_YMM(ymm, 8),
+ DEFINE_YMM(ymm, 9), DEFINE_YMM(ymm, 10), DEFINE_YMM(ymm, 11),
+ DEFINE_YMM(ymm, 12), DEFINE_YMM(ymm, 13), DEFINE_YMM(ymm, 14),
+ DEFINE_YMM(ymm, 15),
+
+ // MPX registers
+ DEFINE_BNDR(bnd, 0),
+ DEFINE_BNDR(bnd, 1),
+ DEFINE_BNDR(bnd, 2),
+ DEFINE_BNDR(bnd, 3),
+
+ DEFINE_BNDC(bndcfgu, 0),
+ DEFINE_BNDC(bndstatus, 1),
+
+ // Debug registers for lldb internal use
+ DEFINE_DR(dr, 0), DEFINE_DR(dr, 1), DEFINE_DR(dr, 2), DEFINE_DR(dr, 3),
+ DEFINE_DR(dr, 4), DEFINE_DR(dr, 5), DEFINE_DR(dr, 6), DEFINE_DR(dr, 7)};
+
+// clang-format on
+
+static_assert(
+ (sizeof(g_register_infos_x86_64_with_base) /
+ sizeof(g_register_infos_x86_64_with_base[0])) ==
+ x86_64_with_base::k_num_registers,
+ "g_register_infos_x86_64_with_base has wrong number of register infos");
+
+#undef FPR_SIZE
+#undef FP_SIZE
+#undef XMM_SIZE
+#undef YMM_SIZE
+#undef DEFINE_GPR
+#undef DEFINE_FPR
+#undef DEFINE_FP
+#undef DEFINE_XMM
+#undef DEFINE_YMM
+#undef DEFINE_BNDR
+#undef DEFINE_BNDC
+#undef DEFINE_DR
+#undef DEFINE_GPR_PSEUDO_32
+#undef DEFINE_GPR_PSEUDO_16
+#undef DEFINE_GPR_PSEUDO_8H
+#undef DEFINE_GPR_PSEUDO_8L
+
+#endif // DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+#ifdef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+
+#define UPDATE_GPR_INFO(reg, reg64) \
+ do { \
+ g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64); \
+ } while (false);
+
+#define UPDATE_GPR_INFO_8H(reg, reg64) \
+ do { \
+ g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64) + 1; \
+ } while (false);
+
+#define UPDATE_FPR_INFO(reg, reg64) \
+ do { \
+ g_register_infos[lldb_##reg##_i386].byte_offset = FPR_OFFSET(reg64); \
+ } while (false);
+
+#define UPDATE_FP_INFO(reg, i) \
+ do { \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(stmm[i]); \
+ } while (false);
+
+#define UPDATE_XMM_INFO(reg, i) \
+ do { \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(reg[i]); \
+ } while (false);
+
+#define UPDATE_YMM_INFO(reg, i) \
+ do { \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = YMM_OFFSET(i); \
+ } while (false);
+
+#define UPDATE_DR_INFO(reg_index) \
+ do { \
+ g_register_infos[lldb_dr##reg_index##_i386].byte_offset = \
+ DR_OFFSET(reg_index); \
+ } while (false);
+
+// Update the register offsets
+UPDATE_GPR_INFO(eax, rax);
+UPDATE_GPR_INFO(ebx, rbx);
+UPDATE_GPR_INFO(ecx, rcx);
+UPDATE_GPR_INFO(edx, rdx);
+UPDATE_GPR_INFO(edi, rdi);
+UPDATE_GPR_INFO(esi, rsi);
+UPDATE_GPR_INFO(ebp, rbp);
+UPDATE_GPR_INFO(esp, rsp);
+UPDATE_GPR_INFO(eip, rip);
+UPDATE_GPR_INFO(eflags, rflags);
+UPDATE_GPR_INFO(cs, cs);
+UPDATE_GPR_INFO(fs, fs);
+UPDATE_GPR_INFO(gs, gs);
+UPDATE_GPR_INFO(ss, ss);
+UPDATE_GPR_INFO(ds, ds);
+UPDATE_GPR_INFO(es, es);
+
+UPDATE_GPR_INFO(ax, rax);
+UPDATE_GPR_INFO(bx, rbx);
+UPDATE_GPR_INFO(cx, rcx);
+UPDATE_GPR_INFO(dx, rdx);
+UPDATE_GPR_INFO(di, rdi);
+UPDATE_GPR_INFO(si, rsi);
+UPDATE_GPR_INFO(bp, rbp);
+UPDATE_GPR_INFO(sp, rsp);
+UPDATE_GPR_INFO_8H(ah, rax);
+UPDATE_GPR_INFO_8H(bh, rbx);
+UPDATE_GPR_INFO_8H(ch, rcx);
+UPDATE_GPR_INFO_8H(dh, rdx);
+UPDATE_GPR_INFO(al, rax);
+UPDATE_GPR_INFO(bl, rbx);
+UPDATE_GPR_INFO(cl, rcx);
+UPDATE_GPR_INFO(dl, rdx);
+
+UPDATE_FPR_INFO(fctrl, fctrl);
+UPDATE_FPR_INFO(fstat, fstat);
+UPDATE_FPR_INFO(ftag, ftag);
+UPDATE_FPR_INFO(fop, fop);
+UPDATE_FPR_INFO(fiseg, ptr.i386_.fiseg);
+UPDATE_FPR_INFO(fioff, ptr.i386_.fioff);
+UPDATE_FPR_INFO(fooff, ptr.i386_.fooff);
+UPDATE_FPR_INFO(foseg, ptr.i386_.foseg);
+UPDATE_FPR_INFO(mxcsr, mxcsr);
+UPDATE_FPR_INFO(mxcsrmask, mxcsrmask);
+
+UPDATE_FP_INFO(st, 0);
+UPDATE_FP_INFO(st, 1);
+UPDATE_FP_INFO(st, 2);
+UPDATE_FP_INFO(st, 3);
+UPDATE_FP_INFO(st, 4);
+UPDATE_FP_INFO(st, 5);
+UPDATE_FP_INFO(st, 6);
+UPDATE_FP_INFO(st, 7);
+UPDATE_FP_INFO(mm, 0);
+UPDATE_FP_INFO(mm, 1);
+UPDATE_FP_INFO(mm, 2);
+UPDATE_FP_INFO(mm, 3);
+UPDATE_FP_INFO(mm, 4);
+UPDATE_FP_INFO(mm, 5);
+UPDATE_FP_INFO(mm, 6);
+UPDATE_FP_INFO(mm, 7);
+
+UPDATE_XMM_INFO(xmm, 0);
+UPDATE_XMM_INFO(xmm, 1);
+UPDATE_XMM_INFO(xmm, 2);
+UPDATE_XMM_INFO(xmm, 3);
+UPDATE_XMM_INFO(xmm, 4);
+UPDATE_XMM_INFO(xmm, 5);
+UPDATE_XMM_INFO(xmm, 6);
+UPDATE_XMM_INFO(xmm, 7);
+
+UPDATE_YMM_INFO(ymm, 0);
+UPDATE_YMM_INFO(ymm, 1);
+UPDATE_YMM_INFO(ymm, 2);
+UPDATE_YMM_INFO(ymm, 3);
+UPDATE_YMM_INFO(ymm, 4);
+UPDATE_YMM_INFO(ymm, 5);
+UPDATE_YMM_INFO(ymm, 6);
+UPDATE_YMM_INFO(ymm, 7);
+
+UPDATE_DR_INFO(0);
+UPDATE_DR_INFO(1);
+UPDATE_DR_INFO(2);
+UPDATE_DR_INFO(3);
+UPDATE_DR_INFO(4);
+UPDATE_DR_INFO(5);
+UPDATE_DR_INFO(6);
+UPDATE_DR_INFO(7);
+
+#undef UPDATE_GPR_INFO
+#undef UPDATE_GPR_INFO_8H
+#undef UPDATE_FPR_INFO
+#undef UPDATE_FP_INFO
+#undef UPDATE_XMM_INFO
+#undef UPDATE_YMM_INFO
+#undef UPDATE_DR_INFO
+
+#endif // UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+
+#undef GPR_OFFSET
+#undef FPR_OFFSET
+#undef YMM_OFFSET
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base_shared.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base_shared.cpp
new file mode 100644
index 000000000000..7b2d64de230f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base_shared.cpp
@@ -0,0 +1,321 @@
+//===-- RegisterInfos_x86_64_with_base_shared.cpp--------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterInfos_x86_64_with_base_shared.h"
+
+#include "lldb/lldb-defines.h"
+#include <mutex>
+
+using namespace lldb;
+
+namespace lldb_private {
+
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_eax[] = {
+ lldb_eax_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_ebx[] = {
+ lldb_ebx_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_ecx[] = {
+ lldb_ecx_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_edx[] = {
+ lldb_edx_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_edi[] = {
+ lldb_edi_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_esi[] = {
+ lldb_esi_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_ebp[] = {
+ lldb_ebp_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_esp[] = {
+ lldb_esp_i386, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_eax[] = {
+ lldb_eax_i386, lldb_ax_i386, lldb_ah_i386, lldb_al_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_ebx[] = {
+ lldb_ebx_i386, lldb_bx_i386, lldb_bh_i386, lldb_bl_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_ecx[] = {
+ lldb_ecx_i386, lldb_cx_i386, lldb_ch_i386, lldb_cl_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_edx[] = {
+ lldb_edx_i386, lldb_dx_i386, lldb_dh_i386, lldb_dl_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_edi[] = {
+ lldb_edi_i386, lldb_di_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_esi[] = {
+ lldb_esi_i386, lldb_si_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_ebp[] = {
+ lldb_ebp_i386, lldb_bp_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_esp[] = {
+ lldb_esp_i386, lldb_sp_i386, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_rax[] = {
+ x86_64_with_base::lldb_rax, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_rbx[] = {
+ x86_64_with_base::lldb_rbx, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_rcx[] = {
+ x86_64_with_base::lldb_rcx, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_rdx[] = {
+ x86_64_with_base::lldb_rdx, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_rdi[] = {
+ x86_64_with_base::lldb_rdi, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_rsi[] = {
+ x86_64_with_base::lldb_rsi, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_rbp[] = {
+ x86_64_with_base::lldb_rbp, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_rsp[] = {
+ x86_64_with_base::lldb_rsp, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_r8[] = {
+ x86_64_with_base::lldb_r8, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_r9[] = {
+ x86_64_with_base::lldb_r9, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_r10[] = {
+ x86_64_with_base::lldb_r10, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_r11[] = {
+ x86_64_with_base::lldb_r11, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_r12[] = {
+ x86_64_with_base::lldb_r12, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_r13[] = {
+ x86_64_with_base::lldb_r13, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_r14[] = {
+ x86_64_with_base::lldb_r14, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_r15[] = {
+ x86_64_with_base::lldb_r15, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_rax[] = {
+ x86_64_with_base::lldb_rax, x86_64_with_base::lldb_eax,
+ x86_64_with_base::lldb_ax, x86_64_with_base::lldb_ah,
+ x86_64_with_base::lldb_al, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_rbx[] = {
+ x86_64_with_base::lldb_rbx, x86_64_with_base::lldb_ebx,
+ x86_64_with_base::lldb_bx, x86_64_with_base::lldb_bh,
+ x86_64_with_base::lldb_bl, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_rcx[] = {
+ x86_64_with_base::lldb_rcx, x86_64_with_base::lldb_ecx,
+ x86_64_with_base::lldb_cx, x86_64_with_base::lldb_ch,
+ x86_64_with_base::lldb_cl, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_rdx[] = {
+ x86_64_with_base::lldb_rdx, x86_64_with_base::lldb_edx,
+ x86_64_with_base::lldb_dx, x86_64_with_base::lldb_dh,
+ x86_64_with_base::lldb_dl, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_rdi[] = {
+ x86_64_with_base::lldb_rdi, x86_64_with_base::lldb_edi,
+ x86_64_with_base::lldb_di, x86_64_with_base::lldb_dil, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_rsi[] = {
+ x86_64_with_base::lldb_rsi, x86_64_with_base::lldb_esi,
+ x86_64_with_base::lldb_si, x86_64_with_base::lldb_sil, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_rbp[] = {
+ x86_64_with_base::lldb_rbp, x86_64_with_base::lldb_ebp,
+ x86_64_with_base::lldb_bp, x86_64_with_base::lldb_bpl, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_rsp[] = {
+ x86_64_with_base::lldb_rsp, x86_64_with_base::lldb_esp,
+ x86_64_with_base::lldb_sp, x86_64_with_base::lldb_spl, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_r8[] = {
+ x86_64_with_base::lldb_r8, x86_64_with_base::lldb_r8d,
+ x86_64_with_base::lldb_r8w, x86_64_with_base::lldb_r8l,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_r9[] = {
+ x86_64_with_base::lldb_r9, x86_64_with_base::lldb_r9d,
+ x86_64_with_base::lldb_r9w, x86_64_with_base::lldb_r9l,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_r10[] = {
+ x86_64_with_base::lldb_r10, x86_64_with_base::lldb_r10d,
+ x86_64_with_base::lldb_r10w, x86_64_with_base::lldb_r10l,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_r11[] = {
+ x86_64_with_base::lldb_r11, x86_64_with_base::lldb_r11d,
+ x86_64_with_base::lldb_r11w, x86_64_with_base::lldb_r11l,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_r12[] = {
+ x86_64_with_base::lldb_r12, x86_64_with_base::lldb_r12d,
+ x86_64_with_base::lldb_r12w, x86_64_with_base::lldb_r12l,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_r13[] = {
+ x86_64_with_base::lldb_r13, x86_64_with_base::lldb_r13d,
+ x86_64_with_base::lldb_r13w, x86_64_with_base::lldb_r13l,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_r14[] = {
+ x86_64_with_base::lldb_r14, x86_64_with_base::lldb_r14d,
+ x86_64_with_base::lldb_r14w, x86_64_with_base::lldb_r14l,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_r15[] = {
+ x86_64_with_base::lldb_r15, x86_64_with_base::lldb_r15d,
+ x86_64_with_base::lldb_r15w, x86_64_with_base::lldb_r15l,
+ LLDB_INVALID_REGNUM};
+
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_fip[] = {
+ x86_64_with_base::lldb_fip, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_fdp[] = {
+ x86_64_with_base::lldb_fdp, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_fip[] = {
+ x86_64_with_base::lldb_fip, x86_64_with_base::lldb_fioff,
+ x86_64_with_base::lldb_fiseg, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_fdp[] = {
+ x86_64_with_base::lldb_fdp, x86_64_with_base::lldb_fooff,
+ x86_64_with_base::lldb_foseg, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st0_32[] = {
+ lldb_st0_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st1_32[] = {
+ lldb_st1_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st2_32[] = {
+ lldb_st2_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st3_32[] = {
+ lldb_st3_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st4_32[] = {
+ lldb_st4_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st5_32[] = {
+ lldb_st5_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st6_32[] = {
+ lldb_st6_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st7_32[] = {
+ lldb_st7_i386, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st0_32[] = {
+ lldb_st0_i386, lldb_mm0_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st1_32[] = {
+ lldb_st1_i386, lldb_mm1_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st2_32[] = {
+ lldb_st2_i386, lldb_mm2_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st3_32[] = {
+ lldb_st3_i386, lldb_mm3_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st4_32[] = {
+ lldb_st4_i386, lldb_mm4_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st5_32[] = {
+ lldb_st5_i386, lldb_mm5_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st6_32[] = {
+ lldb_st6_i386, lldb_mm6_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st7_32[] = {
+ lldb_st7_i386, lldb_mm7_i386, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st0_64[] = {
+ x86_64_with_base::lldb_st0, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st1_64[] = {
+ x86_64_with_base::lldb_st1, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st2_64[] = {
+ x86_64_with_base::lldb_st2, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st3_64[] = {
+ x86_64_with_base::lldb_st3, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st4_64[] = {
+ x86_64_with_base::lldb_st4, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st5_64[] = {
+ x86_64_with_base::lldb_st5, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st6_64[] = {
+ x86_64_with_base::lldb_st6, LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_contained_st7_64[] = {
+ x86_64_with_base::lldb_st7, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st0_64[] = {
+ x86_64_with_base::lldb_st0, x86_64_with_base::lldb_mm0,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st1_64[] = {
+ x86_64_with_base::lldb_st1, x86_64_with_base::lldb_mm1,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st2_64[] = {
+ x86_64_with_base::lldb_st2, x86_64_with_base::lldb_mm2,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st3_64[] = {
+ x86_64_with_base::lldb_st3, x86_64_with_base::lldb_mm3,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st4_64[] = {
+ x86_64_with_base::lldb_st4, x86_64_with_base::lldb_mm4,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st5_64[] = {
+ x86_64_with_base::lldb_st5, x86_64_with_base::lldb_mm5,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st6_64[] = {
+ x86_64_with_base::lldb_st6, x86_64_with_base::lldb_mm6,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterInfos_x86_64_with_base_shared::g_invalidate_st7_64[] = {
+ x86_64_with_base::lldb_st7, x86_64_with_base::lldb_mm7,
+ LLDB_INVALID_REGNUM};
+
+RegInfo &GetRegInfoShared(llvm::Triple::ArchType arch_type, bool with_base) {
+ static std::once_flag once_flag_x86, once_flag_x86_64,
+ once_flag_x86_64_with_base;
+ static RegInfo reg_info_x86, reg_info_x86_64, reg_info_x86_64_with_base, reg_info_invalid;
+
+ switch (arch_type) {
+ case llvm::Triple::x86:
+ std::call_once(once_flag_x86, []() {
+ reg_info_x86.num_registers = k_num_registers_i386;
+ reg_info_x86.num_gpr_registers = k_num_gpr_registers_i386;
+ reg_info_x86.num_fpr_registers = k_num_fpr_registers_i386;
+ reg_info_x86.num_avx_registers = k_num_avx_registers_i386;
+ reg_info_x86.last_gpr = k_last_gpr_i386;
+ reg_info_x86.first_fpr = k_first_fpr_i386;
+ reg_info_x86.last_fpr = k_last_fpr_i386;
+ reg_info_x86.first_st = lldb_st0_i386;
+ reg_info_x86.last_st = lldb_st7_i386;
+ reg_info_x86.first_mm = lldb_mm0_i386;
+ reg_info_x86.last_mm = lldb_mm7_i386;
+ reg_info_x86.first_xmm = lldb_xmm0_i386;
+ reg_info_x86.last_xmm = lldb_xmm7_i386;
+ reg_info_x86.first_ymm = lldb_ymm0_i386;
+ reg_info_x86.last_ymm = lldb_ymm7_i386;
+ reg_info_x86.first_dr = lldb_dr0_i386;
+ reg_info_x86.gpr_flags = lldb_eflags_i386;
+ });
+
+ return reg_info_x86;
+ case llvm::Triple::x86_64:
+ if (with_base) {
+ std::call_once(once_flag_x86_64_with_base, []() {
+ reg_info_x86_64_with_base.num_registers =
+ x86_64_with_base::k_num_registers;
+ reg_info_x86_64_with_base.num_gpr_registers =
+ x86_64_with_base::k_num_gpr_registers;
+ reg_info_x86_64_with_base.num_fpr_registers =
+ x86_64_with_base::k_num_fpr_registers;
+ reg_info_x86_64_with_base.num_avx_registers =
+ x86_64_with_base::k_num_avx_registers;
+ reg_info_x86_64_with_base.last_gpr = x86_64_with_base::k_last_gpr;
+ reg_info_x86_64_with_base.first_fpr = x86_64_with_base::k_first_fpr;
+ reg_info_x86_64_with_base.last_fpr = x86_64_with_base::k_last_fpr;
+ reg_info_x86_64_with_base.first_st = x86_64_with_base::lldb_st0;
+ reg_info_x86_64_with_base.last_st = x86_64_with_base::lldb_st7;
+ reg_info_x86_64_with_base.first_mm = x86_64_with_base::lldb_mm0;
+ reg_info_x86_64_with_base.last_mm = x86_64_with_base::lldb_mm7;
+ reg_info_x86_64_with_base.first_xmm = x86_64_with_base::lldb_xmm0;
+ reg_info_x86_64_with_base.last_xmm = x86_64_with_base::lldb_xmm15;
+ reg_info_x86_64_with_base.first_ymm = x86_64_with_base::lldb_ymm0;
+ reg_info_x86_64_with_base.last_ymm = x86_64_with_base::lldb_ymm15;
+ reg_info_x86_64_with_base.first_dr = x86_64_with_base::lldb_dr0;
+ reg_info_x86_64_with_base.gpr_flags = x86_64_with_base::lldb_rflags;
+ });
+
+ return reg_info_x86_64_with_base;
+ } else {
+ std::call_once(once_flag_x86_64, []() {
+ reg_info_x86_64.num_registers = k_num_registers_x86_64;
+ reg_info_x86_64.num_gpr_registers = k_num_gpr_registers_x86_64;
+ reg_info_x86_64.num_fpr_registers = k_num_fpr_registers_x86_64;
+ reg_info_x86_64.num_avx_registers = k_num_avx_registers_x86_64;
+ reg_info_x86_64.last_gpr = k_last_gpr_x86_64;
+ reg_info_x86_64.first_fpr = k_first_fpr_x86_64;
+ reg_info_x86_64.last_fpr = k_last_fpr_x86_64;
+ reg_info_x86_64.first_st = lldb_st0_x86_64;
+ reg_info_x86_64.last_st = lldb_st7_x86_64;
+ reg_info_x86_64.first_mm = lldb_mm0_x86_64;
+ reg_info_x86_64.last_mm = lldb_mm7_x86_64;
+ reg_info_x86_64.first_xmm = lldb_xmm0_x86_64;
+ reg_info_x86_64.last_xmm = lldb_xmm15_x86_64;
+ reg_info_x86_64.first_ymm = lldb_ymm0_x86_64;
+ reg_info_x86_64.last_ymm = lldb_ymm15_x86_64;
+ reg_info_x86_64.first_dr = lldb_dr0_x86_64;
+ reg_info_x86_64.gpr_flags = lldb_rflags_x86_64;
+ });
+ return reg_info_x86_64;
+ }
+ default:
+ assert(false && "Unhandled target architecture.");
+ return reg_info_invalid;
+ }
+}
+
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base_shared.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base_shared.h
new file mode 100644
index 000000000000..5e4406c1fa27
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64_with_base_shared.h
@@ -0,0 +1,142 @@
+//===-- RegisterInfos_x86_64_with_base_shared.h -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+#include <stdint.h>
+
+#ifndef lldb_RegisterInfos_x86_64_with_base_shared_h
+#define lldb_RegisterInfos_x86_64_with_base_shared_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+namespace lldb_private {
+
+struct RegisterInfos_x86_64_with_base_shared {
+ static uint32_t g_contained_eax[];
+ static uint32_t g_contained_ebx[];
+ static uint32_t g_contained_ecx[];
+ static uint32_t g_contained_edx[];
+ static uint32_t g_contained_edi[];
+ static uint32_t g_contained_esi[];
+ static uint32_t g_contained_ebp[];
+ static uint32_t g_contained_esp[];
+
+ static uint32_t g_invalidate_eax[];
+ static uint32_t g_invalidate_ebx[];
+ static uint32_t g_invalidate_ecx[];
+ static uint32_t g_invalidate_edx[];
+ static uint32_t g_invalidate_edi[];
+ static uint32_t g_invalidate_esi[];
+ static uint32_t g_invalidate_ebp[];
+ static uint32_t g_invalidate_esp[];
+
+ static uint32_t g_contained_rax[];
+ static uint32_t g_contained_rbx[];
+ static uint32_t g_contained_rcx[];
+ static uint32_t g_contained_rdx[];
+ static uint32_t g_contained_rdi[];
+ static uint32_t g_contained_rsi[];
+ static uint32_t g_contained_rbp[];
+ static uint32_t g_contained_rsp[];
+ static uint32_t g_contained_r8[];
+ static uint32_t g_contained_r9[];
+ static uint32_t g_contained_r10[];
+ static uint32_t g_contained_r11[];
+ static uint32_t g_contained_r12[];
+ static uint32_t g_contained_r13[];
+ static uint32_t g_contained_r14[];
+ static uint32_t g_contained_r15[];
+
+ static uint32_t g_invalidate_rax[];
+ static uint32_t g_invalidate_rbx[];
+ static uint32_t g_invalidate_rcx[];
+ static uint32_t g_invalidate_rdx[];
+ static uint32_t g_invalidate_rdi[];
+ static uint32_t g_invalidate_rsi[];
+ static uint32_t g_invalidate_rbp[];
+ static uint32_t g_invalidate_rsp[];
+ static uint32_t g_invalidate_r8[];
+ static uint32_t g_invalidate_r9[];
+ static uint32_t g_invalidate_r10[];
+ static uint32_t g_invalidate_r11[];
+ static uint32_t g_invalidate_r12[];
+ static uint32_t g_invalidate_r13[];
+ static uint32_t g_invalidate_r14[];
+ static uint32_t g_invalidate_r15[];
+
+ static uint32_t g_contained_fip[];
+ static uint32_t g_contained_fdp[];
+
+ static uint32_t g_invalidate_fip[];
+ static uint32_t g_invalidate_fdp[];
+
+ static uint32_t g_contained_st0_32[];
+ static uint32_t g_contained_st1_32[];
+ static uint32_t g_contained_st2_32[];
+ static uint32_t g_contained_st3_32[];
+ static uint32_t g_contained_st4_32[];
+ static uint32_t g_contained_st5_32[];
+ static uint32_t g_contained_st6_32[];
+ static uint32_t g_contained_st7_32[];
+
+ static uint32_t g_invalidate_st0_32[];
+ static uint32_t g_invalidate_st1_32[];
+ static uint32_t g_invalidate_st2_32[];
+ static uint32_t g_invalidate_st3_32[];
+ static uint32_t g_invalidate_st4_32[];
+ static uint32_t g_invalidate_st5_32[];
+ static uint32_t g_invalidate_st6_32[];
+ static uint32_t g_invalidate_st7_32[];
+
+ static uint32_t g_contained_st0_64[];
+ static uint32_t g_contained_st1_64[];
+ static uint32_t g_contained_st2_64[];
+ static uint32_t g_contained_st3_64[];
+ static uint32_t g_contained_st4_64[];
+ static uint32_t g_contained_st5_64[];
+ static uint32_t g_contained_st6_64[];
+ static uint32_t g_contained_st7_64[];
+
+ static uint32_t g_invalidate_st0_64[];
+ static uint32_t g_invalidate_st1_64[];
+ static uint32_t g_invalidate_st2_64[];
+ static uint32_t g_invalidate_st3_64[];
+ static uint32_t g_invalidate_st4_64[];
+ static uint32_t g_invalidate_st5_64[];
+ static uint32_t g_invalidate_st6_64[];
+ static uint32_t g_invalidate_st7_64[];
+};
+
+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;
+};
+
+RegInfo &GetRegInfoShared(llvm::Triple::ArchType arch_type, bool with_base);
+
+} // namespace lldb_private
+
+#endif // ifndef lldb_RegisterInfos_x86_64_with_base_shared_h
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
new file mode 100644
index 000000000000..25cee369d7ee
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -0,0 +1,862 @@
+//===-- StopInfoMachException.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "StopInfoMachException.h"
+
+#include "lldb/lldb-forward.h"
+
+#if defined(__APPLE__)
+// Needed for the EXC_RESOURCE interpretation macros
+#include <kern/exc_resource.h>
+#endif
+
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+
+/// Information about a pointer-authentication related instruction.
+struct PtrauthInstructionInfo {
+ bool IsAuthenticated;
+ bool IsLoad;
+ bool DoesBranch;
+};
+
+/// Get any pointer-authentication related information about the instruction
+/// at address \p at_addr.
+static std::optional<PtrauthInstructionInfo>
+GetPtrauthInstructionInfo(Target &target, const ArchSpec &arch,
+ const Address &at_addr) {
+ const char *plugin_name = nullptr;
+ const char *flavor = nullptr;
+ AddressRange range_bounds(at_addr, 4);
+ const bool prefer_file_cache = true;
+ DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
+ arch, plugin_name, flavor, target, range_bounds, prefer_file_cache);
+ if (!disassembler_sp)
+ return std::nullopt;
+
+ InstructionList &insn_list = disassembler_sp->GetInstructionList();
+ InstructionSP insn = insn_list.GetInstructionAtIndex(0);
+ if (!insn)
+ return std::nullopt;
+
+ return PtrauthInstructionInfo{insn->IsAuthenticated(), insn->IsLoad(),
+ insn->DoesBranch()};
+}
+
+/// Describe the load address of \p addr using the format filename:line:col.
+static void DescribeAddressBriefly(Stream &strm, const Address &addr,
+ Target &target) {
+ strm.Printf("at address=0x%" PRIx64, addr.GetLoadAddress(&target));
+ StreamString s;
+ if (addr.GetDescription(s, target, eDescriptionLevelBrief))
+ strm.Printf(" %s", s.GetString().data());
+ strm.Printf(".\n");
+}
+
+bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) {
+ bool IsBreakpoint = m_value == 6; // EXC_BREAKPOINT
+ bool IsBadAccess = m_value == 1; // EXC_BAD_ACCESS
+ if (!IsBreakpoint && !IsBadAccess)
+ return false;
+
+ // Check that we have a live process.
+ if (!exe_ctx.HasProcessScope() || !exe_ctx.HasThreadScope() ||
+ !exe_ctx.HasTargetScope())
+ return false;
+
+ Thread &thread = *exe_ctx.GetThreadPtr();
+ StackFrameSP current_frame = thread.GetStackFrameAtIndex(0);
+ if (!current_frame)
+ return false;
+
+ Target &target = *exe_ctx.GetTargetPtr();
+ Process &process = *exe_ctx.GetProcessPtr();
+ const ArchSpec &arch = target.GetArchitecture();
+
+ // Check for a ptrauth-enabled target.
+ const bool ptrauth_enabled_target =
+ arch.GetCore() == ArchSpec::eCore_arm_arm64e;
+ if (!ptrauth_enabled_target)
+ return false;
+
+ // Set up a stream we can write a diagnostic into.
+ StreamString strm;
+ auto emit_ptrauth_prologue = [&](uint64_t at_address) {
+ strm.Printf("EXC_BAD_ACCESS (code=%" PRIu64 ", address=0x%" PRIx64 ")\n",
+ m_exc_code, at_address);
+ strm.Printf("Note: Possible pointer authentication failure detected.\n");
+ };
+
+ ABISP abi_sp = process.GetABI();
+ assert(abi_sp && "Missing ABI info");
+
+ // Check if we have a "brk 0xc47x" trap, where the value that failed to
+ // authenticate is in x16.
+ Address current_address = current_frame->GetFrameCodeAddress();
+ if (IsBreakpoint) {
+ RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();
+ if (!reg_ctx)
+ return false;
+
+ const RegisterInfo *X16Info = reg_ctx->GetRegisterInfoByName("x16");
+ RegisterValue X16Val;
+ if (!reg_ctx->ReadRegister(X16Info, X16Val))
+ return false;
+ uint64_t bad_address = X16Val.GetAsUInt64();
+
+ uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address);
+ Address brk_address;
+ if (!target.ResolveLoadAddress(fixed_bad_address, brk_address))
+ return false;
+
+ auto brk_ptrauth_info =
+ GetPtrauthInstructionInfo(target, arch, current_address);
+ if (brk_ptrauth_info && brk_ptrauth_info->IsAuthenticated) {
+ emit_ptrauth_prologue(bad_address);
+ strm.Printf("Found value that failed to authenticate ");
+ DescribeAddressBriefly(strm, brk_address, target);
+ m_description = std::string(strm.GetString());
+ return true;
+ }
+ return false;
+ }
+
+ assert(IsBadAccess && "Handle EXC_BAD_ACCESS only after this point");
+
+ // Check that we have the "bad address" from an EXC_BAD_ACCESS.
+ if (m_exc_data_count < 2)
+ return false;
+
+ // Ok, we know the Target is valid and that it describes a ptrauth-enabled
+ // device. Now, we need to determine whether this exception was caused by a
+ // ptrauth failure.
+
+ uint64_t bad_address = m_exc_subcode;
+ uint64_t fixed_bad_address = abi_sp->FixCodeAddress(bad_address);
+ uint64_t current_pc = current_address.GetLoadAddress(&target);
+
+ // Detect: LDRAA, LDRAB (Load Register, with pointer authentication).
+ //
+ // If an authenticated load results in an exception, the instruction at the
+ // current PC should be one of LDRAx.
+ if (bad_address != current_pc && fixed_bad_address != current_pc) {
+ auto ptrauth_info =
+ GetPtrauthInstructionInfo(target, arch, current_address);
+ if (ptrauth_info && ptrauth_info->IsAuthenticated && ptrauth_info->IsLoad) {
+ emit_ptrauth_prologue(bad_address);
+ strm.Printf("Found authenticated load instruction ");
+ DescribeAddressBriefly(strm, current_address, target);
+ m_description = std::string(strm.GetString());
+ return true;
+ }
+ }
+
+ // Detect: BLRAA, BLRAAZ, BLRAB, BLRABZ (Branch with Link to Register, with
+ // pointer authentication).
+ //
+ // TODO: Detect: BRAA, BRAAZ, BRAB, BRABZ (Branch to Register, with pointer
+ // authentication). At a minimum, this requires call site info support for
+ // indirect calls.
+ //
+ // If an authenticated call or tail call results in an exception, stripping
+ // the bad address should give the current PC, which points to the address
+ // we tried to branch to.
+ if (bad_address != current_pc && fixed_bad_address == current_pc) {
+ if (StackFrameSP parent_frame = thread.GetStackFrameAtIndex(1)) {
+ addr_t return_pc =
+ parent_frame->GetFrameCodeAddress().GetLoadAddress(&target);
+ Address blr_address;
+ if (!target.ResolveLoadAddress(return_pc - 4, blr_address))
+ return false;
+
+ auto blr_ptrauth_info =
+ GetPtrauthInstructionInfo(target, arch, blr_address);
+ if (blr_ptrauth_info && blr_ptrauth_info->IsAuthenticated &&
+ blr_ptrauth_info->DoesBranch) {
+ emit_ptrauth_prologue(bad_address);
+ strm.Printf("Found authenticated indirect branch ");
+ DescribeAddressBriefly(strm, blr_address, target);
+ m_description = std::string(strm.GetString());
+ return true;
+ }
+ }
+ }
+
+ // TODO: Detect: RETAA, RETAB (Return from subroutine, with pointer
+ // authentication).
+ //
+ // Is there a motivating, non-malicious code snippet that corrupts LR?
+
+ return false;
+}
+
+const char *StopInfoMachException::GetDescription() {
+ if (!m_description.empty())
+ return m_description.c_str();
+ if (GetValue() == eStopReasonInvalid)
+ return "invalid stop reason!";
+
+ ExecutionContext exe_ctx(m_thread_wp.lock());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu =
+ target ? target->GetArchitecture().GetMachine()
+ : llvm::Triple::UnknownArch;
+
+ const char *exc_desc = nullptr;
+ const char *code_label = "code";
+ const char *code_desc = nullptr;
+ const char *subcode_label = "subcode";
+ const char *subcode_desc = nullptr;
+
+#if defined(__APPLE__)
+ char code_desc_buf[32];
+ char subcode_desc_buf[32];
+#endif
+
+ switch (m_value) {
+ case 1: // EXC_BAD_ACCESS
+ exc_desc = "EXC_BAD_ACCESS";
+ subcode_label = "address";
+ switch (cpu) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code) {
+ case 0xd:
+ code_desc = "EXC_I386_GPFLT";
+ m_exc_data_count = 1;
+ break;
+ }
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ switch (m_exc_code) {
+ case 0x101:
+ code_desc = "EXC_ARM_DA_ALIGN";
+ break;
+ case 0x102:
+ code_desc = "EXC_ARM_DA_DEBUG";
+ break;
+ }
+ break;
+
+ case llvm::Triple::aarch64:
+ if (DeterminePtrauthFailure(exe_ctx))
+ return m_description.c_str();
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ exc_desc = "EXC_BAD_INSTRUCTION";
+ switch (cpu) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (m_exc_code == 1)
+ code_desc = "EXC_I386_INVOP";
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ if (m_exc_code == 1)
+ code_desc = "EXC_ARM_UNDEFINED";
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ exc_desc = "EXC_ARITHMETIC";
+ switch (cpu) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code) {
+ case 1:
+ code_desc = "EXC_I386_DIV";
+ break;
+ case 2:
+ code_desc = "EXC_I386_INTO";
+ break;
+ case 3:
+ code_desc = "EXC_I386_NOEXT";
+ break;
+ case 4:
+ code_desc = "EXC_I386_EXTOVR";
+ break;
+ case 5:
+ code_desc = "EXC_I386_EXTERR";
+ break;
+ case 6:
+ code_desc = "EXC_I386_EMERR";
+ break;
+ case 7:
+ code_desc = "EXC_I386_BOUND";
+ break;
+ case 8:
+ code_desc = "EXC_I386_SSEEXTERR";
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 4: // EXC_EMULATION
+ exc_desc = "EXC_EMULATION";
+ break;
+
+ case 5: // EXC_SOFTWARE
+ exc_desc = "EXC_SOFTWARE";
+ if (m_exc_code == 0x10003) {
+ subcode_desc = "EXC_SOFT_SIGNAL";
+ subcode_label = "signo";
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ exc_desc = "EXC_BREAKPOINT";
+ switch (cpu) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code) {
+ case 1:
+ code_desc = "EXC_I386_SGL";
+ break;
+ case 2:
+ code_desc = "EXC_I386_BPT";
+ break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ switch (m_exc_code) {
+ case 0x101:
+ code_desc = "EXC_ARM_DA_ALIGN";
+ break;
+ case 0x102:
+ code_desc = "EXC_ARM_DA_DEBUG";
+ break;
+ case 1:
+ code_desc = "EXC_ARM_BREAKPOINT";
+ break;
+ // FIXME temporary workaround, exc_code 0 does not really mean
+ // EXC_ARM_BREAKPOINT
+ case 0:
+ code_desc = "EXC_ARM_BREAKPOINT";
+ break;
+ }
+ break;
+
+ case llvm::Triple::aarch64:
+ if (DeterminePtrauthFailure(exe_ctx))
+ return m_description.c_str();
+ break;
+
+ default:
+ break;
+ }
+ } break;
+
+ case 7:
+ exc_desc = "EXC_SYSCALL";
+ break;
+
+ case 8:
+ exc_desc = "EXC_MACH_SYSCALL";
+ break;
+
+ case 9:
+ exc_desc = "EXC_RPC_ALERT";
+ break;
+
+ case 10:
+ exc_desc = "EXC_CRASH";
+ break;
+ case 11:
+ exc_desc = "EXC_RESOURCE";
+#if defined(__APPLE__)
+ {
+ int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(m_exc_code);
+
+ code_label = "limit";
+ code_desc = code_desc_buf;
+ subcode_label = "observed";
+ subcode_desc = subcode_desc_buf;
+
+ switch (resource_type) {
+ case RESOURCE_TYPE_CPU:
+ exc_desc =
+ "EXC_RESOURCE (RESOURCE_TYPE_CPU: CPU usage monitor tripped)";
+ snprintf(code_desc_buf, sizeof(code_desc_buf), "%d%%",
+ (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(m_exc_code));
+ snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d%%",
+ (int)EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED(
+ m_exc_subcode));
+ break;
+ case RESOURCE_TYPE_WAKEUPS:
+ exc_desc = "EXC_RESOURCE (RESOURCE_TYPE_WAKEUPS: idle wakeups monitor "
+ "tripped)";
+ snprintf(
+ code_desc_buf, sizeof(code_desc_buf), "%d w/s",
+ (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(m_exc_code));
+ snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d w/s",
+ (int)EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED(
+ m_exc_subcode));
+ break;
+ case RESOURCE_TYPE_MEMORY:
+ exc_desc = "EXC_RESOURCE (RESOURCE_TYPE_MEMORY: high watermark memory "
+ "limit exceeded)";
+ snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
+ (int)EXC_RESOURCE_HWM_DECODE_LIMIT(m_exc_code));
+ subcode_desc = nullptr;
+ subcode_label = nullptr;
+ break;
+#if defined(RESOURCE_TYPE_IO)
+ // RESOURCE_TYPE_IO is introduced in macOS SDK 10.12.
+ case RESOURCE_TYPE_IO:
+ exc_desc = "EXC_RESOURCE RESOURCE_TYPE_IO";
+ snprintf(code_desc_buf, sizeof(code_desc_buf), "%d MB",
+ (int)EXC_RESOURCE_IO_DECODE_LIMIT(m_exc_code));
+ snprintf(subcode_desc_buf, sizeof(subcode_desc_buf), "%d MB",
+ (int)EXC_RESOURCE_IO_OBSERVED(m_exc_subcode));
+ ;
+ break;
+#endif
+ }
+ }
+#endif
+ break;
+ case 12:
+ exc_desc = "EXC_GUARD";
+ break;
+ }
+
+ StreamString strm;
+
+ if (exc_desc)
+ strm.PutCString(exc_desc);
+ else
+ strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
+
+ if (m_exc_data_count >= 1) {
+ if (code_desc)
+ strm.Printf(" (%s=%s", code_label, code_desc);
+ else
+ strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
+ }
+
+ if (m_exc_data_count >= 2) {
+ if (subcode_label && subcode_desc)
+ strm.Printf(", %s=%s", subcode_label, subcode_desc);
+ else if (subcode_label)
+ strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
+ }
+
+ if (m_exc_data_count > 0)
+ strm.PutChar(')');
+
+ m_description = std::string(strm.GetString());
+ return m_description.c_str();
+}
+
+static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target,
+ uint32_t exc_data_count,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code) {
+ // Try hardware watchpoint.
+ if (target) {
+ // The exc_sub_code indicates the data break address.
+ WatchpointResourceSP wp_rsrc_sp =
+ target->GetProcessSP()->GetWatchpointResourceList().FindByAddress(
+ (addr_t)exc_sub_code);
+ if (wp_rsrc_sp && wp_rsrc_sp->GetNumberOfConstituents() > 0) {
+ return StopInfo::CreateStopReasonWithWatchpointID(
+ thread, wp_rsrc_sp->GetConstituentAtIndex(0)->GetID());
+ }
+ }
+
+ // Try hardware breakpoint.
+ ProcessSP process_sp(thread.GetProcess());
+ if (process_sp) {
+ // The exc_sub_code indicates the data break address.
+ lldb::BreakpointSiteSP bp_sp =
+ process_sp->GetBreakpointSiteList().FindByAddress(
+ (lldb::addr_t)exc_sub_code);
+ if (bp_sp && bp_sp->IsEnabled()) {
+ return StopInfo::CreateStopReasonWithBreakpointSiteID(thread,
+ bp_sp->GetID());
+ }
+ }
+
+ return nullptr;
+}
+
+#if defined(__APPLE__)
+const char *
+StopInfoMachException::MachException::Name(exception_type_t exc_type) {
+ switch (exc_type) {
+ case EXC_BAD_ACCESS:
+ return "EXC_BAD_ACCESS";
+ case EXC_BAD_INSTRUCTION:
+ return "EXC_BAD_INSTRUCTION";
+ case EXC_ARITHMETIC:
+ return "EXC_ARITHMETIC";
+ case EXC_EMULATION:
+ return "EXC_EMULATION";
+ case EXC_SOFTWARE:
+ return "EXC_SOFTWARE";
+ case EXC_BREAKPOINT:
+ return "EXC_BREAKPOINT";
+ case EXC_SYSCALL:
+ return "EXC_SYSCALL";
+ case EXC_MACH_SYSCALL:
+ return "EXC_MACH_SYSCALL";
+ case EXC_RPC_ALERT:
+ return "EXC_RPC_ALERT";
+#ifdef EXC_CRASH
+ case EXC_CRASH:
+ return "EXC_CRASH";
+#endif
+ case EXC_RESOURCE:
+ return "EXC_RESOURCE";
+#ifdef EXC_GUARD
+ case EXC_GUARD:
+ return "EXC_GUARD";
+#endif
+#ifdef EXC_CORPSE_NOTIFY
+ case EXC_CORPSE_NOTIFY:
+ return "EXC_CORPSE_NOTIFY";
+#endif
+#ifdef EXC_CORPSE_VARIANT_BIT
+ case EXC_CORPSE_VARIANT_BIT:
+ return "EXC_CORPSE_VARIANT_BIT";
+#endif
+ default:
+ break;
+ }
+ return NULL;
+}
+
+std::optional<exception_type_t>
+StopInfoMachException::MachException::ExceptionCode(const char *name) {
+ return llvm::StringSwitch<std::optional<exception_type_t>>(name)
+ .Case("EXC_BAD_ACCESS", EXC_BAD_ACCESS)
+ .Case("EXC_BAD_INSTRUCTION", EXC_BAD_INSTRUCTION)
+ .Case("EXC_ARITHMETIC", EXC_ARITHMETIC)
+ .Case("EXC_EMULATION", EXC_EMULATION)
+ .Case("EXC_SOFTWARE", EXC_SOFTWARE)
+ .Case("EXC_BREAKPOINT", EXC_BREAKPOINT)
+ .Case("EXC_SYSCALL", EXC_SYSCALL)
+ .Case("EXC_MACH_SYSCALL", EXC_MACH_SYSCALL)
+ .Case("EXC_RPC_ALERT", EXC_RPC_ALERT)
+#ifdef EXC_CRASH
+ .Case("EXC_CRASH", EXC_CRASH)
+#endif
+ .Case("EXC_RESOURCE", EXC_RESOURCE)
+#ifdef EXC_GUARD
+ .Case("EXC_GUARD", EXC_GUARD)
+#endif
+#ifdef EXC_CORPSE_NOTIFY
+ .Case("EXC_CORPSE_NOTIFY", EXC_CORPSE_NOTIFY)
+#endif
+ .Default(std::nullopt);
+}
+#endif
+
+StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
+ Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
+ uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted, bool adjust_pc_if_needed) {
+ if (exc_type == 0)
+ return StopInfoSP();
+
+ bool not_stepping_but_got_singlestep_exception = false;
+ uint32_t pc_decrement = 0;
+ ExecutionContext exe_ctx(thread.shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu =
+ target ? target->GetArchitecture().GetMachine()
+ : llvm::Triple::UnknownArch;
+
+ switch (exc_type) {
+ case 1: // EXC_BAD_ACCESS
+ case 2: // EXC_BAD_INSTRUCTION
+ case 3: // EXC_ARITHMETIC
+ case 4: // EXC_EMULATION
+ break;
+
+ case 5: // EXC_SOFTWARE
+ if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
+ {
+ if (exc_sub_code == 5) {
+ // On MacOSX, a SIGTRAP can signify that a process has called exec,
+ // so we should check with our dynamic loader to verify.
+ ProcessSP process_sp(thread.GetProcess());
+ if (process_sp) {
+ DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
+ if (dynamic_loader && dynamic_loader->ProcessDidExec()) {
+ // The program was re-exec'ed
+ return StopInfo::CreateStopReasonWithExec(thread);
+ }
+ }
+ }
+ return StopInfo::CreateStopReasonWithSignal(thread, exc_sub_code);
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ bool is_actual_breakpoint = false;
+ bool is_trace_if_actual_breakpoint_missing = false;
+ switch (cpu) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (exc_code == 1) // EXC_I386_SGL
+ {
+ if (!exc_sub_code) {
+ // This looks like a plain trap.
+ // Have to check if there is a breakpoint here as well. When you
+ // single-step onto a trap, the single step stops you not to trap.
+ // Since we also do that check below, let's just use that logic.
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ } else {
+ if (StopInfoSP stop_info =
+ GetStopInfoForHardwareBP(thread, target, exc_data_count,
+ exc_sub_code, exc_sub_sub_code))
+ return stop_info;
+ }
+ } else if (exc_code == 2 || // EXC_I386_BPT
+ exc_code == 3) // EXC_I386_BPTFLT
+ {
+ // KDP returns EXC_I386_BPTFLT for trace breakpoints
+ if (exc_code == 3)
+ is_trace_if_actual_breakpoint_missing = true;
+
+ is_actual_breakpoint = true;
+ if (!pc_already_adjusted)
+ pc_decrement = 1;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
+ {
+ // LWP_TODO: We need to find the WatchpointResource that matches
+ // the address, and evaluate its Watchpoints.
+
+ // It's a watchpoint, then, if the exc_sub_code indicates a
+ // known/enabled data break address from our watchpoint list.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress(
+ (lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled()) {
+ return StopInfo::CreateStopReasonWithWatchpointID(thread,
+ wp_sp->GetID());
+ } else {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ } else if (exc_code == 1) // EXC_ARM_BREAKPOINT
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ } else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel
+ // is currently returning this so accept it
+ // as indicating a breakpoint until the
+ // kernel is fixed
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ break;
+
+ case llvm::Triple::aarch64_32:
+ case llvm::Triple::aarch64: {
+ // xnu describes three things with type EXC_BREAKPOINT:
+ //
+ // exc_code 0x102 [EXC_ARM_DA_DEBUG], exc_sub_code addr-of-insn
+ // Watchpoint access. exc_sub_code is the address of the
+ // instruction which trigged the watchpoint trap.
+ // debugserver may add the watchpoint number that was triggered
+ // in exc_sub_sub_code.
+ //
+ // exc_code 1 [EXC_ARM_BREAKPOINT], exc_sub_code 0
+ // Instruction step has completed.
+ //
+ // exc_code 1 [EXC_ARM_BREAKPOINT], exc_sub_code address-of-instruction
+ // Software breakpoint instruction executed.
+
+ if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
+ {
+ // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0
+ // is set
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ if (thread.GetTemporaryResumeState() != eStateStepping)
+ not_stepping_but_got_singlestep_exception = true;
+ }
+ if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
+ {
+ // LWP_TODO: We need to find the WatchpointResource that matches
+ // the address, and evaluate its Watchpoints.
+
+ // It's a watchpoint, then, if the exc_sub_code indicates a
+ // known/enabled data break address from our watchpoint list.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress(
+ (lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled()) {
+ return StopInfo::CreateStopReasonWithWatchpointID(thread,
+ wp_sp->GetID());
+ }
+ // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as
+ // EXC_BAD_ACCESS
+ if (thread.GetTemporaryResumeState() == eStateStepping)
+ return StopInfo::CreateStopReasonToTrace(thread);
+ }
+ // It looks like exc_sub_code has the 4 bytes of the instruction that
+ // triggered the exception, i.e. our breakpoint opcode
+ is_actual_breakpoint = exc_code == 1;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (is_actual_breakpoint) {
+ RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
+ addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
+
+ ProcessSP process_sp(thread.CalculateProcess());
+
+ lldb::BreakpointSiteSP bp_site_sp;
+ if (process_sp)
+ bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp && bp_site_sp->IsEnabled()) {
+ // Update the PC if we were asked to do so, but only do so if we find
+ // a breakpoint that we know about cause this could be a trap
+ // instruction in the code
+ if (pc_decrement > 0 && adjust_pc_if_needed)
+ reg_ctx_sp->SetPC(pc);
+
+ // If the breakpoint is for this thread, then we'll report the hit,
+ // but if it is for another thread, we can just report no reason. We
+ // don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that
+ // there's a breakpoint under the pc. If we have an operating system
+ // plug-in, we might have set a thread specific breakpoint using the
+ // operating system thread ID, so we can't make any assumptions about
+ // the thread ID so we must always report the breakpoint regardless
+ // of the thread.
+ if (bp_site_sp->ValidForThisThread(thread) ||
+ thread.GetProcess()->GetOperatingSystem() != nullptr)
+ return StopInfo::CreateStopReasonWithBreakpointSiteID(
+ thread, bp_site_sp->GetID());
+ else if (is_trace_if_actual_breakpoint_missing)
+ return StopInfo::CreateStopReasonToTrace(thread);
+ else
+ return StopInfoSP();
+ }
+
+ // Don't call this a trace if we weren't single stepping this thread.
+ if (is_trace_if_actual_breakpoint_missing &&
+ thread.GetTemporaryResumeState() == eStateStepping) {
+ return StopInfo::CreateStopReasonToTrace(thread);
+ }
+ }
+ } break;
+
+ case 7: // EXC_SYSCALL
+ case 8: // EXC_MACH_SYSCALL
+ case 9: // EXC_RPC_ALERT
+ case 10: // EXC_CRASH
+ break;
+ }
+
+ return std::make_shared<StopInfoMachException>(
+ thread, exc_type, exc_data_count, exc_code, exc_sub_code,
+ not_stepping_but_got_singlestep_exception);
+}
+
+// Detect an unusual situation on Darwin where:
+//
+// 0. We did an instruction-step before this.
+// 1. We have a hardware breakpoint or watchpoint set.
+// 2. We resumed the process, but not with an instruction-step.
+// 3. The thread gets an "instruction-step completed" mach exception.
+// 4. The pc has not advanced - it is the same as before.
+//
+// This method returns true for that combination of events.
+bool StopInfoMachException::WasContinueInterrupted(Thread &thread) {
+ Log *log = GetLog(LLDBLog::Step);
+
+ // We got an instruction-step completed mach exception but we were not
+ // doing an instruction step on this thread.
+ if (!m_not_stepping_but_got_singlestep_exception)
+ return false;
+
+ RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
+ std::optional<addr_t> prev_pc = thread.GetPreviousFrameZeroPC();
+ if (!reg_ctx_sp || !prev_pc)
+ return false;
+
+ // The previous pc value and current pc value are the same.
+ if (*prev_pc != reg_ctx_sp->GetPC())
+ return false;
+
+ // We have a watchpoint -- this is the kernel bug.
+ ProcessSP process_sp = thread.GetProcess();
+ if (process_sp->GetWatchpointResourceList().GetSize()) {
+ LLDB_LOGF(log,
+ "Thread stopped with insn-step completed mach exception but "
+ "thread was not stepping; there is a hardware watchpoint set.");
+ return true;
+ }
+
+ // We have a hardware breakpoint -- this is the kernel bug.
+ auto &bp_site_list = process_sp->GetBreakpointSiteList();
+ for (auto &site : bp_site_list.Sites()) {
+ if (site->IsHardware() && site->IsEnabled()) {
+ LLDB_LOGF(log,
+ "Thread stopped with insn-step completed mach exception but "
+ "thread was not stepping; there is a hardware breakpoint set.");
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.h
new file mode 100644
index 000000000000..c612ac400b4c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.h
@@ -0,0 +1,76 @@
+//===-- StopInfoMachException.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_STOPINFOMACHEXCEPTION_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_STOPINFOMACHEXCEPTION_H
+
+#include <optional>
+#include <string>
+
+#include "lldb/Target/StopInfo.h"
+
+#if defined(__APPLE__)
+// Needed for the EXC_* defines
+#include <mach/exception.h>
+#endif
+
+namespace lldb_private {
+
+class StopInfoMachException : public StopInfo {
+ /// Determine the pointer-authentication related failure that caused this
+ /// exception. Returns true and fills out the failure description if there
+ /// is auth-related failure, and returns false otherwise.
+ bool DeterminePtrauthFailure(ExecutionContext &exe_ctx);
+
+public:
+ // Constructors and Destructors
+ StopInfoMachException(Thread &thread, uint32_t exc_type,
+ uint32_t exc_data_count, uint64_t exc_code,
+ uint64_t exc_subcode,
+ bool not_stepping_but_got_singlestep_exception)
+ : StopInfo(thread, exc_type), m_exc_data_count(exc_data_count),
+ m_exc_code(exc_code), m_exc_subcode(exc_subcode),
+ m_not_stepping_but_got_singlestep_exception(
+ not_stepping_but_got_singlestep_exception) {}
+
+ ~StopInfoMachException() override = default;
+
+ lldb::StopReason GetStopReason() const override {
+ return lldb::eStopReasonException;
+ }
+
+ const char *GetDescription() override;
+
+#if defined(__APPLE__)
+ struct MachException {
+ static const char *Name(exception_type_t exc_type);
+ static std::optional<exception_type_t> ExceptionCode(const char *name);
+ };
+#endif
+
+ // Since some mach exceptions will be reported as breakpoints, signals,
+ // or trace, we use this static accessor which will translate the mach
+ // exception into the correct StopInfo.
+ static lldb::StopInfoSP CreateStopReasonWithMachException(
+ Thread &thread, uint32_t exc_type, uint32_t exc_data_count,
+ uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted = true, bool adjust_pc_if_needed = false);
+
+ bool WasContinueInterrupted(Thread &thread) override;
+
+protected:
+ uint32_t m_exc_data_count;
+ uint64_t m_exc_code;
+ uint64_t m_exc_subcode;
+
+ bool m_not_stepping_but_got_singlestep_exception;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_STOPINFOMACHEXCEPTION_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
new file mode 100644
index 000000000000..89ecc757a68f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -0,0 +1,98 @@
+//===-- ThreadMemory.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/Utility/ThreadMemory.h"
+
+#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Unwind.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadMemory::ThreadMemory(Process &process, tid_t tid,
+ const ValueObjectSP &thread_info_valobj_sp)
+ : Thread(process, tid), m_backing_thread_sp(),
+ m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue(),
+ m_register_data_addr(LLDB_INVALID_ADDRESS) {}
+
+ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid,
+ llvm::StringRef name, llvm::StringRef queue,
+ lldb::addr_t register_data_addr)
+ : Thread(process, tid), m_backing_thread_sp(), m_thread_info_valobj_sp(),
+ m_name(std::string(name)), m_queue(std::string(queue)),
+ m_register_data_addr(register_data_addr) {}
+
+ThreadMemory::~ThreadMemory() { DestroyThread(); }
+
+void ThreadMemory::WillResume(StateType resume_state) {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->WillResume(resume_state);
+}
+
+void ThreadMemory::ClearStackFrames() {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->ClearStackFrames();
+ Thread::ClearStackFrames();
+}
+
+RegisterContextSP ThreadMemory::GetRegisterContext() {
+ if (!m_reg_context_sp)
+ m_reg_context_sp = std::make_shared<RegisterContextThreadMemory>(
+ *this, m_register_data_addr);
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadMemory::CreateRegisterContextForFrame(StackFrame *frame) {
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+ if (concrete_frame_idx == 0)
+ return GetRegisterContext();
+ return GetUnwinder().CreateRegisterContextForFrame(frame);
+}
+
+bool ThreadMemory::CalculateStopInfo() {
+ if (m_backing_thread_sp) {
+ lldb::StopInfoSP backing_stop_info_sp(
+ m_backing_thread_sp->GetPrivateStopInfo());
+ if (backing_stop_info_sp &&
+ backing_stop_info_sp->IsValidForOperatingSystemThread(*this)) {
+ backing_stop_info_sp->SetThread(shared_from_this());
+ SetStopInfo(backing_stop_info_sp);
+ return true;
+ }
+ } else {
+ ProcessSP process_sp(GetProcess());
+
+ if (process_sp) {
+ OperatingSystem *os = process_sp->GetOperatingSystem();
+ if (os) {
+ SetStopInfo(os->CreateThreadStopReason(this));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void ThreadMemory::RefreshStateAfterStop() {
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->RefreshStateAfterStop();
+
+ if (m_reg_context_sp)
+ m_reg_context_sp->InvalidateAllRegisters();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.h
new file mode 100644
index 000000000000..d124f5780ea9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.h
@@ -0,0 +1,107 @@
+//===-- ThreadMemory.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_THREADMEMORY_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_THREADMEMORY_H
+
+#include <string>
+
+#include "lldb/Target/Thread.h"
+
+class ThreadMemory : public lldb_private::Thread {
+public:
+ ThreadMemory(lldb_private::Process &process, lldb::tid_t tid,
+ const lldb::ValueObjectSP &thread_info_valobj_sp);
+
+ ThreadMemory(lldb_private::Process &process, lldb::tid_t tid,
+ llvm::StringRef name, llvm::StringRef queue,
+ lldb::addr_t register_data_addr);
+
+ ~ThreadMemory() override;
+
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+ bool CalculateStopInfo() override;
+
+ const char *GetInfo() override {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetInfo();
+ return nullptr;
+ }
+
+ const char *GetName() override {
+ if (!m_name.empty())
+ return m_name.c_str();
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetName();
+ return nullptr;
+ }
+
+ const char *GetQueueName() override {
+ if (!m_queue.empty())
+ return m_queue.c_str();
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetQueueName();
+ return nullptr;
+ }
+
+ void WillResume(lldb::StateType resume_state) override;
+
+ void DidResume() override {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->DidResume();
+ }
+
+ lldb::user_id_t GetProtocolID() const override {
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->GetProtocolID();
+ return Thread::GetProtocolID();
+ }
+
+ void RefreshStateAfterStop() override;
+
+ lldb::ValueObjectSP &GetValueObject() { return m_thread_info_valobj_sp; }
+
+ void ClearStackFrames() override;
+
+ void ClearBackingThread() override { m_backing_thread_sp.reset(); }
+
+ bool SetBackingThread(const lldb::ThreadSP &thread_sp) override {
+ // printf ("Thread 0x%llx is being backed by thread 0x%llx\n", GetID(),
+ // thread_sp->GetID());
+ m_backing_thread_sp = thread_sp;
+ return (bool)thread_sp;
+ }
+
+ lldb::ThreadSP GetBackingThread() const override {
+ return m_backing_thread_sp;
+ }
+
+protected:
+ bool IsOperatingSystemPluginThread() const override { return true; }
+
+ // If this memory thread is actually represented by a thread from the
+ // lldb_private::Process subclass, then fill in the thread here and
+ // all APIs will be routed through this thread object. If m_backing_thread_sp
+ // is empty, then this thread is simply in memory with no representation
+ // through the process plug-in.
+ lldb::ThreadSP m_backing_thread_sp;
+ lldb::ValueObjectSP m_thread_info_valobj_sp;
+ std::string m_name;
+ std::string m_queue;
+ lldb::addr_t m_register_data_addr;
+
+private:
+ ThreadMemory(const ThreadMemory &) = delete;
+ const ThreadMemory &operator=(const ThreadMemory &) = delete;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_THREADMEMORY_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h
new file mode 100644
index 000000000000..8f0eed4f02c9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h
@@ -0,0 +1,199 @@
+//===-- lldb-arm-register-enums.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM_REGISTER_ENUMS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM_REGISTER_ENUMS_H
+
+namespace lldb_private {
+// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+// Internal codes for all ARM registers.
+enum {
+ k_first_gpr_arm = 0,
+ gpr_r0_arm = k_first_gpr_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_r13_arm,
+ gpr_sp_arm = gpr_r13_arm,
+ gpr_r14_arm,
+ gpr_lr_arm = gpr_r14_arm,
+ gpr_r15_arm,
+ gpr_pc_arm = gpr_r15_arm,
+ gpr_cpsr_arm,
+
+ k_last_gpr_arm = gpr_cpsr_arm,
+
+ k_first_fpr_arm,
+ fpu_s0_arm = k_first_fpr_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,
+ k_last_fpr_arm = fpu_q15_arm,
+ exc_exception_arm,
+ exc_fsr_arm,
+ exc_far_arm,
+
+ dbg_bvr0_arm,
+ dbg_bvr1_arm,
+ dbg_bvr2_arm,
+ dbg_bvr3_arm,
+ dbg_bvr4_arm,
+ dbg_bvr5_arm,
+ dbg_bvr6_arm,
+ dbg_bvr7_arm,
+ dbg_bvr8_arm,
+ dbg_bvr9_arm,
+ dbg_bvr10_arm,
+ dbg_bvr11_arm,
+ dbg_bvr12_arm,
+ dbg_bvr13_arm,
+ dbg_bvr14_arm,
+ dbg_bvr15_arm,
+ dbg_bcr0_arm,
+ dbg_bcr1_arm,
+ dbg_bcr2_arm,
+ dbg_bcr3_arm,
+ dbg_bcr4_arm,
+ dbg_bcr5_arm,
+ dbg_bcr6_arm,
+ dbg_bcr7_arm,
+ dbg_bcr8_arm,
+ dbg_bcr9_arm,
+ dbg_bcr10_arm,
+ dbg_bcr11_arm,
+ dbg_bcr12_arm,
+ dbg_bcr13_arm,
+ dbg_bcr14_arm,
+ dbg_bcr15_arm,
+ dbg_wvr0_arm,
+ dbg_wvr1_arm,
+ dbg_wvr2_arm,
+ dbg_wvr3_arm,
+ dbg_wvr4_arm,
+ dbg_wvr5_arm,
+ dbg_wvr6_arm,
+ dbg_wvr7_arm,
+ dbg_wvr8_arm,
+ dbg_wvr9_arm,
+ dbg_wvr10_arm,
+ dbg_wvr11_arm,
+ dbg_wvr12_arm,
+ dbg_wvr13_arm,
+ dbg_wvr14_arm,
+ dbg_wvr15_arm,
+ dbg_wcr0_arm,
+ dbg_wcr1_arm,
+ dbg_wcr2_arm,
+ dbg_wcr3_arm,
+ dbg_wcr4_arm,
+ dbg_wcr5_arm,
+ dbg_wcr6_arm,
+ dbg_wcr7_arm,
+ dbg_wcr8_arm,
+ dbg_wcr9_arm,
+ dbg_wcr10_arm,
+ dbg_wcr11_arm,
+ dbg_wcr12_arm,
+ dbg_wcr13_arm,
+ dbg_wcr14_arm,
+ dbg_wcr15_arm,
+
+ k_num_registers_arm,
+ k_num_gpr_registers_arm = k_last_gpr_arm - k_first_gpr_arm + 1,
+ k_num_fpr_registers_arm = k_last_fpr_arm - k_first_fpr_arm + 1
+};
+}
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM_REGISTER_ENUMS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h
new file mode 100644
index 000000000000..39d47b8801cc
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h
@@ -0,0 +1,264 @@
+//===-- lldb-arm64-register-enums.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM64_REGISTER_ENUMS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM64_REGISTER_ENUMS_H
+
+namespace lldb_private {
+// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+// Internal codes for all ARM64 registers.
+enum {
+ k_first_gpr_arm64,
+ gpr_x0_arm64 = k_first_gpr_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,
+
+ gpr_w0_arm64,
+ gpr_w1_arm64,
+ gpr_w2_arm64,
+ gpr_w3_arm64,
+ gpr_w4_arm64,
+ gpr_w5_arm64,
+ gpr_w6_arm64,
+ gpr_w7_arm64,
+ gpr_w8_arm64,
+ gpr_w9_arm64,
+ gpr_w10_arm64,
+ gpr_w11_arm64,
+ gpr_w12_arm64,
+ gpr_w13_arm64,
+ gpr_w14_arm64,
+ gpr_w15_arm64,
+ gpr_w16_arm64,
+ gpr_w17_arm64,
+ gpr_w18_arm64,
+ gpr_w19_arm64,
+ gpr_w20_arm64,
+ gpr_w21_arm64,
+ gpr_w22_arm64,
+ gpr_w23_arm64,
+ gpr_w24_arm64,
+ gpr_w25_arm64,
+ gpr_w26_arm64,
+ gpr_w27_arm64,
+ gpr_w28_arm64,
+
+ k_last_gpr_arm64 = gpr_w28_arm64,
+
+ k_first_fpr_arm64,
+ fpu_v0_arm64 = k_first_fpr_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_s0_arm64,
+ fpu_s1_arm64,
+ fpu_s2_arm64,
+ fpu_s3_arm64,
+ fpu_s4_arm64,
+ fpu_s5_arm64,
+ fpu_s6_arm64,
+ fpu_s7_arm64,
+ fpu_s8_arm64,
+ fpu_s9_arm64,
+ fpu_s10_arm64,
+ fpu_s11_arm64,
+ fpu_s12_arm64,
+ fpu_s13_arm64,
+ fpu_s14_arm64,
+ fpu_s15_arm64,
+ fpu_s16_arm64,
+ fpu_s17_arm64,
+ fpu_s18_arm64,
+ fpu_s19_arm64,
+ fpu_s20_arm64,
+ fpu_s21_arm64,
+ fpu_s22_arm64,
+ fpu_s23_arm64,
+ fpu_s24_arm64,
+ fpu_s25_arm64,
+ fpu_s26_arm64,
+ fpu_s27_arm64,
+ fpu_s28_arm64,
+ fpu_s29_arm64,
+ fpu_s30_arm64,
+ fpu_s31_arm64,
+
+ fpu_d0_arm64,
+ fpu_d1_arm64,
+ fpu_d2_arm64,
+ fpu_d3_arm64,
+ fpu_d4_arm64,
+ fpu_d5_arm64,
+ fpu_d6_arm64,
+ fpu_d7_arm64,
+ fpu_d8_arm64,
+ fpu_d9_arm64,
+ fpu_d10_arm64,
+ fpu_d11_arm64,
+ fpu_d12_arm64,
+ fpu_d13_arm64,
+ fpu_d14_arm64,
+ fpu_d15_arm64,
+ fpu_d16_arm64,
+ fpu_d17_arm64,
+ fpu_d18_arm64,
+ fpu_d19_arm64,
+ fpu_d20_arm64,
+ fpu_d21_arm64,
+ fpu_d22_arm64,
+ fpu_d23_arm64,
+ fpu_d24_arm64,
+ fpu_d25_arm64,
+ fpu_d26_arm64,
+ fpu_d27_arm64,
+ fpu_d28_arm64,
+ fpu_d29_arm64,
+ fpu_d30_arm64,
+ fpu_d31_arm64,
+
+ fpu_fpsr_arm64,
+ fpu_fpcr_arm64,
+ k_last_fpr_arm64 = fpu_fpcr_arm64,
+
+ exc_far_arm64,
+ exc_esr_arm64,
+ exc_exception_arm64,
+
+ dbg_bvr0_arm64,
+ dbg_bvr1_arm64,
+ dbg_bvr2_arm64,
+ dbg_bvr3_arm64,
+ dbg_bvr4_arm64,
+ dbg_bvr5_arm64,
+ dbg_bvr6_arm64,
+ dbg_bvr7_arm64,
+ dbg_bvr8_arm64,
+ dbg_bvr9_arm64,
+ dbg_bvr10_arm64,
+ dbg_bvr11_arm64,
+ dbg_bvr12_arm64,
+ dbg_bvr13_arm64,
+ dbg_bvr14_arm64,
+ dbg_bvr15_arm64,
+ dbg_bcr0_arm64,
+ dbg_bcr1_arm64,
+ dbg_bcr2_arm64,
+ dbg_bcr3_arm64,
+ dbg_bcr4_arm64,
+ dbg_bcr5_arm64,
+ dbg_bcr6_arm64,
+ dbg_bcr7_arm64,
+ dbg_bcr8_arm64,
+ dbg_bcr9_arm64,
+ dbg_bcr10_arm64,
+ dbg_bcr11_arm64,
+ dbg_bcr12_arm64,
+ dbg_bcr13_arm64,
+ dbg_bcr14_arm64,
+ dbg_bcr15_arm64,
+ dbg_wvr0_arm64,
+ dbg_wvr1_arm64,
+ dbg_wvr2_arm64,
+ dbg_wvr3_arm64,
+ dbg_wvr4_arm64,
+ dbg_wvr5_arm64,
+ dbg_wvr6_arm64,
+ dbg_wvr7_arm64,
+ dbg_wvr8_arm64,
+ dbg_wvr9_arm64,
+ dbg_wvr10_arm64,
+ dbg_wvr11_arm64,
+ dbg_wvr12_arm64,
+ dbg_wvr13_arm64,
+ dbg_wvr14_arm64,
+ dbg_wvr15_arm64,
+ dbg_wcr0_arm64,
+ dbg_wcr1_arm64,
+ dbg_wcr2_arm64,
+ dbg_wcr3_arm64,
+ dbg_wcr4_arm64,
+ dbg_wcr5_arm64,
+ dbg_wcr6_arm64,
+ dbg_wcr7_arm64,
+ dbg_wcr8_arm64,
+ dbg_wcr9_arm64,
+ dbg_wcr10_arm64,
+ dbg_wcr11_arm64,
+ dbg_wcr12_arm64,
+ dbg_wcr13_arm64,
+ dbg_wcr14_arm64,
+ dbg_wcr15_arm64,
+
+ k_num_registers_arm64,
+ k_num_gpr_registers_arm64 = k_last_gpr_arm64 - k_first_gpr_arm64 + 1,
+ k_num_fpr_registers_arm64 = k_last_fpr_arm64 - k_first_fpr_arm64 + 1
+};
+}
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_ARM64_REGISTER_ENUMS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-loongarch-register-enums.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-loongarch-register-enums.h
new file mode 100644
index 000000000000..f55c807f86c0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-loongarch-register-enums.h
@@ -0,0 +1,178 @@
+//===-- lldb-loongarch-register-enums.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_LOONGARCH_REGISTER_ENUMS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_LOONGARCH_REGISTER_ENUMS_H
+
+// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+// Internal codes for all loongarch registers.
+enum {
+ // The same order as user_regs_struct in <asm/ptrace.h>
+ // note: these enum values are used as byte_offset
+ gpr_first_loongarch = 0,
+ gpr_r0_loongarch = gpr_first_loongarch,
+ gpr_r1_loongarch,
+ gpr_r2_loongarch,
+ gpr_r3_loongarch,
+ gpr_r4_loongarch,
+ gpr_r5_loongarch,
+ gpr_r6_loongarch,
+ gpr_r7_loongarch,
+ gpr_r8_loongarch,
+ gpr_r9_loongarch,
+ gpr_r10_loongarch,
+ gpr_r11_loongarch,
+ gpr_r12_loongarch,
+ gpr_r13_loongarch,
+ gpr_r14_loongarch,
+ gpr_r15_loongarch,
+ gpr_r16_loongarch,
+ gpr_r17_loongarch,
+ gpr_r18_loongarch,
+ gpr_r19_loongarch,
+ gpr_r20_loongarch,
+ gpr_r21_loongarch,
+ gpr_r22_loongarch,
+ gpr_r23_loongarch,
+ gpr_r24_loongarch,
+ gpr_r25_loongarch,
+ gpr_r26_loongarch,
+ gpr_r27_loongarch,
+ gpr_r28_loongarch,
+ gpr_r29_loongarch,
+ gpr_r30_loongarch,
+ gpr_r31_loongarch,
+ gpr_orig_a0_loongarch,
+ gpr_pc_loongarch,
+ gpr_badv_loongarch,
+ gpr_reserved0_loongarch,
+ gpr_reserved1_loongarch,
+ gpr_reserved2_loongarch,
+ gpr_reserved3_loongarch,
+ gpr_reserved4_loongarch,
+ gpr_reserved5_loongarch,
+ gpr_reserved6_loongarch,
+ gpr_reserved7_loongarch,
+ gpr_reserved8_loongarch,
+ gpr_reserved9_loongarch,
+ gpr_last_loongarch = 44,
+
+ gpr_zero_loongarch = gpr_r0_loongarch,
+ gpr_ra_loongarch = gpr_r1_loongarch,
+ gpr_tp_loongarch = gpr_r2_loongarch,
+ gpr_sp_loongarch = gpr_r3_loongarch,
+ gpr_a0_loongarch = gpr_r4_loongarch,
+ gpr_a1_loongarch = gpr_r5_loongarch,
+ gpr_a2_loongarch = gpr_r6_loongarch,
+ gpr_a3_loongarch = gpr_r7_loongarch,
+ gpr_a4_loongarch = gpr_r8_loongarch,
+ gpr_a5_loongarch = gpr_r9_loongarch,
+ gpr_a6_loongarch = gpr_r10_loongarch,
+ gpr_a7_loongarch = gpr_r11_loongarch,
+ gpr_t0_loongarch = gpr_r12_loongarch,
+ gpr_t1_loongarch = gpr_r13_loongarch,
+ gpr_t2_loongarch = gpr_r14_loongarch,
+ gpr_t3_loongarch = gpr_r15_loongarch,
+ gpr_t4_loongarch = gpr_r16_loongarch,
+ gpr_t5_loongarch = gpr_r17_loongarch,
+ gpr_t6_loongarch = gpr_r18_loongarch,
+ gpr_t7_loongarch = gpr_r19_loongarch,
+ gpr_t8_loongarch = gpr_r20_loongarch,
+ gpr_fp_loongarch = gpr_r22_loongarch,
+ gpr_s0_loongarch = gpr_r23_loongarch,
+ gpr_s1_loongarch = gpr_r24_loongarch,
+ gpr_s2_loongarch = gpr_r25_loongarch,
+ gpr_s3_loongarch = gpr_r26_loongarch,
+ gpr_s4_loongarch = gpr_r27_loongarch,
+ gpr_s5_loongarch = gpr_r28_loongarch,
+ gpr_s6_loongarch = gpr_r29_loongarch,
+ gpr_s7_loongarch = gpr_r30_loongarch,
+ gpr_s8_loongarch = gpr_r31_loongarch,
+
+ fpr_first_loongarch = 45,
+ fpr_f0_loongarch = fpr_first_loongarch,
+ fpr_f1_loongarch,
+ fpr_f2_loongarch,
+ fpr_f3_loongarch,
+ fpr_f4_loongarch,
+ fpr_f5_loongarch,
+ fpr_f6_loongarch,
+ fpr_f7_loongarch,
+ fpr_f8_loongarch,
+ fpr_f9_loongarch,
+ fpr_f10_loongarch,
+ fpr_f11_loongarch,
+ fpr_f12_loongarch,
+ fpr_f13_loongarch,
+ fpr_f14_loongarch,
+ fpr_f15_loongarch,
+ fpr_f16_loongarch,
+ fpr_f17_loongarch,
+ fpr_f18_loongarch,
+ fpr_f19_loongarch,
+ fpr_f20_loongarch,
+ fpr_f21_loongarch,
+ fpr_f22_loongarch,
+ fpr_f23_loongarch,
+ fpr_f24_loongarch,
+ fpr_f25_loongarch,
+ fpr_f26_loongarch,
+ fpr_f27_loongarch,
+ fpr_f28_loongarch,
+ fpr_f29_loongarch,
+ fpr_f30_loongarch,
+ fpr_f31_loongarch,
+ fpr_fcc0_loongarch,
+ fpr_fcc1_loongarch,
+ fpr_fcc2_loongarch,
+ fpr_fcc3_loongarch,
+ fpr_fcc4_loongarch,
+ fpr_fcc5_loongarch,
+ fpr_fcc6_loongarch,
+ fpr_fcc7_loongarch,
+ fpr_fcsr_loongarch,
+ fpr_last_loongarch = fpr_fcsr_loongarch,
+
+ fpr_fa0_loongarch = fpr_f0_loongarch,
+ fpr_fa1_loongarch = fpr_f1_loongarch,
+ fpr_fa2_loongarch = fpr_f2_loongarch,
+ fpr_fa3_loongarch = fpr_f3_loongarch,
+ fpr_fa4_loongarch = fpr_f4_loongarch,
+ fpr_fa5_loongarch = fpr_f5_loongarch,
+ fpr_fa6_loongarch = fpr_f6_loongarch,
+ fpr_fa7_loongarch = fpr_f7_loongarch,
+ fpr_ft0_loongarch = fpr_f8_loongarch,
+ fpr_ft1_loongarch = fpr_f9_loongarch,
+ fpr_ft2_loongarch = fpr_f10_loongarch,
+ fpr_ft3_loongarch = fpr_f11_loongarch,
+ fpr_ft4_loongarch = fpr_f12_loongarch,
+ fpr_ft5_loongarch = fpr_f13_loongarch,
+ fpr_ft6_loongarch = fpr_f14_loongarch,
+ fpr_ft7_loongarch = fpr_f15_loongarch,
+ fpr_ft8_loongarch = fpr_f16_loongarch,
+ fpr_ft9_loongarch = fpr_f17_loongarch,
+ fpr_ft10_loongarch = fpr_f18_loongarch,
+ fpr_ft11_loongarch = fpr_f19_loongarch,
+ fpr_ft12_loongarch = fpr_f20_loongarch,
+ fpr_ft13_loongarch = fpr_f21_loongarch,
+ fpr_ft14_loongarch = fpr_f22_loongarch,
+ fpr_ft15_loongarch = fpr_f23_loongarch,
+ fpr_fs0_loongarch = fpr_f24_loongarch,
+ fpr_fs1_loongarch = fpr_f25_loongarch,
+ fpr_fs2_loongarch = fpr_f26_loongarch,
+ fpr_fs3_loongarch = fpr_f27_loongarch,
+ fpr_fs4_loongarch = fpr_f28_loongarch,
+ fpr_fs5_loongarch = fpr_f29_loongarch,
+ fpr_fs6_loongarch = fpr_f30_loongarch,
+ fpr_fs7_loongarch = fpr_f31_loongarch,
+
+ k_num_registers_loongarch
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_LOONGARCH_REGISTER_ENUMS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h
new file mode 100644
index 000000000000..000f6e3847e7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h
@@ -0,0 +1,103 @@
+//===-- lldb-mips-freebsd-register-enums.h ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_MIPS_FREEBSD_REGISTER_ENUMS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_MIPS_FREEBSD_REGISTER_ENUMS_H
+
+namespace lldb_private {
+// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+// Internal codes for all mips registers.
+enum {
+ k_first_gpr_mips64,
+ gpr_zero_mips64 = k_first_gpr_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_ic_mips64,
+ gpr_dummy_mips64,
+ k_last_gpr_mips64 = gpr_dummy_mips64,
+
+ k_first_fpr_mips64,
+ fpr_f0_mips64 = k_first_fpr_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,
+ k_last_fpr_mips64 = fpr_fir_mips64,
+
+ k_num_registers_mips64,
+
+ k_num_gpr_registers_mips64 = k_last_gpr_mips64 - k_first_gpr_mips64 + 1,
+ k_num_fpr_registers_mips64 = k_last_fpr_mips64 - k_first_fpr_mips64 + 1,
+};
+} // namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_MIPS_FREEBSD_REGISTER_ENUMS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h
new file mode 100644
index 000000000000..40a75c006d84
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-ppc64-register-enums.h
@@ -0,0 +1,136 @@
+//===-- lldb-ppc64-register-enums.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64_REGISTER_ENUMS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64_REGISTER_ENUMS_H
+
+// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+// Internal codes for all ppc64 registers.
+enum {
+ k_first_gpr_ppc64,
+ gpr_r0_ppc64 = k_first_gpr_ppc64,
+ gpr_r1_ppc64,
+ gpr_r2_ppc64,
+ gpr_r3_ppc64,
+ gpr_r4_ppc64,
+ gpr_r5_ppc64,
+ gpr_r6_ppc64,
+ gpr_r7_ppc64,
+ gpr_r8_ppc64,
+ gpr_r9_ppc64,
+ gpr_r10_ppc64,
+ gpr_r11_ppc64,
+ gpr_r12_ppc64,
+ gpr_r13_ppc64,
+ gpr_r14_ppc64,
+ gpr_r15_ppc64,
+ gpr_r16_ppc64,
+ gpr_r17_ppc64,
+ gpr_r18_ppc64,
+ gpr_r19_ppc64,
+ gpr_r20_ppc64,
+ gpr_r21_ppc64,
+ gpr_r22_ppc64,
+ gpr_r23_ppc64,
+ gpr_r24_ppc64,
+ gpr_r25_ppc64,
+ gpr_r26_ppc64,
+ gpr_r27_ppc64,
+ gpr_r28_ppc64,
+ gpr_r29_ppc64,
+ gpr_r30_ppc64,
+ gpr_r31_ppc64,
+ gpr_cr_ppc64,
+ gpr_msr_ppc64,
+ gpr_xer_ppc64,
+ gpr_lr_ppc64,
+ gpr_ctr_ppc64,
+ gpr_pc_ppc64,
+ k_last_gpr_ppc64 = gpr_pc_ppc64,
+
+ k_first_fpr_ppc64,
+ fpr_f0_ppc64 = k_first_fpr_ppc64,
+ fpr_f1_ppc64,
+ fpr_f2_ppc64,
+ fpr_f3_ppc64,
+ fpr_f4_ppc64,
+ fpr_f5_ppc64,
+ fpr_f6_ppc64,
+ fpr_f7_ppc64,
+ fpr_f8_ppc64,
+ fpr_f9_ppc64,
+ fpr_f10_ppc64,
+ fpr_f11_ppc64,
+ fpr_f12_ppc64,
+ fpr_f13_ppc64,
+ fpr_f14_ppc64,
+ fpr_f15_ppc64,
+ fpr_f16_ppc64,
+ fpr_f17_ppc64,
+ fpr_f18_ppc64,
+ fpr_f19_ppc64,
+ fpr_f20_ppc64,
+ fpr_f21_ppc64,
+ fpr_f22_ppc64,
+ fpr_f23_ppc64,
+ fpr_f24_ppc64,
+ fpr_f25_ppc64,
+ fpr_f26_ppc64,
+ fpr_f27_ppc64,
+ fpr_f28_ppc64,
+ fpr_f29_ppc64,
+ fpr_f30_ppc64,
+ fpr_f31_ppc64,
+ fpr_fpscr_ppc64,
+ k_last_fpr_ppc64 = fpr_fpscr_ppc64,
+
+ k_first_vmx_ppc64,
+ vmx_vr0_ppc64 = k_first_vmx_ppc64,
+ vmx_vr1_ppc64,
+ vmx_vr2_ppc64,
+ vmx_vr3_ppc64,
+ vmx_vr4_ppc64,
+ vmx_vr5_ppc64,
+ vmx_vr6_ppc64,
+ vmx_vr7_ppc64,
+ vmx_vr8_ppc64,
+ vmx_vr9_ppc64,
+ vmx_vr10_ppc64,
+ vmx_vr11_ppc64,
+ vmx_vr12_ppc64,
+ vmx_vr13_ppc64,
+ vmx_vr14_ppc64,
+ vmx_vr15_ppc64,
+ vmx_vr16_ppc64,
+ vmx_vr17_ppc64,
+ vmx_vr18_ppc64,
+ vmx_vr19_ppc64,
+ vmx_vr20_ppc64,
+ vmx_vr21_ppc64,
+ vmx_vr22_ppc64,
+ vmx_vr23_ppc64,
+ vmx_vr24_ppc64,
+ vmx_vr25_ppc64,
+ vmx_vr26_ppc64,
+ vmx_vr27_ppc64,
+ vmx_vr28_ppc64,
+ vmx_vr29_ppc64,
+ vmx_vr30_ppc64,
+ vmx_vr31_ppc64,
+ vmx_vscr_ppc64,
+ vmx_vrsave_ppc64,
+ k_last_vmx_ppc64 = vmx_vrsave_ppc64,
+
+ k_num_registers_ppc64,
+ k_num_gpr_registers_ppc64 = k_last_gpr_ppc64 - k_first_gpr_ppc64 + 1,
+ k_num_fpr_registers_ppc64 = k_last_fpr_ppc64 - k_first_fpr_ppc64 + 1,
+ k_num_vmx_registers_ppc64 = k_last_vmx_ppc64 - k_first_vmx_ppc64 + 1,
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64_REGISTER_ENUMS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-ppc64le-register-enums.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-ppc64le-register-enums.h
new file mode 100644
index 000000000000..a7b5bc5ad9e3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-ppc64le-register-enums.h
@@ -0,0 +1,207 @@
+//===-- lldb-ppc64le-register-enums.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64LE_REGISTER_ENUMS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64LE_REGISTER_ENUMS_H
+
+// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+// Internal codes for all ppc64le registers.
+enum {
+ k_first_gpr_ppc64le,
+ gpr_r0_ppc64le = k_first_gpr_ppc64le,
+ gpr_r1_ppc64le,
+ gpr_r2_ppc64le,
+ gpr_r3_ppc64le,
+ gpr_r4_ppc64le,
+ gpr_r5_ppc64le,
+ gpr_r6_ppc64le,
+ gpr_r7_ppc64le,
+ gpr_r8_ppc64le,
+ gpr_r9_ppc64le,
+ gpr_r10_ppc64le,
+ gpr_r11_ppc64le,
+ gpr_r12_ppc64le,
+ gpr_r13_ppc64le,
+ gpr_r14_ppc64le,
+ gpr_r15_ppc64le,
+ gpr_r16_ppc64le,
+ gpr_r17_ppc64le,
+ gpr_r18_ppc64le,
+ gpr_r19_ppc64le,
+ gpr_r20_ppc64le,
+ gpr_r21_ppc64le,
+ gpr_r22_ppc64le,
+ gpr_r23_ppc64le,
+ gpr_r24_ppc64le,
+ gpr_r25_ppc64le,
+ gpr_r26_ppc64le,
+ gpr_r27_ppc64le,
+ gpr_r28_ppc64le,
+ gpr_r29_ppc64le,
+ gpr_r30_ppc64le,
+ gpr_r31_ppc64le,
+ gpr_pc_ppc64le,
+ gpr_msr_ppc64le,
+ gpr_origr3_ppc64le,
+ gpr_ctr_ppc64le,
+ gpr_lr_ppc64le,
+ gpr_xer_ppc64le,
+ gpr_cr_ppc64le,
+ gpr_softe_ppc64le,
+ gpr_trap_ppc64le,
+ k_last_gpr_ppc64le = gpr_trap_ppc64le,
+
+ k_first_fpr_ppc64le,
+ fpr_f0_ppc64le = k_first_fpr_ppc64le,
+ fpr_f1_ppc64le,
+ fpr_f2_ppc64le,
+ fpr_f3_ppc64le,
+ fpr_f4_ppc64le,
+ fpr_f5_ppc64le,
+ fpr_f6_ppc64le,
+ fpr_f7_ppc64le,
+ fpr_f8_ppc64le,
+ fpr_f9_ppc64le,
+ fpr_f10_ppc64le,
+ fpr_f11_ppc64le,
+ fpr_f12_ppc64le,
+ fpr_f13_ppc64le,
+ fpr_f14_ppc64le,
+ fpr_f15_ppc64le,
+ fpr_f16_ppc64le,
+ fpr_f17_ppc64le,
+ fpr_f18_ppc64le,
+ fpr_f19_ppc64le,
+ fpr_f20_ppc64le,
+ fpr_f21_ppc64le,
+ fpr_f22_ppc64le,
+ fpr_f23_ppc64le,
+ fpr_f24_ppc64le,
+ fpr_f25_ppc64le,
+ fpr_f26_ppc64le,
+ fpr_f27_ppc64le,
+ fpr_f28_ppc64le,
+ fpr_f29_ppc64le,
+ fpr_f30_ppc64le,
+ fpr_f31_ppc64le,
+ fpr_fpscr_ppc64le,
+ k_last_fpr_ppc64le = fpr_fpscr_ppc64le,
+
+ k_first_vmx_ppc64le,
+ vmx_vr0_ppc64le = k_first_vmx_ppc64le,
+ vmx_vr1_ppc64le,
+ vmx_vr2_ppc64le,
+ vmx_vr3_ppc64le,
+ vmx_vr4_ppc64le,
+ vmx_vr5_ppc64le,
+ vmx_vr6_ppc64le,
+ vmx_vr7_ppc64le,
+ vmx_vr8_ppc64le,
+ vmx_vr9_ppc64le,
+ vmx_vr10_ppc64le,
+ vmx_vr11_ppc64le,
+ vmx_vr12_ppc64le,
+ vmx_vr13_ppc64le,
+ vmx_vr14_ppc64le,
+ vmx_vr15_ppc64le,
+ vmx_vr16_ppc64le,
+ vmx_vr17_ppc64le,
+ vmx_vr18_ppc64le,
+ vmx_vr19_ppc64le,
+ vmx_vr20_ppc64le,
+ vmx_vr21_ppc64le,
+ vmx_vr22_ppc64le,
+ vmx_vr23_ppc64le,
+ vmx_vr24_ppc64le,
+ vmx_vr25_ppc64le,
+ vmx_vr26_ppc64le,
+ vmx_vr27_ppc64le,
+ vmx_vr28_ppc64le,
+ vmx_vr29_ppc64le,
+ vmx_vr30_ppc64le,
+ vmx_vr31_ppc64le,
+ vmx_vscr_ppc64le,
+ vmx_vrsave_ppc64le,
+ k_last_vmx_ppc64le = vmx_vrsave_ppc64le,
+
+ k_first_vsx_ppc64le,
+ vsx_vs0_ppc64le = k_first_vsx_ppc64le,
+ vsx_vs1_ppc64le,
+ vsx_vs2_ppc64le,
+ vsx_vs3_ppc64le,
+ vsx_vs4_ppc64le,
+ vsx_vs5_ppc64le,
+ vsx_vs6_ppc64le,
+ vsx_vs7_ppc64le,
+ vsx_vs8_ppc64le,
+ vsx_vs9_ppc64le,
+ vsx_vs10_ppc64le,
+ vsx_vs11_ppc64le,
+ vsx_vs12_ppc64le,
+ vsx_vs13_ppc64le,
+ vsx_vs14_ppc64le,
+ vsx_vs15_ppc64le,
+ vsx_vs16_ppc64le,
+ vsx_vs17_ppc64le,
+ vsx_vs18_ppc64le,
+ vsx_vs19_ppc64le,
+ vsx_vs20_ppc64le,
+ vsx_vs21_ppc64le,
+ vsx_vs22_ppc64le,
+ vsx_vs23_ppc64le,
+ vsx_vs24_ppc64le,
+ vsx_vs25_ppc64le,
+ vsx_vs26_ppc64le,
+ vsx_vs27_ppc64le,
+ vsx_vs28_ppc64le,
+ vsx_vs29_ppc64le,
+ vsx_vs30_ppc64le,
+ vsx_vs31_ppc64le,
+ vsx_vs32_ppc64le,
+ vsx_vs33_ppc64le,
+ vsx_vs34_ppc64le,
+ vsx_vs35_ppc64le,
+ vsx_vs36_ppc64le,
+ vsx_vs37_ppc64le,
+ vsx_vs38_ppc64le,
+ vsx_vs39_ppc64le,
+ vsx_vs40_ppc64le,
+ vsx_vs41_ppc64le,
+ vsx_vs42_ppc64le,
+ vsx_vs43_ppc64le,
+ vsx_vs44_ppc64le,
+ vsx_vs45_ppc64le,
+ vsx_vs46_ppc64le,
+ vsx_vs47_ppc64le,
+ vsx_vs48_ppc64le,
+ vsx_vs49_ppc64le,
+ vsx_vs50_ppc64le,
+ vsx_vs51_ppc64le,
+ vsx_vs52_ppc64le,
+ vsx_vs53_ppc64le,
+ vsx_vs54_ppc64le,
+ vsx_vs55_ppc64le,
+ vsx_vs56_ppc64le,
+ vsx_vs57_ppc64le,
+ vsx_vs58_ppc64le,
+ vsx_vs59_ppc64le,
+ vsx_vs60_ppc64le,
+ vsx_vs61_ppc64le,
+ vsx_vs62_ppc64le,
+ vsx_vs63_ppc64le,
+ k_last_vsx_ppc64le = vsx_vs63_ppc64le,
+
+ k_num_registers_ppc64le,
+ k_num_gpr_registers_ppc64le = k_last_gpr_ppc64le - k_first_gpr_ppc64le + 1,
+ k_num_fpr_registers_ppc64le = k_last_fpr_ppc64le - k_first_fpr_ppc64le + 1,
+ k_num_vmx_registers_ppc64le = k_last_vmx_ppc64le - k_first_vmx_ppc64le + 1,
+ k_num_vsx_registers_ppc64le = k_last_vsx_ppc64le - k_first_vsx_ppc64le + 1,
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_PPC64LE_REGISTER_ENUMS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-riscv-register-enums.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-riscv-register-enums.h
new file mode 100644
index 000000000000..caec313750ab
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-riscv-register-enums.h
@@ -0,0 +1,193 @@
+//===-- lldb-riscv-register-enums.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_RISCV_REGISTER_ENUMS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_RISCV_REGISTER_ENUMS_H
+
+// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+// Internal codes for all riscv registers.
+enum {
+ // The same order as user_regs_struct in <asm/ptrace.h>
+ // note: these enum values are used as byte_offset
+ gpr_first_riscv = 0,
+ gpr_pc_riscv = gpr_first_riscv,
+ gpr_x1_riscv,
+ gpr_x2_riscv,
+ gpr_x3_riscv,
+ gpr_x4_riscv,
+ gpr_x5_riscv,
+ gpr_x6_riscv,
+ gpr_x7_riscv,
+ gpr_x8_riscv,
+ gpr_x9_riscv,
+ gpr_x10_riscv,
+ gpr_x11_riscv,
+ gpr_x12_riscv,
+ gpr_x13_riscv,
+ gpr_x14_riscv,
+ gpr_x15_riscv,
+ gpr_x16_riscv,
+ gpr_x17_riscv,
+ gpr_x18_riscv,
+ gpr_x19_riscv,
+ gpr_x20_riscv,
+ gpr_x21_riscv,
+ gpr_x22_riscv,
+ gpr_x23_riscv,
+ gpr_x24_riscv,
+ gpr_x25_riscv,
+ gpr_x26_riscv,
+ gpr_x27_riscv,
+ gpr_x28_riscv,
+ gpr_x29_riscv,
+ gpr_x30_riscv,
+ gpr_x31_riscv,
+ gpr_x0_riscv,
+ gpr_zero_riscv = gpr_x0_riscv,
+ gpr_ra_riscv = gpr_x1_riscv,
+ gpr_sp_riscv = gpr_x2_riscv,
+ gpr_gp_riscv = gpr_x3_riscv,
+ gpr_tp_riscv = gpr_x4_riscv,
+ gpr_t0_riscv = gpr_x5_riscv,
+ gpr_t1_riscv = gpr_x6_riscv,
+ gpr_t2_riscv = gpr_x7_riscv,
+ gpr_fp_riscv = gpr_x8_riscv,
+ gpr_s1_riscv = gpr_x9_riscv,
+ gpr_a0_riscv = gpr_x10_riscv,
+ gpr_a1_riscv = gpr_x11_riscv,
+ gpr_a2_riscv = gpr_x12_riscv,
+ gpr_a3_riscv = gpr_x13_riscv,
+ gpr_a4_riscv = gpr_x14_riscv,
+ gpr_a5_riscv = gpr_x15_riscv,
+ gpr_a6_riscv = gpr_x16_riscv,
+ gpr_a7_riscv = gpr_x17_riscv,
+ gpr_s2_riscv = gpr_x18_riscv,
+ gpr_s3_riscv = gpr_x19_riscv,
+ gpr_s4_riscv = gpr_x20_riscv,
+ gpr_s5_riscv = gpr_x21_riscv,
+ gpr_s6_riscv = gpr_x22_riscv,
+ gpr_s7_riscv = gpr_x23_riscv,
+ gpr_s8_riscv = gpr_x24_riscv,
+ gpr_s9_riscv = gpr_x25_riscv,
+ gpr_s10_riscv = gpr_x26_riscv,
+ gpr_s11_riscv = gpr_x27_riscv,
+ gpr_t3_riscv = gpr_x28_riscv,
+ gpr_t4_riscv = gpr_x29_riscv,
+ gpr_t5_riscv = gpr_x30_riscv,
+ gpr_t6_riscv = gpr_x31_riscv,
+ gpr_last_riscv = gpr_x0_riscv,
+
+ fpr_first_riscv = 33,
+ fpr_f0_riscv = fpr_first_riscv,
+ fpr_f1_riscv,
+ fpr_f2_riscv,
+ fpr_f3_riscv,
+ fpr_f4_riscv,
+ fpr_f5_riscv,
+ fpr_f6_riscv,
+ fpr_f7_riscv,
+ fpr_f8_riscv,
+ fpr_f9_riscv,
+ fpr_f10_riscv,
+ fpr_f11_riscv,
+ fpr_f12_riscv,
+ fpr_f13_riscv,
+ fpr_f14_riscv,
+ fpr_f15_riscv,
+ fpr_f16_riscv,
+ fpr_f17_riscv,
+ fpr_f18_riscv,
+ fpr_f19_riscv,
+ fpr_f20_riscv,
+ fpr_f21_riscv,
+ fpr_f22_riscv,
+ fpr_f23_riscv,
+ fpr_f24_riscv,
+ fpr_f25_riscv,
+ fpr_f26_riscv,
+ fpr_f27_riscv,
+ fpr_f28_riscv,
+ fpr_f29_riscv,
+ fpr_f30_riscv,
+ fpr_f31_riscv,
+
+ fpr_fcsr_riscv,
+ fpr_ft0_riscv = fpr_f0_riscv,
+ fpr_ft1_riscv = fpr_f1_riscv,
+ fpr_ft2_riscv = fpr_f2_riscv,
+ fpr_ft3_riscv = fpr_f3_riscv,
+ fpr_ft4_riscv = fpr_f4_riscv,
+ fpr_ft5_riscv = fpr_f5_riscv,
+ fpr_ft6_riscv = fpr_f6_riscv,
+ fpr_ft7_riscv = fpr_f7_riscv,
+ fpr_fs0_riscv = fpr_f8_riscv,
+ fpr_fs1_riscv = fpr_f9_riscv,
+ fpr_fa0_riscv = fpr_f10_riscv,
+ fpr_fa1_riscv = fpr_f11_riscv,
+ fpr_fa2_riscv = fpr_f12_riscv,
+ fpr_fa3_riscv = fpr_f13_riscv,
+ fpr_fa4_riscv = fpr_f14_riscv,
+ fpr_fa5_riscv = fpr_f15_riscv,
+ fpr_fa6_riscv = fpr_f16_riscv,
+ fpr_fa7_riscv = fpr_f17_riscv,
+ fpr_fs2_riscv = fpr_f18_riscv,
+ fpr_fs3_riscv = fpr_f19_riscv,
+ fpr_fs4_riscv = fpr_f20_riscv,
+ fpr_fs5_riscv = fpr_f21_riscv,
+ fpr_fs6_riscv = fpr_f22_riscv,
+ fpr_fs7_riscv = fpr_f23_riscv,
+ fpr_fs8_riscv = fpr_f24_riscv,
+ fpr_fs9_riscv = fpr_f25_riscv,
+ fpr_fs10_riscv = fpr_f26_riscv,
+ fpr_fs11_riscv = fpr_f27_riscv,
+ fpr_ft8_riscv = fpr_f28_riscv,
+ fpr_ft9_riscv = fpr_f29_riscv,
+ fpr_ft10_riscv = fpr_f30_riscv,
+ fpr_ft11_riscv = fpr_f31_riscv,
+ fpr_last_riscv = fpr_fcsr_riscv,
+
+ vpr_first_riscv = 66,
+ vpr_v0_riscv = vpr_first_riscv,
+ vpr_v1_riscv,
+ vpr_v2_riscv,
+ vpr_v3_riscv,
+ vpr_v4_riscv,
+ vpr_v5_riscv,
+ vpr_v6_riscv,
+ vpr_v7_riscv,
+ vpr_v8_riscv,
+ vpr_v9_riscv,
+ vpr_v10_riscv,
+ vpr_v11_riscv,
+ vpr_v12_riscv,
+ vpr_v13_riscv,
+ vpr_v14_riscv,
+ vpr_v15_riscv,
+ vpr_v16_riscv,
+ vpr_v17_riscv,
+ vpr_v18_riscv,
+ vpr_v19_riscv,
+ vpr_v20_riscv,
+ vpr_v21_riscv,
+ vpr_v22_riscv,
+ vpr_v23_riscv,
+ vpr_v24_riscv,
+ vpr_v25_riscv,
+ vpr_v26_riscv,
+ vpr_v27_riscv,
+ vpr_v28_riscv,
+ vpr_v29_riscv,
+ vpr_v30_riscv,
+ vpr_v31_riscv,
+ vpr_last_riscv = vpr_v31_riscv,
+
+ k_num_registers_riscv
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_RISCV_REGISTER_ENUMS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-s390x-register-enums.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-s390x-register-enums.h
new file mode 100644
index 000000000000..23c441e1c803
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-s390x-register-enums.h
@@ -0,0 +1,90 @@
+//===-- lldb-s390x-register-enums.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_S390X_REGISTER_ENUMS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_S390X_REGISTER_ENUMS_H
+
+namespace lldb_private {
+// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+// Internal codes for all s390x registers.
+enum {
+ k_first_gpr_s390x,
+ lldb_r0_s390x = k_first_gpr_s390x,
+ lldb_r1_s390x,
+ lldb_r2_s390x,
+ lldb_r3_s390x,
+ lldb_r4_s390x,
+ lldb_r5_s390x,
+ lldb_r6_s390x,
+ lldb_r7_s390x,
+ lldb_r8_s390x,
+ lldb_r9_s390x,
+ lldb_r10_s390x,
+ lldb_r11_s390x,
+ lldb_r12_s390x,
+ lldb_r13_s390x,
+ lldb_r14_s390x,
+ lldb_r15_s390x,
+ lldb_acr0_s390x,
+ lldb_acr1_s390x,
+ lldb_acr2_s390x,
+ lldb_acr3_s390x,
+ lldb_acr4_s390x,
+ lldb_acr5_s390x,
+ lldb_acr6_s390x,
+ lldb_acr7_s390x,
+ lldb_acr8_s390x,
+ lldb_acr9_s390x,
+ lldb_acr10_s390x,
+ lldb_acr11_s390x,
+ lldb_acr12_s390x,
+ lldb_acr13_s390x,
+ lldb_acr14_s390x,
+ lldb_acr15_s390x,
+ lldb_pswm_s390x,
+ lldb_pswa_s390x,
+ k_last_gpr_s390x = lldb_pswa_s390x,
+
+ k_first_fpr_s390x,
+ lldb_f0_s390x = k_first_fpr_s390x,
+ lldb_f1_s390x,
+ lldb_f2_s390x,
+ lldb_f3_s390x,
+ lldb_f4_s390x,
+ lldb_f5_s390x,
+ lldb_f6_s390x,
+ lldb_f7_s390x,
+ lldb_f8_s390x,
+ lldb_f9_s390x,
+ lldb_f10_s390x,
+ lldb_f11_s390x,
+ lldb_f12_s390x,
+ lldb_f13_s390x,
+ lldb_f14_s390x,
+ lldb_f15_s390x,
+ lldb_fpc_s390x,
+ k_last_fpr_s390x = lldb_fpc_s390x,
+
+ // These are only available on Linux.
+ k_first_linux_s390x,
+ lldb_orig_r2_s390x = k_first_linux_s390x,
+ lldb_last_break_s390x,
+ lldb_system_call_s390x,
+ k_last_linux_s390x = lldb_system_call_s390x,
+
+ k_num_registers_s390x,
+ k_num_gpr_registers_s390x = k_last_gpr_s390x - k_first_gpr_s390x + 1,
+ k_num_fpr_registers_s390x = k_last_fpr_s390x - k_first_fpr_s390x + 1,
+ k_num_linux_registers_s390x = k_last_linux_s390x - k_first_linux_s390x + 1,
+ k_num_user_registers_s390x =
+ k_num_gpr_registers_s390x + k_num_fpr_registers_s390x,
+};
+}
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_S390X_REGISTER_ENUMS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h
new file mode 100644
index 000000000000..85aa254d6621
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h
@@ -0,0 +1,517 @@
+//===-- lldb-x86-register-enums.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_X86_REGISTER_ENUMS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_X86_REGISTER_ENUMS_H
+
+namespace lldb_private {
+// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+// Internal codes for all i386 registers.
+enum {
+ k_first_gpr_i386,
+ lldb_eax_i386 = k_first_gpr_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,
+
+ k_first_alias_i386,
+ lldb_ax_i386 = k_first_alias_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,
+ k_last_alias_i386 = lldb_dl_i386,
+
+ k_last_gpr_i386 = k_last_alias_i386,
+
+ k_first_fpr_i386,
+ lldb_fctrl_i386 = k_first_fpr_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,
+ k_last_fpr_i386 = lldb_xmm7_i386,
+
+ k_first_avx_i386,
+ lldb_ymm0_i386 = k_first_avx_i386,
+ lldb_ymm1_i386,
+ lldb_ymm2_i386,
+ lldb_ymm3_i386,
+ lldb_ymm4_i386,
+ lldb_ymm5_i386,
+ lldb_ymm6_i386,
+ lldb_ymm7_i386,
+ k_last_avx_i386 = lldb_ymm7_i386,
+
+ k_first_mpxr_i386,
+ lldb_bnd0_i386 = k_first_mpxr_i386,
+ lldb_bnd1_i386,
+ lldb_bnd2_i386,
+ lldb_bnd3_i386,
+ k_last_mpxr_i386 = lldb_bnd3_i386,
+
+ k_first_mpxc_i386,
+ lldb_bndcfgu_i386 = k_first_mpxc_i386,
+ lldb_bndstatus_i386,
+ k_last_mpxc_i386 = lldb_bndstatus_i386,
+
+ k_first_dbr_i386,
+ lldb_dr0_i386 = k_first_dbr_i386,
+ lldb_dr1_i386,
+ lldb_dr2_i386,
+ lldb_dr3_i386,
+ lldb_dr4_i386,
+ lldb_dr5_i386,
+ lldb_dr6_i386,
+ lldb_dr7_i386,
+ k_last_dbr_i386 = lldb_dr7_i386,
+
+ k_num_registers_i386,
+ k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1,
+ k_num_fpr_registers_i386 = k_last_fpr_i386 - k_first_fpr_i386 + 1,
+ k_num_avx_registers_i386 = k_last_avx_i386 - k_first_avx_i386 + 1,
+ k_num_mpx_registers_i386 = k_last_mpxc_i386 - k_first_mpxr_i386 + 1,
+ k_num_user_registers_i386 = k_num_gpr_registers_i386 +
+ k_num_fpr_registers_i386 +
+ k_num_avx_registers_i386 +
+ k_num_mpx_registers_i386,
+ k_num_dbr_registers_i386 = k_last_dbr_i386 - k_first_dbr_i386 + 1,
+};
+
+// Internal codes for all x86_64 registers.
+enum {
+ k_first_gpr_x86_64,
+ lldb_rax_x86_64 = k_first_gpr_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,
+
+ k_first_alias_x86_64,
+ lldb_eax_x86_64 = k_first_alias_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 of r8
+ lldb_r9d_x86_64, // Low 32 bits of r9
+ lldb_r10d_x86_64, // Low 32 bits of r10
+ lldb_r11d_x86_64, // Low 32 bits of r11
+ lldb_r12d_x86_64, // Low 32 bits of r12
+ lldb_r13d_x86_64, // Low 32 bits of r13
+ lldb_r14d_x86_64, // Low 32 bits of r14
+ lldb_r15d_x86_64, // Low 32 bits of 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 of r8
+ lldb_r9w_x86_64, // Low 16 bits of r9
+ lldb_r10w_x86_64, // Low 16 bits of r10
+ lldb_r11w_x86_64, // Low 16 bits of r11
+ lldb_r12w_x86_64, // Low 16 bits of r12
+ lldb_r13w_x86_64, // Low 16 bits of r13
+ lldb_r14w_x86_64, // Low 16 bits of r14
+ lldb_r15w_x86_64, // Low 16 bits of 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 of r8
+ lldb_r9l_x86_64, // Low 8 bits of r9
+ lldb_r10l_x86_64, // Low 8 bits of r10
+ lldb_r11l_x86_64, // Low 8 bits of r11
+ lldb_r12l_x86_64, // Low 8 bits of r12
+ lldb_r13l_x86_64, // Low 8 bits of r13
+ lldb_r14l_x86_64, // Low 8 bits of r14
+ lldb_r15l_x86_64, // Low 8 bits of r15
+ k_last_alias_x86_64 = lldb_r15l_x86_64,
+
+ k_last_gpr_x86_64 = k_last_alias_x86_64,
+
+ k_first_fpr_x86_64,
+ lldb_fctrl_x86_64 = k_first_fpr_x86_64,
+ lldb_fstat_x86_64,
+ lldb_ftag_x86_64,
+ lldb_fop_x86_64,
+ lldb_fiseg_x86_64,
+ lldb_fioff_x86_64,
+ lldb_fip_x86_64,
+ lldb_foseg_x86_64,
+ lldb_fooff_x86_64,
+ lldb_fdp_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,
+ k_last_fpr_x86_64 = lldb_xmm15_x86_64,
+
+ k_first_avx_x86_64,
+ lldb_ymm0_x86_64 = k_first_avx_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,
+ k_last_avx_x86_64 = lldb_ymm15_x86_64,
+
+ k_first_mpxr_x86_64,
+ lldb_bnd0_x86_64 = k_first_mpxr_x86_64,
+ lldb_bnd1_x86_64,
+ lldb_bnd2_x86_64,
+ lldb_bnd3_x86_64,
+ k_last_mpxr_x86_64 = lldb_bnd3_x86_64,
+
+ k_first_mpxc_x86_64,
+ lldb_bndcfgu_x86_64 = k_first_mpxc_x86_64,
+ lldb_bndstatus_x86_64,
+ k_last_mpxc_x86_64 = lldb_bndstatus_x86_64,
+
+ k_first_dbr_x86_64,
+ lldb_dr0_x86_64 = k_first_dbr_x86_64,
+ lldb_dr1_x86_64,
+ lldb_dr2_x86_64,
+ lldb_dr3_x86_64,
+ lldb_dr4_x86_64,
+ lldb_dr5_x86_64,
+ lldb_dr6_x86_64,
+ lldb_dr7_x86_64,
+ k_last_dbr_x86_64 = lldb_dr7_x86_64,
+
+ k_num_registers_x86_64,
+ k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1,
+ k_num_fpr_registers_x86_64 = k_last_fpr_x86_64 - k_first_fpr_x86_64 + 1,
+ k_num_avx_registers_x86_64 = k_last_avx_x86_64 - k_first_avx_x86_64 + 1,
+ k_num_mpx_registers_x86_64 = k_last_mpxc_x86_64 - k_first_mpxr_x86_64 + 1,
+ k_num_user_registers_x86_64 = k_num_gpr_registers_x86_64 +
+ k_num_fpr_registers_x86_64 +
+ k_num_avx_registers_x86_64 +
+ k_num_mpx_registers_x86_64,
+ k_num_dbr_registers_x86_64 = k_last_dbr_x86_64 - k_first_dbr_x86_64 + 1,
+};
+
+// For platform that supports fs_base/gs_base registers.
+namespace x86_64_with_base {
+enum {
+ k_first_gpr,
+ lldb_rax = k_first_gpr,
+ lldb_rbx,
+ lldb_rcx,
+ lldb_rdx,
+ lldb_rdi,
+ lldb_rsi,
+ lldb_rbp,
+ lldb_rsp,
+ lldb_r8,
+ lldb_r9,
+ lldb_r10,
+ lldb_r11,
+ lldb_r12,
+ lldb_r13,
+ lldb_r14,
+ lldb_r15,
+ lldb_rip,
+ lldb_rflags,
+ lldb_cs,
+ lldb_fs,
+ lldb_gs,
+ lldb_ss,
+ lldb_fs_base,
+ lldb_gs_base,
+ lldb_ds,
+ lldb_es,
+
+ k_first_alias,
+ lldb_eax = k_first_alias,
+ lldb_ebx,
+ lldb_ecx,
+ lldb_edx,
+ lldb_edi,
+ lldb_esi,
+ lldb_ebp,
+ lldb_esp,
+ lldb_r8d, // Low 32 bits of r8
+ lldb_r9d, // Low 32 bits of r9
+ lldb_r10d, // Low 32 bits of r10
+ lldb_r11d, // Low 32 bits of r11
+ lldb_r12d, // Low 32 bits of r12
+ lldb_r13d, // Low 32 bits of r13
+ lldb_r14d, // Low 32 bits of r14
+ lldb_r15d, // Low 32 bits of r15
+ lldb_ax,
+ lldb_bx,
+ lldb_cx,
+ lldb_dx,
+ lldb_di,
+ lldb_si,
+ lldb_bp,
+ lldb_sp,
+ lldb_r8w, // Low 16 bits of r8
+ lldb_r9w, // Low 16 bits of r9
+ lldb_r10w, // Low 16 bits of r10
+ lldb_r11w, // Low 16 bits of r11
+ lldb_r12w, // Low 16 bits of r12
+ lldb_r13w, // Low 16 bits of r13
+ lldb_r14w, // Low 16 bits of r14
+ lldb_r15w, // Low 16 bits of r15
+ lldb_ah,
+ lldb_bh,
+ lldb_ch,
+ lldb_dh,
+ lldb_al,
+ lldb_bl,
+ lldb_cl,
+ lldb_dl,
+ lldb_dil,
+ lldb_sil,
+ lldb_bpl,
+ lldb_spl,
+ lldb_r8l, // Low 8 bits of r8
+ lldb_r9l, // Low 8 bits of r9
+ lldb_r10l, // Low 8 bits of r10
+ lldb_r11l, // Low 8 bits of r11
+ lldb_r12l, // Low 8 bits of r12
+ lldb_r13l, // Low 8 bits of r13
+ lldb_r14l, // Low 8 bits of r14
+ lldb_r15l, // Low 8 bits of r15
+ k_last_alias = lldb_r15l,
+
+ k_last_gpr = k_last_alias,
+
+ k_first_fpr,
+ lldb_fctrl = k_first_fpr,
+ lldb_fstat,
+ lldb_ftag,
+ lldb_fop,
+ lldb_fiseg,
+ lldb_fioff,
+ lldb_fip,
+ lldb_foseg,
+ lldb_fooff,
+ lldb_fdp,
+ lldb_mxcsr,
+ lldb_mxcsrmask,
+ lldb_st0,
+ lldb_st1,
+ lldb_st2,
+ lldb_st3,
+ lldb_st4,
+ lldb_st5,
+ lldb_st6,
+ lldb_st7,
+ lldb_mm0,
+ lldb_mm1,
+ lldb_mm2,
+ lldb_mm3,
+ lldb_mm4,
+ lldb_mm5,
+ lldb_mm6,
+ lldb_mm7,
+ lldb_xmm0,
+ lldb_xmm1,
+ lldb_xmm2,
+ lldb_xmm3,
+ lldb_xmm4,
+ lldb_xmm5,
+ lldb_xmm6,
+ lldb_xmm7,
+ lldb_xmm8,
+ lldb_xmm9,
+ lldb_xmm10,
+ lldb_xmm11,
+ lldb_xmm12,
+ lldb_xmm13,
+ lldb_xmm14,
+ lldb_xmm15,
+ k_last_fpr = lldb_xmm15,
+
+ k_first_avx,
+ lldb_ymm0 = k_first_avx,
+ lldb_ymm1,
+ lldb_ymm2,
+ lldb_ymm3,
+ lldb_ymm4,
+ lldb_ymm5,
+ lldb_ymm6,
+ lldb_ymm7,
+ lldb_ymm8,
+ lldb_ymm9,
+ lldb_ymm10,
+ lldb_ymm11,
+ lldb_ymm12,
+ lldb_ymm13,
+ lldb_ymm14,
+ lldb_ymm15,
+ k_last_avx = lldb_ymm15,
+
+ k_first_mpxr,
+ lldb_bnd0 = k_first_mpxr,
+ lldb_bnd1,
+ lldb_bnd2,
+ lldb_bnd3,
+ k_last_mpxr = lldb_bnd3,
+
+ k_first_mpxc,
+ lldb_bndcfgu = k_first_mpxc,
+ lldb_bndstatus,
+ k_last_mpxc = lldb_bndstatus,
+
+ k_first_dbr,
+ lldb_dr0 = k_first_dbr,
+ lldb_dr1,
+ lldb_dr2,
+ lldb_dr3,
+ lldb_dr4,
+ lldb_dr5,
+ lldb_dr6,
+ lldb_dr7,
+ k_last_dbr = lldb_dr7,
+
+ k_num_registers,
+ k_num_gpr_registers = k_last_gpr - k_first_gpr + 1,
+ k_num_fpr_registers = k_last_fpr - k_first_fpr + 1,
+ k_num_avx_registers = k_last_avx - k_first_avx + 1,
+ k_num_mpx_registers = k_last_mpxc - k_first_mpxr + 1,
+ k_num_user_registers = k_num_gpr_registers +
+ k_num_fpr_registers +
+ k_num_avx_registers +
+ k_num_mpx_registers,
+ k_num_dbr_registers = k_last_dbr - k_first_dbr + 1,
+};
+} // namespace x86_64_with_base
+
+}
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LLDB_X86_REGISTER_ENUMS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
new file mode 100644
index 000000000000..30af9345999c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -0,0 +1,1097 @@
+//===-- ProcessElfCore.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdlib>
+
+#include <memory>
+#include <mutex>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Threading.h"
+
+#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "ProcessElfCore.h"
+#include "ThreadElfCore.h"
+
+using namespace lldb_private;
+namespace ELF = llvm::ELF;
+
+LLDB_PLUGIN_DEFINE(ProcessElfCore)
+
+llvm::StringRef ProcessElfCore::GetPluginDescriptionStatic() {
+ return "ELF core dump plug-in.";
+}
+
+void ProcessElfCore::Terminate() {
+ PluginManager::UnregisterPlugin(ProcessElfCore::CreateInstance);
+}
+
+lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file,
+ bool can_connect) {
+ lldb::ProcessSP process_sp;
+ if (crash_file && !can_connect) {
+ // Read enough data for an ELF32 header or ELF64 header Note: Here we care
+ // about e_type field only, so it is safe to ignore possible presence of
+ // the header extension.
+ const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr);
+
+ auto data_sp = FileSystem::Instance().CreateDataBuffer(
+ crash_file->GetPath(), header_size, 0);
+ if (data_sp && data_sp->GetByteSize() == header_size &&
+ elf::ELFHeader::MagicBytesMatch(data_sp->GetBytes())) {
+ elf::ELFHeader elf_header;
+ DataExtractor data(data_sp, lldb::eByteOrderLittle, 4);
+ lldb::offset_t data_offset = 0;
+ if (elf_header.Parse(data, &data_offset)) {
+ // Check whether we're dealing with a raw FreeBSD "full memory dump"
+ // ELF vmcore that needs to be handled via FreeBSDKernel plugin instead.
+ if (elf_header.e_ident[7] == 0xFF && elf_header.e_version == 0)
+ return process_sp;
+ if (elf_header.e_type == llvm::ELF::ET_CORE)
+ process_sp = std::make_shared<ProcessElfCore>(target_sp, listener_sp,
+ *crash_file);
+ }
+ }
+ }
+ return process_sp;
+}
+
+bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) {
+ // For now we are just making sure the file exists for a given module
+ if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) {
+ ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture());
+ Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,
+ nullptr, nullptr, nullptr));
+ 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;
+}
+
+// ProcessElfCore constructor
+ProcessElfCore::ProcessElfCore(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec &core_file)
+ : PostMortemProcess(target_sp, listener_sp, core_file) {}
+
+// Destructor
+ProcessElfCore::~ProcessElfCore() {
+ 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(true /* destructing */);
+}
+
+lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment(
+ const elf::ELFProgramHeader &header) {
+ const lldb::addr_t addr = header.p_vaddr;
+ FileRange file_range(header.p_offset, header.p_filesz);
+ VMRangeToFileOffset::Entry range_entry(addr, header.p_memsz, file_range);
+
+ // Only add to m_core_aranges if the file size is non zero. Some core files
+ // have PT_LOAD segments for all address ranges, but set f_filesz to zero for
+ // the .text sections since they can be retrieved from the object files.
+ if (header.p_filesz > 0) {
+ VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();
+ if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() &&
+ last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() &&
+ last_entry->GetByteSize() == last_entry->data.GetByteSize()) {
+ last_entry->SetRangeEnd(range_entry.GetRangeEnd());
+ last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd());
+ } else {
+ m_core_aranges.Append(range_entry);
+ }
+ }
+ // Keep a separate map of permissions that isn't coalesced so all ranges
+ // are maintained.
+ const uint32_t permissions =
+ ((header.p_flags & llvm::ELF::PF_R) ? lldb::ePermissionsReadable : 0u) |
+ ((header.p_flags & llvm::ELF::PF_W) ? lldb::ePermissionsWritable : 0u) |
+ ((header.p_flags & llvm::ELF::PF_X) ? lldb::ePermissionsExecutable : 0u);
+
+ m_core_range_infos.Append(
+ VMRangeToPermissions::Entry(addr, header.p_memsz, permissions));
+
+ return addr;
+}
+
+lldb::addr_t ProcessElfCore::AddAddressRangeFromMemoryTagSegment(
+ const elf::ELFProgramHeader &header) {
+ // If lldb understood multiple kinds of tag segments we would record the type
+ // of the segment here also. As long as there is only 1 type lldb looks for,
+ // there is no need.
+ FileRange file_range(header.p_offset, header.p_filesz);
+ m_core_tag_ranges.Append(
+ VMRangeToFileOffset::Entry(header.p_vaddr, header.p_memsz, file_range));
+
+ return header.p_vaddr;
+}
+
+// Process Control
+Status ProcessElfCore::DoLoadCore() {
+ Status error;
+ if (!m_core_module_sp) {
+ error.SetErrorString("invalid core module");
+ return error;
+ }
+
+ ObjectFileELF *core = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
+ if (core == nullptr) {
+ error.SetErrorString("invalid core object file");
+ return error;
+ }
+
+ llvm::ArrayRef<elf::ELFProgramHeader> segments = core->ProgramHeaders();
+ if (segments.size() == 0) {
+ error.SetErrorString("core file has no segments");
+ return error;
+ }
+
+ SetCanJIT(false);
+
+ m_thread_data_valid = true;
+
+ bool ranges_are_sorted = true;
+ lldb::addr_t vm_addr = 0;
+ lldb::addr_t tag_addr = 0;
+ /// Walk through segments and Thread and Address Map information.
+ /// PT_NOTE - Contains Thread and Register information
+ /// PT_LOAD - Contains a contiguous range of Process Address Space
+ /// PT_AARCH64_MEMTAG_MTE - Contains AArch64 MTE memory tags for a range of
+ /// Process Address Space.
+ for (const elf::ELFProgramHeader &H : segments) {
+ DataExtractor data = core->GetSegmentData(H);
+
+ // Parse thread contexts and auxv structure
+ if (H.p_type == llvm::ELF::PT_NOTE) {
+ if (llvm::Error error = ParseThreadContextsFromNoteSegment(H, data))
+ return Status(std::move(error));
+ }
+ // PT_LOAD segments contains address map
+ if (H.p_type == llvm::ELF::PT_LOAD) {
+ lldb::addr_t last_addr = AddAddressRangeFromLoadSegment(H);
+ if (vm_addr > last_addr)
+ ranges_are_sorted = false;
+ vm_addr = last_addr;
+ } else if (H.p_type == llvm::ELF::PT_AARCH64_MEMTAG_MTE) {
+ lldb::addr_t last_addr = AddAddressRangeFromMemoryTagSegment(H);
+ if (tag_addr > last_addr)
+ ranges_are_sorted = false;
+ tag_addr = last_addr;
+ }
+ }
+
+ if (!ranges_are_sorted) {
+ m_core_aranges.Sort();
+ m_core_range_infos.Sort();
+ m_core_tag_ranges.Sort();
+ }
+
+ // 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());
+
+ ArchSpec target_arch = GetTarget().GetArchitecture();
+ ArchSpec core_arch(m_core_module_sp->GetArchitecture());
+ target_arch.MergeFrom(core_arch);
+ GetTarget().SetArchitecture(target_arch);
+
+ SetUnixSignals(UnixSignals::Create(GetArchitecture()));
+
+ // Ensure we found at least one thread that was stopped on a signal.
+ bool siginfo_signal_found = false;
+ bool prstatus_signal_found = false;
+ // Check we found a signal in a SIGINFO note.
+ for (const auto &thread_data : m_thread_data) {
+ if (thread_data.signo != 0)
+ siginfo_signal_found = true;
+ if (thread_data.prstatus_sig != 0)
+ prstatus_signal_found = true;
+ }
+ if (!siginfo_signal_found) {
+ // If we don't have signal from SIGINFO use the signal from each threads
+ // PRSTATUS note.
+ if (prstatus_signal_found) {
+ for (auto &thread_data : m_thread_data)
+ thread_data.signo = thread_data.prstatus_sig;
+ } else if (m_thread_data.size() > 0) {
+ // If all else fails force the first thread to be SIGSTOP
+ m_thread_data.begin()->signo =
+ GetUnixSignals()->GetSignalNumberFromName("SIGSTOP");
+ }
+ }
+
+ // Try to find gnu build id before we load the executable.
+ UpdateBuildIdForNTFileEntries();
+
+ // Core files are useless without the main executable. See if we can locate
+ // the main executable using data we found in the core file notes.
+ lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
+ if (!exe_module_sp) {
+ // The first entry in the NT_FILE might be our executable
+ if (!m_nt_file_entries.empty()) {
+ ModuleSpec exe_module_spec;
+ exe_module_spec.GetArchitecture() = arch;
+ exe_module_spec.GetUUID() = m_nt_file_entries[0].uuid;
+ exe_module_spec.GetFileSpec().SetFile(m_nt_file_entries[0].path,
+ FileSpec::Style::native);
+ if (exe_module_spec.GetFileSpec()) {
+ exe_module_sp =
+ GetTarget().GetOrCreateModule(exe_module_spec, true /* notify */);
+ if (exe_module_sp)
+ GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo);
+ }
+ }
+ }
+ return error;
+}
+
+void ProcessElfCore::UpdateBuildIdForNTFileEntries() {
+ for (NT_FILE_Entry &entry : m_nt_file_entries) {
+ entry.uuid = FindBuidIdInCoreMemory(entry.start);
+ }
+}
+
+lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
+ if (m_dyld_up.get() == nullptr)
+ m_dyld_up.reset(DynamicLoader::FindPlugin(
+ this, DynamicLoaderPOSIXDYLD::GetPluginNameStatic()));
+ return m_dyld_up.get();
+}
+
+bool ProcessElfCore::DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
+ const uint32_t num_threads = GetNumThreadContexts();
+ if (!m_thread_data_valid)
+ return false;
+
+ for (lldb::tid_t tid = 0; tid < num_threads; ++tid) {
+ const ThreadData &td = m_thread_data[tid];
+ lldb::ThreadSP thread_sp(new ThreadElfCore(*this, td));
+ new_thread_list.AddThread(thread_sp);
+ }
+ return new_thread_list.GetSize(false) > 0;
+}
+
+void ProcessElfCore::RefreshStateAfterStop() {}
+
+Status ProcessElfCore::DoDestroy() { return Status(); }
+
+// Process Queries
+
+bool ProcessElfCore::IsAlive() { return true; }
+
+// Process Memory
+size_t ProcessElfCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) {
+ if (lldb::ABISP abi_sp = GetABI())
+ addr = abi_sp->FixAnyAddress(addr);
+
+ // 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);
+}
+
+Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &region_info) {
+ region_info.Clear();
+ const VMRangeToPermissions::Entry *permission_entry =
+ m_core_range_infos.FindEntryThatContainsOrFollows(load_addr);
+ if (permission_entry) {
+ if (permission_entry->Contains(load_addr)) {
+ region_info.GetRange().SetRangeBase(permission_entry->GetRangeBase());
+ region_info.GetRange().SetRangeEnd(permission_entry->GetRangeEnd());
+ const Flags permissions(permission_entry->data);
+ region_info.SetReadable(permissions.Test(lldb::ePermissionsReadable)
+ ? MemoryRegionInfo::eYes
+ : MemoryRegionInfo::eNo);
+ region_info.SetWritable(permissions.Test(lldb::ePermissionsWritable)
+ ? MemoryRegionInfo::eYes
+ : MemoryRegionInfo::eNo);
+ region_info.SetExecutable(permissions.Test(lldb::ePermissionsExecutable)
+ ? MemoryRegionInfo::eYes
+ : MemoryRegionInfo::eNo);
+ region_info.SetMapped(MemoryRegionInfo::eYes);
+
+ // A region is memory tagged if there is a memory tag segment that covers
+ // the exact same range.
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
+ const VMRangeToFileOffset::Entry *tag_entry =
+ m_core_tag_ranges.FindEntryStartsAt(permission_entry->GetRangeBase());
+ if (tag_entry &&
+ tag_entry->GetRangeEnd() == permission_entry->GetRangeEnd())
+ region_info.SetMemoryTagged(MemoryRegionInfo::eYes);
+ } else if (load_addr < permission_entry->GetRangeBase()) {
+ region_info.GetRange().SetRangeBase(load_addr);
+ region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());
+ region_info.SetReadable(MemoryRegionInfo::eNo);
+ region_info.SetWritable(MemoryRegionInfo::eNo);
+ region_info.SetExecutable(MemoryRegionInfo::eNo);
+ region_info.SetMapped(MemoryRegionInfo::eNo);
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
+ }
+ return Status();
+ }
+
+ region_info.GetRange().SetRangeBase(load_addr);
+ region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
+ region_info.SetReadable(MemoryRegionInfo::eNo);
+ region_info.SetWritable(MemoryRegionInfo::eNo);
+ region_info.SetExecutable(MemoryRegionInfo::eNo);
+ region_info.SetMapped(MemoryRegionInfo::eNo);
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
+ return Status();
+}
+
+size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) {
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+
+ if (core_objfile == nullptr)
+ return 0;
+
+ // Get the address range
+ const VMRangeToFileOffset::Entry *address_range =
+ m_core_aranges.FindEntryThatContains(addr);
+ if (address_range == nullptr || address_range->GetRangeEnd() < addr) {
+ error.SetErrorStringWithFormat("core file does not contain 0x%" PRIx64,
+ addr);
+ return 0;
+ }
+
+ // Convert the address into core file offset
+ const lldb::addr_t offset = addr - address_range->GetRangeBase();
+ const lldb::addr_t file_start = address_range->data.GetRangeBase();
+ const lldb::addr_t file_end = address_range->data.GetRangeEnd();
+ size_t bytes_to_read = size; // Number of bytes to read from the core file
+ size_t bytes_copied = 0; // Number of bytes actually read from the core file
+ lldb::addr_t bytes_left =
+ 0; // Number of bytes available in the core file from the given address
+
+ // Don't proceed if core file doesn't contain the actual data for this
+ // address range.
+ if (file_start == file_end)
+ return 0;
+
+ // Figure out how many on-disk bytes remain in this segment starting at the
+ // given offset
+ if (file_end > file_start + offset)
+ bytes_left = file_end - (file_start + offset);
+
+ if (bytes_to_read > bytes_left)
+ bytes_to_read = bytes_left;
+
+ // If there is data available on the core file read it
+ if (bytes_to_read)
+ bytes_copied =
+ core_objfile->CopyData(offset + file_start, bytes_to_read, buf);
+
+ return bytes_copied;
+}
+
+llvm::Expected<std::vector<lldb::addr_t>>
+ProcessElfCore::ReadMemoryTags(lldb::addr_t addr, size_t len) {
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+ if (core_objfile == nullptr)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No core object file.");
+
+ llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
+ GetMemoryTagManager();
+ if (!tag_manager_or_err)
+ return tag_manager_or_err.takeError();
+
+ // LLDB only supports AArch64 MTE tag segments so we do not need to worry
+ // about the segment type here. If you got here then you must have a tag
+ // manager (meaning you are debugging AArch64) and all the segments in this
+ // list will have had type PT_AARCH64_MEMTAG_MTE.
+ const VMRangeToFileOffset::Entry *tag_entry =
+ m_core_tag_ranges.FindEntryThatContains(addr);
+ // If we don't have a tag segment or the range asked for extends outside the
+ // segment.
+ if (!tag_entry || (addr + len) >= tag_entry->GetRangeEnd())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No tag segment that covers this range.");
+
+ const MemoryTagManager *tag_manager = *tag_manager_or_err;
+ return tag_manager->UnpackTagsFromCoreFileSegment(
+ [core_objfile](lldb::offset_t offset, size_t length, void *dst) {
+ return core_objfile->CopyData(offset, length, dst);
+ },
+ tag_entry->GetRangeBase(), tag_entry->data.GetRangeBase(), addr, len);
+}
+
+void ProcessElfCore::Clear() {
+ m_thread_list.Clear();
+
+ SetUnixSignals(std::make_shared<UnixSignals>());
+}
+
+void ProcessElfCore::Initialize() {
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+ });
+}
+
+lldb::addr_t ProcessElfCore::GetImageInfoAddress() {
+ ObjectFile *obj_file = GetTarget().GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress(&GetTarget());
+
+ if (addr.IsValid())
+ return addr.GetLoadAddress(&GetTarget());
+ return LLDB_INVALID_ADDRESS;
+}
+
+// Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.
+static void ParseFreeBSDPrStatus(ThreadData &thread_data,
+ const DataExtractor &data,
+ bool lp64) {
+ lldb::offset_t offset = 0;
+ int pr_version = data.GetU32(&offset);
+
+ Log *log = GetLog(LLDBLog::Process);
+ if (log) {
+ if (pr_version > 1)
+ LLDB_LOGF(log, "FreeBSD PRSTATUS unexpected version %d", pr_version);
+ }
+
+ // Skip padding, pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate
+ if (lp64)
+ offset += 32;
+ else
+ offset += 16;
+
+ thread_data.signo = data.GetU32(&offset); // pr_cursig
+ thread_data.tid = data.GetU32(&offset); // pr_pid
+ if (lp64)
+ offset += 4;
+
+ size_t len = data.GetByteSize() - offset;
+ thread_data.gpregset = DataExtractor(data, offset, len);
+}
+
+// Parse a FreeBSD NT_PRPSINFO note - see FreeBSD sys/procfs.h for details.
+static void ParseFreeBSDPrPsInfo(ProcessElfCore &process,
+ const DataExtractor &data,
+ bool lp64) {
+ lldb::offset_t offset = 0;
+ int pr_version = data.GetU32(&offset);
+
+ Log *log = GetLog(LLDBLog::Process);
+ if (log) {
+ if (pr_version > 1)
+ LLDB_LOGF(log, "FreeBSD PRPSINFO unexpected version %d", pr_version);
+ }
+
+ // Skip pr_psinfosz, pr_fname, pr_psargs
+ offset += 108;
+ if (lp64)
+ offset += 4;
+
+ process.SetID(data.GetU32(&offset)); // pr_pid
+}
+
+static llvm::Error ParseNetBSDProcInfo(const DataExtractor &data,
+ uint32_t &cpi_nlwps,
+ uint32_t &cpi_signo,
+ uint32_t &cpi_siglwp,
+ uint32_t &cpi_pid) {
+ lldb::offset_t offset = 0;
+
+ uint32_t version = data.GetU32(&offset);
+ if (version != 1)
+ return llvm::make_error<llvm::StringError>(
+ "Error parsing NetBSD core(5) notes: Unsupported procinfo version",
+ llvm::inconvertibleErrorCode());
+
+ uint32_t cpisize = data.GetU32(&offset);
+ if (cpisize != NETBSD::NT_PROCINFO_SIZE)
+ return llvm::make_error<llvm::StringError>(
+ "Error parsing NetBSD core(5) notes: Unsupported procinfo size",
+ llvm::inconvertibleErrorCode());
+
+ cpi_signo = data.GetU32(&offset); /* killing signal */
+
+ offset += NETBSD::NT_PROCINFO_CPI_SIGCODE_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_SIGPEND_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_SIGMASK_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_SIGIGNORE_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_SIGCATCH_SIZE;
+ cpi_pid = data.GetU32(&offset);
+ offset += NETBSD::NT_PROCINFO_CPI_PPID_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_PGRP_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_SID_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_RUID_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_EUID_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_SVUID_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_RGID_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_EGID_SIZE;
+ offset += NETBSD::NT_PROCINFO_CPI_SVGID_SIZE;
+ cpi_nlwps = data.GetU32(&offset); /* number of LWPs */
+
+ offset += NETBSD::NT_PROCINFO_CPI_NAME_SIZE;
+ cpi_siglwp = data.GetU32(&offset); /* LWP target of killing signal */
+
+ return llvm::Error::success();
+}
+
+static void ParseOpenBSDProcInfo(ThreadData &thread_data,
+ const DataExtractor &data) {
+ lldb::offset_t offset = 0;
+
+ int version = data.GetU32(&offset);
+ if (version != 1)
+ return;
+
+ offset += 4;
+ thread_data.signo = data.GetU32(&offset);
+}
+
+llvm::Expected<std::vector<CoreNote>>
+ProcessElfCore::parseSegment(const DataExtractor &segment) {
+ lldb::offset_t offset = 0;
+ std::vector<CoreNote> result;
+
+ while (offset < segment.GetByteSize()) {
+ ELFNote note = ELFNote();
+ if (!note.Parse(segment, &offset))
+ return llvm::make_error<llvm::StringError>(
+ "Unable to parse note segment", llvm::inconvertibleErrorCode());
+
+ size_t note_start = offset;
+ size_t note_size = llvm::alignTo(note.n_descsz, 4);
+
+ result.push_back({note, DataExtractor(segment, note_start, note_size)});
+ offset += note_size;
+ }
+
+ return std::move(result);
+}
+
+llvm::Error ProcessElfCore::parseFreeBSDNotes(llvm::ArrayRef<CoreNote> notes) {
+ ArchSpec arch = GetArchitecture();
+ bool lp64 = (arch.GetMachine() == llvm::Triple::aarch64 ||
+ arch.GetMachine() == llvm::Triple::mips64 ||
+ arch.GetMachine() == llvm::Triple::ppc64 ||
+ arch.GetMachine() == llvm::Triple::x86_64);
+ bool have_prstatus = false;
+ bool have_prpsinfo = false;
+ ThreadData thread_data;
+ for (const auto &note : notes) {
+ if (note.info.n_name != "FreeBSD")
+ continue;
+
+ if ((note.info.n_type == ELF::NT_PRSTATUS && have_prstatus) ||
+ (note.info.n_type == ELF::NT_PRPSINFO && have_prpsinfo)) {
+ assert(thread_data.gpregset.GetByteSize() > 0);
+ // Add the new thread to thread list
+ m_thread_data.push_back(thread_data);
+ thread_data = ThreadData();
+ have_prstatus = false;
+ have_prpsinfo = false;
+ }
+
+ switch (note.info.n_type) {
+ case ELF::NT_PRSTATUS:
+ have_prstatus = true;
+ ParseFreeBSDPrStatus(thread_data, note.data, lp64);
+ break;
+ case ELF::NT_PRPSINFO:
+ have_prpsinfo = true;
+ ParseFreeBSDPrPsInfo(*this, note.data, lp64);
+ break;
+ case ELF::NT_FREEBSD_THRMISC: {
+ lldb::offset_t offset = 0;
+ thread_data.name = note.data.GetCStr(&offset, 20);
+ break;
+ }
+ case ELF::NT_FREEBSD_PROCSTAT_AUXV:
+ // FIXME: FreeBSD sticks an int at the beginning of the note
+ m_auxv = DataExtractor(note.data, 4, note.data.GetByteSize() - 4);
+ break;
+ default:
+ thread_data.notes.push_back(note);
+ break;
+ }
+ }
+ if (!have_prstatus) {
+ return llvm::make_error<llvm::StringError>(
+ "Could not find NT_PRSTATUS note in core file.",
+ llvm::inconvertibleErrorCode());
+ }
+ m_thread_data.push_back(thread_data);
+ return llvm::Error::success();
+}
+
+/// NetBSD specific Thread context from PT_NOTE segment
+///
+/// NetBSD ELF core files use notes to provide information about
+/// the process's state. The note name is "NetBSD-CORE" for
+/// information that is global to the process, and "NetBSD-CORE@nn",
+/// where "nn" is the lwpid of the LWP that the information belongs
+/// to (such as register state).
+///
+/// NetBSD uses the following note identifiers:
+///
+/// ELF_NOTE_NETBSD_CORE_PROCINFO (value 1)
+/// Note is a "netbsd_elfcore_procinfo" structure.
+/// ELF_NOTE_NETBSD_CORE_AUXV (value 2; since NetBSD 8.0)
+/// Note is an array of AuxInfo structures.
+///
+/// NetBSD also uses ptrace(2) request numbers (the ones that exist in
+/// machine-dependent space) to identify register info notes. The
+/// info in such notes is in the same format that ptrace(2) would
+/// export that information.
+///
+/// For more information see /usr/include/sys/exec_elf.h
+///
+llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) {
+ ThreadData thread_data;
+ bool had_nt_regs = false;
+
+ // To be extracted from struct netbsd_elfcore_procinfo
+ // Used to sanity check of the LWPs of the process
+ uint32_t nlwps = 0;
+ uint32_t signo = 0; // killing signal
+ uint32_t siglwp = 0; // LWP target of killing signal
+ uint32_t pr_pid = 0;
+
+ for (const auto &note : notes) {
+ llvm::StringRef name = note.info.n_name;
+
+ if (name == "NetBSD-CORE") {
+ if (note.info.n_type == NETBSD::NT_PROCINFO) {
+ llvm::Error error = ParseNetBSDProcInfo(note.data, nlwps, signo,
+ siglwp, pr_pid);
+ if (error)
+ return error;
+ SetID(pr_pid);
+ } else if (note.info.n_type == NETBSD::NT_AUXV) {
+ m_auxv = note.data;
+ }
+ } else if (name.consume_front("NetBSD-CORE@")) {
+ lldb::tid_t tid;
+ if (name.getAsInteger(10, tid))
+ return llvm::make_error<llvm::StringError>(
+ "Error parsing NetBSD core(5) notes: Cannot convert LWP ID "
+ "to integer",
+ llvm::inconvertibleErrorCode());
+
+ switch (GetArchitecture().GetMachine()) {
+ case llvm::Triple::aarch64: {
+ // Assume order PT_GETREGS, PT_GETFPREGS
+ if (note.info.n_type == NETBSD::AARCH64::NT_REGS) {
+ // If this is the next thread, push the previous one first.
+ if (had_nt_regs) {
+ m_thread_data.push_back(thread_data);
+ thread_data = ThreadData();
+ had_nt_regs = false;
+ }
+
+ thread_data.gpregset = note.data;
+ thread_data.tid = tid;
+ if (thread_data.gpregset.GetByteSize() == 0)
+ return llvm::make_error<llvm::StringError>(
+ "Could not find general purpose registers note in core file.",
+ llvm::inconvertibleErrorCode());
+ had_nt_regs = true;
+ } else if (note.info.n_type == NETBSD::AARCH64::NT_FPREGS) {
+ if (!had_nt_regs || tid != thread_data.tid)
+ return llvm::make_error<llvm::StringError>(
+ "Error parsing NetBSD core(5) notes: Unexpected order "
+ "of NOTEs PT_GETFPREG before PT_GETREG",
+ llvm::inconvertibleErrorCode());
+ thread_data.notes.push_back(note);
+ }
+ } break;
+ case llvm::Triple::x86: {
+ // Assume order PT_GETREGS, PT_GETFPREGS
+ if (note.info.n_type == NETBSD::I386::NT_REGS) {
+ // If this is the next thread, push the previous one first.
+ if (had_nt_regs) {
+ m_thread_data.push_back(thread_data);
+ thread_data = ThreadData();
+ had_nt_regs = false;
+ }
+
+ thread_data.gpregset = note.data;
+ thread_data.tid = tid;
+ if (thread_data.gpregset.GetByteSize() == 0)
+ return llvm::make_error<llvm::StringError>(
+ "Could not find general purpose registers note in core file.",
+ llvm::inconvertibleErrorCode());
+ had_nt_regs = true;
+ } else if (note.info.n_type == NETBSD::I386::NT_FPREGS) {
+ if (!had_nt_regs || tid != thread_data.tid)
+ return llvm::make_error<llvm::StringError>(
+ "Error parsing NetBSD core(5) notes: Unexpected order "
+ "of NOTEs PT_GETFPREG before PT_GETREG",
+ llvm::inconvertibleErrorCode());
+ thread_data.notes.push_back(note);
+ }
+ } break;
+ case llvm::Triple::x86_64: {
+ // Assume order PT_GETREGS, PT_GETFPREGS
+ if (note.info.n_type == NETBSD::AMD64::NT_REGS) {
+ // If this is the next thread, push the previous one first.
+ if (had_nt_regs) {
+ m_thread_data.push_back(thread_data);
+ thread_data = ThreadData();
+ had_nt_regs = false;
+ }
+
+ thread_data.gpregset = note.data;
+ thread_data.tid = tid;
+ if (thread_data.gpregset.GetByteSize() == 0)
+ return llvm::make_error<llvm::StringError>(
+ "Could not find general purpose registers note in core file.",
+ llvm::inconvertibleErrorCode());
+ had_nt_regs = true;
+ } else if (note.info.n_type == NETBSD::AMD64::NT_FPREGS) {
+ if (!had_nt_regs || tid != thread_data.tid)
+ return llvm::make_error<llvm::StringError>(
+ "Error parsing NetBSD core(5) notes: Unexpected order "
+ "of NOTEs PT_GETFPREG before PT_GETREG",
+ llvm::inconvertibleErrorCode());
+ thread_data.notes.push_back(note);
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Push the last thread.
+ if (had_nt_regs)
+ m_thread_data.push_back(thread_data);
+
+ if (m_thread_data.empty())
+ return llvm::make_error<llvm::StringError>(
+ "Error parsing NetBSD core(5) notes: No threads information "
+ "specified in notes",
+ llvm::inconvertibleErrorCode());
+
+ if (m_thread_data.size() != nlwps)
+ return llvm::make_error<llvm::StringError>(
+ "Error parsing NetBSD core(5) notes: Mismatch between the number "
+ "of LWPs in netbsd_elfcore_procinfo and the number of LWPs specified "
+ "by MD notes",
+ llvm::inconvertibleErrorCode());
+
+ // Signal targeted at the whole process.
+ if (siglwp == 0) {
+ for (auto &data : m_thread_data)
+ data.signo = signo;
+ }
+ // Signal destined for a particular LWP.
+ else {
+ bool passed = false;
+
+ for (auto &data : m_thread_data) {
+ if (data.tid == siglwp) {
+ data.signo = signo;
+ passed = true;
+ break;
+ }
+ }
+
+ if (!passed)
+ return llvm::make_error<llvm::StringError>(
+ "Error parsing NetBSD core(5) notes: Signal passed to unknown LWP",
+ llvm::inconvertibleErrorCode());
+ }
+
+ return llvm::Error::success();
+}
+
+llvm::Error ProcessElfCore::parseOpenBSDNotes(llvm::ArrayRef<CoreNote> notes) {
+ ThreadData thread_data = {};
+ for (const auto &note : notes) {
+ // OpenBSD per-thread information is stored in notes named "OpenBSD@nnn" so
+ // match on the initial part of the string.
+ if (!llvm::StringRef(note.info.n_name).starts_with("OpenBSD"))
+ continue;
+
+ switch (note.info.n_type) {
+ case OPENBSD::NT_PROCINFO:
+ ParseOpenBSDProcInfo(thread_data, note.data);
+ break;
+ case OPENBSD::NT_AUXV:
+ m_auxv = note.data;
+ break;
+ case OPENBSD::NT_REGS:
+ thread_data.gpregset = note.data;
+ break;
+ default:
+ thread_data.notes.push_back(note);
+ break;
+ }
+ }
+ if (thread_data.gpregset.GetByteSize() == 0) {
+ return llvm::make_error<llvm::StringError>(
+ "Could not find general purpose registers note in core file.",
+ llvm::inconvertibleErrorCode());
+ }
+ m_thread_data.push_back(thread_data);
+ return llvm::Error::success();
+}
+
+/// A description of a linux process usually contains the following NOTE
+/// entries:
+/// - NT_PRPSINFO - General process information like pid, uid, name, ...
+/// - NT_SIGINFO - Information about the signal that terminated the process
+/// - NT_AUXV - Process auxiliary vector
+/// - NT_FILE - Files mapped into memory
+///
+/// Additionally, for each thread in the process the core file will contain at
+/// least the NT_PRSTATUS note, containing the thread id and general purpose
+/// registers. It may include additional notes for other register sets (floating
+/// point and vector registers, ...). The tricky part here is that some of these
+/// notes have "CORE" in their owner fields, while other set it to "LINUX".
+llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef<CoreNote> notes) {
+ const ArchSpec &arch = GetArchitecture();
+ bool have_prstatus = false;
+ bool have_prpsinfo = false;
+ ThreadData thread_data;
+ for (const auto &note : notes) {
+ if (note.info.n_name != "CORE" && note.info.n_name != "LINUX")
+ continue;
+
+ if ((note.info.n_type == ELF::NT_PRSTATUS && have_prstatus) ||
+ (note.info.n_type == ELF::NT_PRPSINFO && have_prpsinfo)) {
+ assert(thread_data.gpregset.GetByteSize() > 0);
+ // Add the new thread to thread list
+ m_thread_data.push_back(thread_data);
+ thread_data = ThreadData();
+ have_prstatus = false;
+ have_prpsinfo = false;
+ }
+
+ switch (note.info.n_type) {
+ case ELF::NT_PRSTATUS: {
+ have_prstatus = true;
+ ELFLinuxPrStatus prstatus;
+ Status status = prstatus.Parse(note.data, arch);
+ if (status.Fail())
+ return status.ToError();
+ thread_data.prstatus_sig = prstatus.pr_cursig;
+ thread_data.tid = prstatus.pr_pid;
+ uint32_t header_size = ELFLinuxPrStatus::GetSize(arch);
+ size_t len = note.data.GetByteSize() - header_size;
+ thread_data.gpregset = DataExtractor(note.data, header_size, len);
+ break;
+ }
+ case ELF::NT_PRPSINFO: {
+ have_prpsinfo = true;
+ ELFLinuxPrPsInfo prpsinfo;
+ Status status = prpsinfo.Parse(note.data, arch);
+ if (status.Fail())
+ return status.ToError();
+ thread_data.name.assign (prpsinfo.pr_fname, strnlen (prpsinfo.pr_fname, sizeof (prpsinfo.pr_fname)));
+ SetID(prpsinfo.pr_pid);
+ break;
+ }
+ case ELF::NT_SIGINFO: {
+ ELFLinuxSigInfo siginfo;
+ Status status = siginfo.Parse(note.data, arch);
+ if (status.Fail())
+ return status.ToError();
+ thread_data.signo = siginfo.si_signo;
+ thread_data.code = siginfo.si_code;
+ break;
+ }
+ case ELF::NT_FILE: {
+ m_nt_file_entries.clear();
+ lldb::offset_t offset = 0;
+ const uint64_t count = note.data.GetAddress(&offset);
+ note.data.GetAddress(&offset); // Skip page size
+ for (uint64_t i = 0; i < count; ++i) {
+ NT_FILE_Entry entry;
+ entry.start = note.data.GetAddress(&offset);
+ entry.end = note.data.GetAddress(&offset);
+ entry.file_ofs = note.data.GetAddress(&offset);
+ m_nt_file_entries.push_back(entry);
+ }
+ for (uint64_t i = 0; i < count; ++i) {
+ const char *path = note.data.GetCStr(&offset);
+ if (path && path[0])
+ m_nt_file_entries[i].path.assign(path);
+ }
+ break;
+ }
+ case ELF::NT_AUXV:
+ m_auxv = note.data;
+ break;
+ default:
+ thread_data.notes.push_back(note);
+ break;
+ }
+ }
+ // Add last entry in the note section
+ if (have_prstatus)
+ m_thread_data.push_back(thread_data);
+ return llvm::Error::success();
+}
+
+/// Parse Thread context from PT_NOTE segment and store it in the thread list
+/// A note segment consists of one or more NOTE entries, but their types and
+/// meaning differ depending on the OS.
+llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
+ const elf::ELFProgramHeader &segment_header,
+ const DataExtractor &segment_data) {
+ assert(segment_header.p_type == llvm::ELF::PT_NOTE);
+
+ auto notes_or_error = parseSegment(segment_data);
+ if(!notes_or_error)
+ return notes_or_error.takeError();
+ switch (GetArchitecture().GetTriple().getOS()) {
+ case llvm::Triple::FreeBSD:
+ return parseFreeBSDNotes(*notes_or_error);
+ case llvm::Triple::Linux:
+ return parseLinuxNotes(*notes_or_error);
+ case llvm::Triple::NetBSD:
+ return parseNetBSDNotes(*notes_or_error);
+ case llvm::Triple::OpenBSD:
+ return parseOpenBSDNotes(*notes_or_error);
+ default:
+ return llvm::make_error<llvm::StringError>(
+ "Don't know how to parse core file. Unsupported OS.",
+ llvm::inconvertibleErrorCode());
+ }
+}
+
+UUID ProcessElfCore::FindBuidIdInCoreMemory(lldb::addr_t address) {
+ UUID invalid_uuid;
+ const uint32_t addr_size = GetAddressByteSize();
+ const size_t elf_header_size = addr_size == 4 ? sizeof(llvm::ELF::Elf32_Ehdr)
+ : sizeof(llvm::ELF::Elf64_Ehdr);
+
+ std::vector<uint8_t> elf_header_bytes;
+ elf_header_bytes.resize(elf_header_size);
+ Status error;
+ size_t byte_read =
+ ReadMemory(address, elf_header_bytes.data(), elf_header_size, error);
+ if (byte_read != elf_header_size ||
+ !elf::ELFHeader::MagicBytesMatch(elf_header_bytes.data()))
+ return invalid_uuid;
+ DataExtractor elf_header_data(elf_header_bytes.data(), elf_header_size,
+ GetByteOrder(), addr_size);
+ lldb::offset_t offset = 0;
+
+ elf::ELFHeader elf_header;
+ elf_header.Parse(elf_header_data, &offset);
+
+ const lldb::addr_t ph_addr = address + elf_header.e_phoff;
+
+ std::vector<uint8_t> ph_bytes;
+ ph_bytes.resize(elf_header.e_phentsize);
+ for (unsigned int i = 0; i < elf_header.e_phnum; ++i) {
+ byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize,
+ ph_bytes.data(), elf_header.e_phentsize, error);
+ if (byte_read != elf_header.e_phentsize)
+ break;
+ DataExtractor program_header_data(ph_bytes.data(), elf_header.e_phentsize,
+ GetByteOrder(), addr_size);
+ offset = 0;
+ elf::ELFProgramHeader program_header;
+ program_header.Parse(program_header_data, &offset);
+ if (program_header.p_type != llvm::ELF::PT_NOTE)
+ continue;
+
+ std::vector<uint8_t> note_bytes;
+ note_bytes.resize(program_header.p_memsz);
+
+ byte_read = ReadMemory(program_header.p_vaddr, note_bytes.data(),
+ program_header.p_memsz, error);
+ if (byte_read != program_header.p_memsz)
+ continue;
+ DataExtractor segment_data(note_bytes.data(), note_bytes.size(),
+ GetByteOrder(), addr_size);
+ auto notes_or_error = parseSegment(segment_data);
+ if (!notes_or_error)
+ return invalid_uuid;
+ for (const CoreNote &note : *notes_or_error) {
+ if (note.info.n_namesz == 4 &&
+ note.info.n_type == llvm::ELF::NT_GNU_BUILD_ID &&
+ "GNU" == note.info.n_name &&
+ note.data.ValidOffsetForDataOfSize(0, note.info.n_descsz))
+ return UUID(note.data.GetData().take_front(note.info.n_descsz));
+ }
+ }
+ return invalid_uuid;
+}
+
+uint32_t ProcessElfCore::GetNumThreadContexts() {
+ if (!m_thread_data_valid)
+ DoLoadCore();
+ return m_thread_data.size();
+}
+
+ArchSpec ProcessElfCore::GetArchitecture() {
+ ArchSpec arch = m_core_module_sp->GetObjectFile()->GetArchitecture();
+
+ ArchSpec target_arch = GetTarget().GetArchitecture();
+ arch.MergeFrom(target_arch);
+
+ // On MIPS there is no way to differentiate betwenn 32bit and 64bit core
+ // files and this information can't be merged in from the target arch so we
+ // fail back to unconditionally returning the target arch in this config.
+ if (target_arch.IsMIPS()) {
+ return target_arch;
+ }
+
+ return arch;
+}
+
+DataExtractor ProcessElfCore::GetAuxvData() {
+ const uint8_t *start = m_auxv.GetDataStart();
+ size_t len = m_auxv.GetByteSize();
+ lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(start, len));
+ return DataExtractor(buffer, GetByteOrder(), GetAddressByteSize());
+}
+
+bool ProcessElfCore::GetProcessInfo(ProcessInstanceInfo &info) {
+ info.Clear();
+ info.SetProcessID(GetID());
+ info.SetArchitecture(GetArchitecture());
+ lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
+ if (module_sp) {
+ const bool add_exe_file_as_first_arg = false;
+ info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
+ add_exe_file_as_first_arg);
+ }
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
new file mode 100644
index 000000000000..668a7c484674
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -0,0 +1,187 @@
+//===-- ProcessElfCore.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// Notes about Linux Process core dumps:
+// 1) Linux core dump is stored as ELF file.
+// 2) The ELF file's PT_NOTE and PT_LOAD segments describes the program's
+// address space and thread contexts.
+// 3) PT_NOTE segment contains note entries which describes a thread context.
+// 4) PT_LOAD segment describes a valid contiguous range of process address
+// space.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H
+
+#include <list>
+#include <vector>
+
+#include "lldb/Target/PostMortemProcess.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/ObjectFile/ELF/ELFHeader.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+struct ThreadData;
+
+class ProcessElfCore : public lldb_private::PostMortemProcess {
+public:
+ // Constructors and Destructors
+ static lldb::ProcessSP
+ CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
+ const lldb_private::FileSpec *crash_file_path,
+ bool can_connect);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "elf-core"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ // Constructors and Destructors
+ ProcessElfCore(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
+ const lldb_private::FileSpec &core_file);
+
+ ~ProcessElfCore() override;
+
+ // 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::Status DoLoadCore() override;
+
+ lldb_private::DynamicLoader *GetDynamicLoader() override;
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ // Process Control
+ lldb_private::Status DoDestroy() override;
+
+ void RefreshStateAfterStop() override;
+
+ lldb_private::Status WillResume() override {
+ lldb_private::Status error;
+ error.SetErrorStringWithFormatv(
+ "error: {0} does not support resuming processes", GetPluginName());
+ return error;
+ }
+
+ // Process Queries
+ bool IsAlive() override;
+
+ bool WarnBeforeDetach() const override { return false; }
+
+ // Process Memory
+ size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ lldb_private::Status &error) override;
+
+ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ lldb_private::Status &error) override;
+
+ // We do not implement DoReadMemoryTags. Instead all the work is done in
+ // ReadMemoryTags which avoids having to unpack and repack tags.
+ llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr,
+ size_t len) override;
+
+ lldb::addr_t GetImageInfoAddress() override;
+
+ lldb_private::ArchSpec GetArchitecture();
+
+ // Returns AUXV structure found in the core file
+ lldb_private::DataExtractor GetAuxvData() override;
+
+ bool GetProcessInfo(lldb_private::ProcessInstanceInfo &info) override;
+
+protected:
+ void Clear();
+
+ bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) override;
+
+ lldb_private::Status
+ DoGetMemoryRegionInfo(lldb::addr_t load_addr,
+ lldb_private::MemoryRegionInfo &region_info) override;
+
+ bool SupportsMemoryTagging() override { return !m_core_tag_ranges.IsEmpty(); }
+
+private:
+ struct NT_FILE_Entry {
+ lldb::addr_t start;
+ lldb::addr_t end;
+ lldb::addr_t file_ofs;
+ std::string path;
+ // Add a UUID member for convenient access. The UUID value is not in the
+ // NT_FILE entries, we will find it in core memory and store it here for
+ // easy access.
+ lldb_private::UUID uuid;
+ };
+
+ // For ProcessElfCore only
+ typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
+ typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange>
+ VMRangeToFileOffset;
+ typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t>
+ VMRangeToPermissions;
+
+ lldb::ModuleSP m_core_module_sp;
+ std::string m_dyld_plugin_name;
+
+ // True if m_thread_contexts contains valid entries
+ bool m_thread_data_valid = false;
+
+ // Contain thread data read from NOTE segments
+ std::vector<ThreadData> m_thread_data;
+
+ // AUXV structure found from the NOTE segment
+ lldb_private::DataExtractor m_auxv;
+
+ // Address ranges found in the core
+ VMRangeToFileOffset m_core_aranges;
+
+ // Permissions for all ranges
+ VMRangeToPermissions m_core_range_infos;
+
+ // Memory tag ranges found in the core
+ VMRangeToFileOffset m_core_tag_ranges;
+
+ // NT_FILE entries found from the NOTE segment
+ std::vector<NT_FILE_Entry> m_nt_file_entries;
+
+ // Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment
+ llvm::Error ParseThreadContextsFromNoteSegment(
+ const elf::ELFProgramHeader &segment_header,
+ const lldb_private::DataExtractor &segment_data);
+
+ // Returns number of thread contexts stored in the core file
+ uint32_t GetNumThreadContexts();
+
+ // Populate gnu uuid for each NT_FILE entry
+ void UpdateBuildIdForNTFileEntries();
+
+ // Returns the value of certain type of note of a given start address
+ lldb_private::UUID FindBuidIdInCoreMemory(lldb::addr_t address);
+
+ // Parse a contiguous address range of the process from LOAD segment
+ lldb::addr_t
+ AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header);
+
+ // Parse a contiguous address range from a memory tag segment
+ lldb::addr_t
+ AddAddressRangeFromMemoryTagSegment(const elf::ELFProgramHeader &header);
+
+ llvm::Expected<std::vector<lldb_private::CoreNote>>
+ parseSegment(const lldb_private::DataExtractor &segment);
+ llvm::Error parseFreeBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
+ llvm::Error parseNetBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
+ llvm::Error parseOpenBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
+ llvm::Error parseLinuxNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextLinuxCore_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextLinuxCore_x86_64.cpp
new file mode 100644
index 000000000000..b806292c7a1a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextLinuxCore_x86_64.cpp
@@ -0,0 +1,237 @@
+//===-- RegisterContextLinuxCore_x86_64.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextLinuxCore_x86_64.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/RegisterValue.h"
+
+using namespace lldb_private;
+
+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 must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+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");
+
+const uint32_t g_lldb_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 must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+static_assert((sizeof(g_lldb_regnums_i386) / sizeof(g_lldb_regnums_i386[0])) -
+ 1 ==
+ k_num_fpr_registers_i386,
+ "g_lldb_regnums_i386 has wrong number of register infos");
+
+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 must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+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");
+
+static const uint32_t g_gpr_regnums_x86_64[] = {
+ x86_64_with_base::lldb_rax,
+ x86_64_with_base::lldb_rbx,
+ x86_64_with_base::lldb_rcx,
+ x86_64_with_base::lldb_rdx,
+ x86_64_with_base::lldb_rdi,
+ x86_64_with_base::lldb_rsi,
+ x86_64_with_base::lldb_rbp,
+ x86_64_with_base::lldb_rsp,
+ x86_64_with_base::lldb_r8,
+ x86_64_with_base::lldb_r9,
+ x86_64_with_base::lldb_r10,
+ x86_64_with_base::lldb_r11,
+ x86_64_with_base::lldb_r12,
+ x86_64_with_base::lldb_r13,
+ x86_64_with_base::lldb_r14,
+ x86_64_with_base::lldb_r15,
+ x86_64_with_base::lldb_rip,
+ x86_64_with_base::lldb_rflags,
+ x86_64_with_base::lldb_cs,
+ x86_64_with_base::lldb_fs,
+ x86_64_with_base::lldb_gs,
+ x86_64_with_base::lldb_ss,
+ x86_64_with_base::lldb_fs_base,
+ x86_64_with_base::lldb_gs_base,
+ x86_64_with_base::lldb_ds,
+ x86_64_with_base::lldb_es,
+ x86_64_with_base::lldb_eax,
+ x86_64_with_base::lldb_ebx,
+ x86_64_with_base::lldb_ecx,
+ x86_64_with_base::lldb_edx,
+ x86_64_with_base::lldb_edi,
+ x86_64_with_base::lldb_esi,
+ x86_64_with_base::lldb_ebp,
+ x86_64_with_base::lldb_esp,
+ x86_64_with_base::lldb_r8d, // Low 32 bits or r8
+ x86_64_with_base::lldb_r9d, // Low 32 bits or r9
+ x86_64_with_base::lldb_r10d, // Low 32 bits or r10
+ x86_64_with_base::lldb_r11d, // Low 32 bits or r11
+ x86_64_with_base::lldb_r12d, // Low 32 bits or r12
+ x86_64_with_base::lldb_r13d, // Low 32 bits or r13
+ x86_64_with_base::lldb_r14d, // Low 32 bits or r14
+ x86_64_with_base::lldb_r15d, // Low 32 bits or r15
+ x86_64_with_base::lldb_ax,
+ x86_64_with_base::lldb_bx,
+ x86_64_with_base::lldb_cx,
+ x86_64_with_base::lldb_dx,
+ x86_64_with_base::lldb_di,
+ x86_64_with_base::lldb_si,
+ x86_64_with_base::lldb_bp,
+ x86_64_with_base::lldb_sp,
+ x86_64_with_base::lldb_r8w, // Low 16 bits or r8
+ x86_64_with_base::lldb_r9w, // Low 16 bits or r9
+ x86_64_with_base::lldb_r10w, // Low 16 bits or r10
+ x86_64_with_base::lldb_r11w, // Low 16 bits or r11
+ x86_64_with_base::lldb_r12w, // Low 16 bits or r12
+ x86_64_with_base::lldb_r13w, // Low 16 bits or r13
+ x86_64_with_base::lldb_r14w, // Low 16 bits or r14
+ x86_64_with_base::lldb_r15w, // Low 16 bits or r15
+ x86_64_with_base::lldb_ah,
+ x86_64_with_base::lldb_bh,
+ x86_64_with_base::lldb_ch,
+ x86_64_with_base::lldb_dh,
+ x86_64_with_base::lldb_al,
+ x86_64_with_base::lldb_bl,
+ x86_64_with_base::lldb_cl,
+ x86_64_with_base::lldb_dl,
+ x86_64_with_base::lldb_dil,
+ x86_64_with_base::lldb_sil,
+ x86_64_with_base::lldb_bpl,
+ x86_64_with_base::lldb_spl,
+ x86_64_with_base::lldb_r8l, // Low 8 bits or r8
+ x86_64_with_base::lldb_r9l, // Low 8 bits or r9
+ x86_64_with_base::lldb_r10l, // Low 8 bits or r10
+ x86_64_with_base::lldb_r11l, // Low 8 bits or r11
+ x86_64_with_base::lldb_r12l, // Low 8 bits or r12
+ x86_64_with_base::lldb_r13l, // Low 8 bits or r13
+ x86_64_with_base::lldb_r14l, // Low 8 bits or r14
+ x86_64_with_base::lldb_r15l, // Low 8 bits or r15
+ LLDB_INVALID_REGNUM // Register sets must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
+ 1 ==
+ x86_64_with_base::k_num_gpr_registers,
+ "g_gpr_regnums_x86_64 has wrong number of register infos");
+
+static const uint32_t g_lldb_regnums_x86_64[] = {
+ x86_64_with_base::lldb_fctrl, x86_64_with_base::lldb_fstat,
+ x86_64_with_base::lldb_ftag, x86_64_with_base::lldb_fop,
+ x86_64_with_base::lldb_fiseg, x86_64_with_base::lldb_fioff,
+ x86_64_with_base::lldb_fip, x86_64_with_base::lldb_foseg,
+ x86_64_with_base::lldb_fooff, x86_64_with_base::lldb_fdp,
+ x86_64_with_base::lldb_mxcsr, x86_64_with_base::lldb_mxcsrmask,
+ x86_64_with_base::lldb_st0, x86_64_with_base::lldb_st1,
+ x86_64_with_base::lldb_st2, x86_64_with_base::lldb_st3,
+ x86_64_with_base::lldb_st4, x86_64_with_base::lldb_st5,
+ x86_64_with_base::lldb_st6, x86_64_with_base::lldb_st7,
+ x86_64_with_base::lldb_mm0, x86_64_with_base::lldb_mm1,
+ x86_64_with_base::lldb_mm2, x86_64_with_base::lldb_mm3,
+ x86_64_with_base::lldb_mm4, x86_64_with_base::lldb_mm5,
+ x86_64_with_base::lldb_mm6, x86_64_with_base::lldb_mm7,
+ x86_64_with_base::lldb_xmm0, x86_64_with_base::lldb_xmm1,
+ x86_64_with_base::lldb_xmm2, x86_64_with_base::lldb_xmm3,
+ x86_64_with_base::lldb_xmm4, x86_64_with_base::lldb_xmm5,
+ x86_64_with_base::lldb_xmm6, x86_64_with_base::lldb_xmm7,
+ x86_64_with_base::lldb_xmm8, x86_64_with_base::lldb_xmm9,
+ x86_64_with_base::lldb_xmm10, x86_64_with_base::lldb_xmm11,
+ x86_64_with_base::lldb_xmm12, x86_64_with_base::lldb_xmm13,
+ x86_64_with_base::lldb_xmm14, x86_64_with_base::lldb_xmm15,
+ LLDB_INVALID_REGNUM // Register sets must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+static_assert(
+ (sizeof(g_lldb_regnums_x86_64) / sizeof(g_lldb_regnums_x86_64[0])) - 1 ==
+ x86_64_with_base::k_num_fpr_registers,
+ "g_lldb_regnums_x86_64 has wrong number of register infos");
+
+static const uint32_t g_avx_regnums_x86_64[] = {
+ x86_64_with_base::lldb_ymm0, x86_64_with_base::lldb_ymm1,
+ x86_64_with_base::lldb_ymm2, x86_64_with_base::lldb_ymm3,
+ x86_64_with_base::lldb_ymm4, x86_64_with_base::lldb_ymm5,
+ x86_64_with_base::lldb_ymm6, x86_64_with_base::lldb_ymm7,
+ x86_64_with_base::lldb_ymm8, x86_64_with_base::lldb_ymm9,
+ x86_64_with_base::lldb_ymm10, x86_64_with_base::lldb_ymm11,
+ x86_64_with_base::lldb_ymm12, x86_64_with_base::lldb_ymm13,
+ x86_64_with_base::lldb_ymm14, x86_64_with_base::lldb_ymm15,
+ LLDB_INVALID_REGNUM // Register sets must be terminated with
+ // LLDB_INVALID_REGNUM.
+};
+static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) -
+ 1 ==
+ x86_64_with_base::k_num_avx_registers,
+ "g_avx_regnums_x86_64 has wrong number of register infos");
+
+static const RegisterSet g_reg_sets_i386[] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_i386,
+ g_gpr_regnums_i386},
+ {"Floating Point Registers", "fpu", k_num_fpr_registers_i386,
+ g_lldb_regnums_i386},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386,
+ g_avx_regnums_i386}};
+
+static const RegisterSet g_reg_sets_x86_64[] = {
+ {"General Purpose Registers", "gpr", x86_64_with_base::k_num_gpr_registers,
+ g_gpr_regnums_x86_64},
+ {"Floating Point Registers", "fpu", x86_64_with_base::k_num_fpr_registers,
+ g_lldb_regnums_x86_64},
+ {"Advanced Vector Extensions", "avx", x86_64_with_base::k_num_avx_registers,
+ g_avx_regnums_x86_64}};
+
+RegisterContextLinuxCore_x86_64::RegisterContextLinuxCore_x86_64(
+ Thread &thread, RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
+ : RegisterContextCorePOSIX_x86_64(thread, register_info, gpregset, notes) {}
+
+const RegisterSet *RegisterContextLinuxCore_x86_64::GetRegisterSet(size_t set) {
+ if (IsRegisterSetAvailable(set)) {
+ switch (m_register_info_up->GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ return &g_reg_sets_i386[set];
+ case llvm::Triple::x86_64:
+ return &g_reg_sets_x86_64[set];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
+
+RegInfo &RegisterContextLinuxCore_x86_64::GetRegInfo() {
+ return GetRegInfoShared(
+ m_register_info_up->GetTargetArchitecture().GetMachine(),
+ /*with_base=*/true);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextLinuxCore_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextLinuxCore_x86_64.h
new file mode 100644
index 000000000000..a68ed82d718c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextLinuxCore_x86_64.h
@@ -0,0 +1,28 @@
+//===-- RegisterContextLinuxCore_x86_64.h -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTLINUXCORE_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTLINUXCORE_X86_64_H
+
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "RegisterContextPOSIXCore_x86_64.h"
+
+class RegisterContextLinuxCore_x86_64 : public RegisterContextCorePOSIX_x86_64 {
+public:
+ RegisterContextLinuxCore_x86_64(
+ lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ lldb_private::RegInfo &GetRegInfo() override;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTLINUXCORE_X86_64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
new file mode 100644
index 000000000000..3a62081827c6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
@@ -0,0 +1,74 @@
+//===-- RegisterContextPOSIXCore_arm.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIXCore_arm.h"
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include <memory>
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm(
+ Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm> register_info,
+ const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
+ : RegisterContextPOSIX_arm(thread, std::move(register_info)) {
+ m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
+ gpregset.GetByteSize());
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm() = default;
+
+bool RegisterContextCorePOSIX_arm::ReadGPR() { return true; }
+
+bool RegisterContextCorePOSIX_arm::ReadFPR() { return false; }
+
+bool RegisterContextCorePOSIX_arm::WriteGPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_arm::WriteFPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_arm::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ lldb::offset_t offset = reg_info->byte_offset;
+ if (offset + reg_info->byte_size <= GetGPRSize()) {
+ uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size) {
+ value = v;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RegisterContextCorePOSIX_arm::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_arm::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_arm::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_arm::HardwareSingleStep(bool enable) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
new file mode 100644
index 000000000000..8d773a046bca
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
@@ -0,0 +1,53 @@
+//===-- RegisterContextPOSIXCore_arm.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+
+class RegisterContextCorePOSIX_arm : public RegisterContextPOSIX_arm {
+public:
+ RegisterContextCorePOSIX_arm(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm> register_info,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ ~RegisterContextCorePOSIX_arm() override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ bool HardwareSingleStep(bool enable) override;
+
+protected:
+ bool ReadGPR() override;
+
+ bool ReadFPR() override;
+
+ bool WriteGPR() override;
+
+ bool WriteFPR() override;
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb_private::DataExtractor m_gpr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
new file mode 100644
index 000000000000..413bf1bbdb2a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
@@ -0,0 +1,396 @@
+//===-- RegisterContextPOSIXCore_arm64.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIXCore_arm64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+
+#include "Plugins/Process/Utility/AuxVector.h"
+#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include <memory>
+
+using namespace lldb_private;
+
+std::unique_ptr<RegisterContextCorePOSIX_arm64>
+RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch,
+ const DataExtractor &gpregset,
+ llvm::ArrayRef<CoreNote> notes) {
+ Flags opt_regsets = RegisterInfoPOSIX_arm64::eRegsetMaskDefault;
+
+ DataExtractor ssve_data =
+ getRegset(notes, arch.GetTriple(), AARCH64_SSVE_Desc);
+ if (ssve_data.GetByteSize() >= sizeof(sve::user_sve_header))
+ opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSSVE);
+
+ DataExtractor sve_data = getRegset(notes, arch.GetTriple(), AARCH64_SVE_Desc);
+ if (sve_data.GetByteSize() >= sizeof(sve::user_sve_header))
+ opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE);
+
+ // Pointer Authentication register set data is based on struct
+ // user_pac_mask declared in ptrace.h. See reference implementation
+ // in Linux kernel source at arch/arm64/include/uapi/asm/ptrace.h.
+ DataExtractor pac_data = getRegset(notes, arch.GetTriple(), AARCH64_PAC_Desc);
+ if (pac_data.GetByteSize() >= sizeof(uint64_t) * 2)
+ opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth);
+
+ DataExtractor tls_data = getRegset(notes, arch.GetTriple(), AARCH64_TLS_Desc);
+ // A valid note will always contain at least one register, "tpidr". It may
+ // expand in future.
+ if (tls_data.GetByteSize() >= sizeof(uint64_t))
+ opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS);
+
+ DataExtractor za_data = getRegset(notes, arch.GetTriple(), AARCH64_ZA_Desc);
+ // Nothing if ZA is not present, just the header if it is disabled.
+ if (za_data.GetByteSize() >= sizeof(sve::user_za_header))
+ opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZA);
+
+ DataExtractor mte_data = getRegset(notes, arch.GetTriple(), AARCH64_MTE_Desc);
+ if (mte_data.GetByteSize() >= sizeof(uint64_t))
+ opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskMTE);
+
+ DataExtractor zt_data = getRegset(notes, arch.GetTriple(), AARCH64_ZT_Desc);
+ // Although ZT0 can be in a disabled state like ZA can, the kernel reports
+ // its content as 0s in that state. Therefore even a disabled ZT0 will have
+ // a note containing those 0s. ZT0 is a 512 bit / 64 byte register.
+ if (zt_data.GetByteSize() >= 64)
+ opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZT);
+
+ auto register_info_up =
+ std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
+ return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
+ new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up),
+ gpregset, notes));
+}
+
+RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
+ Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
+ const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
+ : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {
+ ::memset(&m_sme_pseudo_regs, 0, sizeof(m_sme_pseudo_regs));
+
+ ProcessElfCore *process =
+ static_cast<ProcessElfCore *>(thread.GetProcess().get());
+ llvm::Triple::OSType os = process->GetArchitecture().GetTriple().getOS();
+ if ((os == llvm::Triple::Linux) || (os == llvm::Triple::FreeBSD)) {
+ AuxVector aux_vec(process->GetAuxvData());
+ std::optional<uint64_t> auxv_at_hwcap = aux_vec.GetAuxValue(
+ os == llvm::Triple::FreeBSD ? AuxVector::AUXV_FREEBSD_AT_HWCAP
+ : AuxVector::AUXV_AT_HWCAP);
+ std::optional<uint64_t> auxv_at_hwcap2 =
+ aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP2);
+
+ m_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0),
+ auxv_at_hwcap2.value_or(0));
+ m_register_flags_detector.UpdateRegisterInfo(GetRegisterInfo(),
+ GetRegisterCount());
+ }
+
+ m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
+ gpregset.GetByteSize()));
+ m_gpr_data.SetByteOrder(gpregset.GetByteOrder());
+
+ const llvm::Triple &target_triple =
+ m_register_info_up->GetTargetArchitecture().GetTriple();
+ m_fpr_data = getRegset(notes, target_triple, FPR_Desc);
+
+ if (m_register_info_up->IsSSVEPresent()) {
+ m_sve_data = getRegset(notes, target_triple, AARCH64_SSVE_Desc);
+ lldb::offset_t flags_offset = 12;
+ uint16_t flags = m_sve_data.GetU32(&flags_offset);
+ if ((flags & sve::ptrace_regs_mask) == sve::ptrace_regs_sve)
+ m_sve_state = SVEState::Streaming;
+ }
+
+ if (m_sve_state != SVEState::Streaming && m_register_info_up->IsSVEPresent())
+ m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc);
+
+ if (m_register_info_up->IsPAuthPresent())
+ m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc);
+
+ if (m_register_info_up->IsTLSPresent())
+ m_tls_data = getRegset(notes, target_triple, AARCH64_TLS_Desc);
+
+ if (m_register_info_up->IsZAPresent())
+ m_za_data = getRegset(notes, target_triple, AARCH64_ZA_Desc);
+
+ if (m_register_info_up->IsMTEPresent())
+ m_mte_data = getRegset(notes, target_triple, AARCH64_MTE_Desc);
+
+ if (m_register_info_up->IsZTPresent())
+ m_zt_data = getRegset(notes, target_triple, AARCH64_ZT_Desc);
+
+ ConfigureRegisterContext();
+}
+
+RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default;
+
+bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; }
+
+bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; }
+
+bool RegisterContextCorePOSIX_arm64::WriteGPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_arm64::WriteFPR() {
+ assert(0);
+ return false;
+}
+
+const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) {
+ return m_sve_data.GetDataStart() + offset;
+}
+
+void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() {
+ if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) {
+ uint64_t sve_header_field_offset = 8;
+ m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset);
+
+ if (m_sve_state != SVEState::Streaming) {
+ sve_header_field_offset = 12;
+ uint16_t sve_header_flags_field =
+ m_sve_data.GetU16(&sve_header_field_offset);
+ if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
+ sve::ptrace_regs_fpsimd)
+ m_sve_state = SVEState::FPSIMD;
+ else if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
+ sve::ptrace_regs_sve)
+ m_sve_state = SVEState::Full;
+ }
+
+ if (!sve::vl_valid(m_sve_vector_length)) {
+ m_sve_state = SVEState::Disabled;
+ m_sve_vector_length = 0;
+ }
+ } else
+ m_sve_state = SVEState::Disabled;
+
+ if (m_sve_state != SVEState::Disabled)
+ m_register_info_up->ConfigureVectorLengthSVE(
+ sve::vq_from_vl(m_sve_vector_length));
+
+ if (m_sve_state == SVEState::Streaming)
+ m_sme_pseudo_regs.ctrl_reg |= 1;
+
+ if (m_za_data.GetByteSize() >= sizeof(sve::user_za_header)) {
+ lldb::offset_t vlen_offset = 8;
+ uint16_t svl = m_za_data.GetU16(&vlen_offset);
+ m_sme_pseudo_regs.svg_reg = svl / 8;
+ m_register_info_up->ConfigureVectorLengthZA(svl / 16);
+
+ // If there is register data then ZA is active. The size of the note may be
+ // misleading here so we use the size field of the embedded header.
+ lldb::offset_t size_offset = 0;
+ uint32_t size = m_za_data.GetU32(&size_offset);
+ if (size > sizeof(sve::user_za_header))
+ m_sme_pseudo_regs.ctrl_reg |= 1 << 1;
+ }
+}
+
+uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(
+ const RegisterInfo *reg_info) {
+ // Start of Z0 data is after GPRs plus 8 bytes of vg register
+ uint32_t sve_reg_offset = LLDB_INVALID_INDEX32;
+ if (m_sve_state == SVEState::FPSIMD) {
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16;
+ } else if (m_sve_state == SVEState::Full ||
+ m_sve_state == SVEState::Streaming) {
+ uint32_t sve_z0_offset = GetGPRSize() + 16;
+ sve_reg_offset =
+ sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset;
+ }
+
+ return sve_reg_offset;
+}
+
+bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ Status error;
+ lldb::offset_t offset;
+
+ offset = reg_info->byte_offset;
+ if (offset + reg_info->byte_size <= GetGPRSize()) {
+ value.SetFromMemoryData(*reg_info, m_gpr_data.GetDataStart() + offset,
+ reg_info->byte_size, lldb::eByteOrderLittle, error);
+ return error.Success();
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM)
+ return false;
+
+ if (IsFPR(reg)) {
+ if (m_sve_state == SVEState::Disabled) {
+ // SVE is disabled take legacy route for FPU register access
+ offset -= GetGPRSize();
+ if (offset < m_fpr_data.GetByteSize()) {
+ value.SetFromMemoryData(*reg_info, m_fpr_data.GetDataStart() + offset,
+ reg_info->byte_size, lldb::eByteOrderLittle,
+ error);
+ return error.Success();
+ }
+ } else {
+ // FPSR and FPCR will be located right after Z registers in
+ // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will
+ // be located at the end of register data after an alignment correction
+ // based on currently selected vector length.
+ uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
+ if (reg == GetRegNumFPSR()) {
+ sve_reg_num = reg;
+ if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming)
+ offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length));
+ else if (m_sve_state == SVEState::FPSIMD)
+ offset = sve::ptrace_fpsimd_offset + (32 * 16);
+ } else if (reg == GetRegNumFPCR()) {
+ sve_reg_num = reg;
+ if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming)
+ offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length));
+ else if (m_sve_state == SVEState::FPSIMD)
+ offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4;
+ } else {
+ // Extract SVE Z register value register number for this reg_info
+ if (reg_info->value_regs &&
+ reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
+ sve_reg_num = reg_info->value_regs[0];
+ offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
+ }
+
+ assert(sve_reg_num != LLDB_INVALID_REGNUM);
+ assert(offset < m_sve_data.GetByteSize());
+ value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
+ reg_info->byte_size, lldb::eByteOrderLittle,
+ error);
+ }
+ } else if (IsSVE(reg)) {
+ if (IsSVEVG(reg)) {
+ value = GetSVERegVG();
+ return true;
+ }
+
+ switch (m_sve_state) {
+ case SVEState::FPSIMD: {
+ // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just
+ // copy 16 bytes of v register to the start of z register. All other
+ // SVE register will be set to zero.
+ uint64_t byte_size = 1;
+ uint8_t zeros = 0;
+ const uint8_t *src = &zeros;
+ if (IsSVEZ(reg)) {
+ byte_size = 16;
+ offset = CalculateSVEOffset(reg_info);
+ assert(offset < m_sve_data.GetByteSize());
+ src = GetSVEBuffer(offset);
+ }
+ value.SetFromMemoryData(*reg_info, src, byte_size, lldb::eByteOrderLittle,
+ error);
+ } break;
+ case SVEState::Full:
+ case SVEState::Streaming:
+ offset = CalculateSVEOffset(reg_info);
+ assert(offset < m_sve_data.GetByteSize());
+ value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
+ reg_info->byte_size, lldb::eByteOrderLittle,
+ error);
+ break;
+ case SVEState::Disabled:
+ default:
+ return false;
+ }
+ } else if (IsPAuth(reg)) {
+ offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset();
+ assert(offset < m_pac_data.GetByteSize());
+ value.SetFromMemoryData(*reg_info, m_pac_data.GetDataStart() + offset,
+ reg_info->byte_size, lldb::eByteOrderLittle, error);
+ } else if (IsTLS(reg)) {
+ offset = reg_info->byte_offset - m_register_info_up->GetTLSOffset();
+ assert(offset < m_tls_data.GetByteSize());
+ value.SetFromMemoryData(*reg_info, m_tls_data.GetDataStart() + offset,
+ reg_info->byte_size, lldb::eByteOrderLittle, error);
+ } else if (IsMTE(reg)) {
+ offset = reg_info->byte_offset - m_register_info_up->GetMTEOffset();
+ assert(offset < m_mte_data.GetByteSize());
+ value.SetFromMemoryData(*reg_info, m_mte_data.GetDataStart() + offset,
+ reg_info->byte_size, lldb::eByteOrderLittle, error);
+ } else if (IsSME(reg)) {
+ // If you had SME in the process, active or otherwise, there will at least
+ // be a ZA header. No header, no SME at all.
+ if (m_za_data.GetByteSize() < sizeof(sve::user_za_header))
+ return false;
+
+ if (m_register_info_up->IsSMERegZA(reg)) {
+ // Don't use the size of the note to tell whether ZA is enabled. There may
+ // be non-register padding data after the header. Use the embedded
+ // header's size field instead.
+ lldb::offset_t size_offset = 0;
+ uint32_t size = m_za_data.GetU32(&size_offset);
+ bool za_enabled = size > sizeof(sve::user_za_header);
+
+ size_t za_note_size = m_za_data.GetByteSize();
+ // For a disabled ZA we fake a value of all 0s.
+ if (!za_enabled) {
+ uint64_t svl = m_sme_pseudo_regs.svg_reg * 8;
+ za_note_size = sizeof(sve::user_za_header) + (svl * svl);
+ }
+
+ const uint8_t *src = nullptr;
+ std::vector<uint8_t> disabled_za_data;
+
+ if (za_enabled)
+ src = m_za_data.GetDataStart();
+ else {
+ disabled_za_data.resize(za_note_size);
+ std::fill(disabled_za_data.begin(), disabled_za_data.end(), 0);
+ src = disabled_za_data.data();
+ }
+
+ value.SetFromMemoryData(*reg_info, src + sizeof(sve::user_za_header),
+ reg_info->byte_size, lldb::eByteOrderLittle,
+ error);
+ } else if (m_register_info_up->IsSMERegZT(reg)) {
+ value.SetFromMemoryData(*reg_info, m_zt_data.GetDataStart(),
+ reg_info->byte_size, lldb::eByteOrderLittle,
+ error);
+ } else {
+ offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset();
+ assert(offset < sizeof(m_sme_pseudo_regs));
+ // Host endian since these values are derived instead of being read from a
+ // core file note.
+ value.SetFromMemoryData(
+ *reg_info, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset,
+ reg_info->byte_size, lldb_private::endian::InlHostByteOrder(), error);
+ }
+ } else
+ return false;
+
+ return error.Success();
+}
+
+bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
new file mode 100644
index 000000000000..ff94845e58d6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
@@ -0,0 +1,89 @@
+//===-- RegisterContextPOSIXCore_arm64.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H
+
+#include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
+#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
+
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+
+class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 {
+public:
+ static std::unique_ptr<RegisterContextCorePOSIX_arm64>
+ Create(lldb_private::Thread &thread, const lldb_private::ArchSpec &arch,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ ~RegisterContextCorePOSIX_arm64() override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ bool HardwareSingleStep(bool enable) override;
+
+protected:
+ RegisterContextCorePOSIX_arm64(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ bool ReadGPR() override;
+
+ bool ReadFPR() override;
+
+ bool WriteGPR() override;
+
+ bool WriteFPR() override;
+
+private:
+ lldb_private::DataExtractor m_gpr_data;
+ lldb_private::DataExtractor m_fpr_data;
+ lldb_private::DataExtractor m_sve_data;
+ lldb_private::DataExtractor m_pac_data;
+ lldb_private::DataExtractor m_tls_data;
+ lldb_private::DataExtractor m_za_data;
+ lldb_private::DataExtractor m_mte_data;
+ lldb_private::DataExtractor m_zt_data;
+
+ SVEState m_sve_state = SVEState::Unknown;
+ uint16_t m_sve_vector_length = 0;
+
+ // These are pseudo registers derived from the values in SSVE and ZA data.
+ struct __attribute__((packed)) sme_pseudo_regs {
+ uint64_t ctrl_reg;
+ uint64_t svg_reg;
+ };
+ static_assert(sizeof(sme_pseudo_regs) == 16);
+
+ struct sme_pseudo_regs m_sme_pseudo_regs;
+
+ lldb_private::Arm64RegisterFlagsDetector m_register_flags_detector;
+
+ const uint8_t *GetSVEBuffer(uint64_t offset = 0);
+
+ void ConfigureRegisterContext();
+
+ uint32_t CalculateSVEOffset(const lldb_private::RegisterInfo *reg_info);
+
+ uint64_t GetSVERegVG() { return m_sve_vector_length / 8; }
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
new file mode 100644
index 000000000000..56e68742ead7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
@@ -0,0 +1,91 @@
+//===-- RegisterContextPOSIXCore_mips64.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIXCore_mips64.h"
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include <memory>
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_mips64::RegisterContextCorePOSIX_mips64(
+ Thread &thread, RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
+ : RegisterContextPOSIX_mips64(thread, 0, register_info) {
+ m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
+ gpregset.GetByteSize());
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+
+ DataExtractor fpregset = getRegset(
+ notes, register_info->GetTargetArchitecture().GetTriple(), FPR_Desc);
+ m_fpr_buffer = std::make_shared<DataBufferHeap>(fpregset.GetDataStart(),
+ fpregset.GetByteSize());
+ m_fpr.SetData(m_fpr_buffer);
+ m_fpr.SetByteOrder(fpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_mips64::~RegisterContextCorePOSIX_mips64() = default;
+
+bool RegisterContextCorePOSIX_mips64::ReadGPR() { return true; }
+
+bool RegisterContextCorePOSIX_mips64::ReadFPR() { return false; }
+
+bool RegisterContextCorePOSIX_mips64::WriteGPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_mips64::WriteFPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_mips64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+
+ lldb::offset_t offset = reg_info->byte_offset;
+ lldb_private::ArchSpec arch = m_register_info_up->GetTargetArchitecture();
+ uint64_t v;
+ if (IsGPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ if (reg_info->byte_size == 4 && !(arch.GetMachine() == llvm::Triple::mips64el))
+ // In case of 32bit core file, the register data are placed at 4 byte
+ // offset.
+ offset = offset / 2;
+ v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ value = v;
+ return true;
+ } else if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ offset = offset - sizeof(GPR_linux_mips);
+ v =m_fpr.GetMaxU64(&offset, reg_info->byte_size);
+ value = v;
+ return true;
+ }
+ return false;
+}
+
+bool RegisterContextCorePOSIX_mips64::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_mips64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &value) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_mips64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_mips64::HardwareSingleStep(bool enable) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h
new file mode 100644
index 000000000000..529b00215e35
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h
@@ -0,0 +1,55 @@
+//===-- RegisterContextPOSIXCore_mips64.h -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_MIPS64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_MIPS64_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+
+class RegisterContextCorePOSIX_mips64 : public RegisterContextPOSIX_mips64 {
+public:
+ RegisterContextCorePOSIX_mips64(
+ lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ ~RegisterContextCorePOSIX_mips64() override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ bool HardwareSingleStep(bool enable) override;
+
+protected:
+ bool ReadGPR() override;
+
+ bool ReadFPR() override;
+
+ bool WriteGPR() override;
+
+ bool WriteFPR() override;
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb::DataBufferSP m_fpr_buffer;
+ lldb_private::DataExtractor m_gpr;
+ lldb_private::DataExtractor m_fpr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_MIPS64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp
new file mode 100644
index 000000000000..4e7be91c3895
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp
@@ -0,0 +1,111 @@
+//===-- RegisterContextPOSIXCore_powerpc.cpp ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIXCore_powerpc.h"
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include <memory>
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_powerpc::RegisterContextCorePOSIX_powerpc(
+ Thread &thread, RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
+ : RegisterContextPOSIX_powerpc(thread, 0, register_info) {
+ m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
+ gpregset.GetByteSize());
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+
+ ArchSpec arch = register_info->GetTargetArchitecture();
+ DataExtractor fpregset = getRegset(notes, arch.GetTriple(), FPR_Desc);
+ m_fpr_buffer = std::make_shared<DataBufferHeap>(fpregset.GetDataStart(),
+ fpregset.GetByteSize());
+ m_fpr.SetData(m_fpr_buffer);
+ m_fpr.SetByteOrder(fpregset.GetByteOrder());
+
+ DataExtractor vregset = getRegset(notes, arch.GetTriple(), PPC_VMX_Desc);
+ m_vec_buffer = std::make_shared<DataBufferHeap>(vregset.GetDataStart(),
+ vregset.GetByteSize());
+ m_vec.SetData(m_vec_buffer);
+ m_vec.SetByteOrder(vregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_powerpc::~RegisterContextCorePOSIX_powerpc() = default;
+
+bool RegisterContextCorePOSIX_powerpc::ReadGPR() { return true; }
+
+bool RegisterContextCorePOSIX_powerpc::ReadFPR() { return true; }
+
+bool RegisterContextCorePOSIX_powerpc::ReadVMX() { return true; }
+
+bool RegisterContextCorePOSIX_powerpc::WriteGPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_powerpc::WriteFPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_powerpc::WriteVMX() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_powerpc::ReadRegister(
+ const RegisterInfo *reg_info, RegisterValue &value) {
+ lldb::offset_t offset = reg_info->byte_offset;
+ if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ uint64_t v = m_fpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size) {
+ value = v;
+ return true;
+ }
+ } else if (IsVMX(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ uint32_t v[4];
+ offset = m_vec.CopyData(offset, reg_info->byte_size, &v);
+ if (offset == reg_info->byte_size) {
+ value.SetBytes(v, reg_info->byte_size, m_vec.GetByteOrder());
+ return true;
+ }
+ } else {
+ uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size) {
+ if (reg_info->byte_size < sizeof(v))
+ value = (uint32_t)v;
+ else
+ value = v;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RegisterContextCorePOSIX_powerpc::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_powerpc::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &value) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_powerpc::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_powerpc::HardwareSingleStep(bool enable) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h
new file mode 100644
index 000000000000..5364c5589238
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h
@@ -0,0 +1,60 @@
+//===-- RegisterContextPOSIXCore_powerpc.h ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_POWERPC_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_POWERPC_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "lldb/Utility/DataExtractor.h"
+
+class RegisterContextCorePOSIX_powerpc : public RegisterContextPOSIX_powerpc {
+public:
+ RegisterContextCorePOSIX_powerpc(
+ lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ ~RegisterContextCorePOSIX_powerpc() override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ bool HardwareSingleStep(bool enable) override;
+
+protected:
+ bool ReadGPR() override;
+
+ bool ReadFPR() override;
+
+ bool ReadVMX() override;
+
+ bool WriteGPR() override;
+
+ bool WriteFPR() override;
+
+ bool WriteVMX() override;
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb::DataBufferSP m_fpr_buffer;
+ lldb::DataBufferSP m_vec_buffer;
+ lldb_private::DataExtractor m_gpr;
+ lldb_private::DataExtractor m_fpr;
+ lldb_private::DataExtractor m_vec;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_POWERPC_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp
new file mode 100644
index 000000000000..d44fb399e18a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.cpp
@@ -0,0 +1,133 @@
+//===-- RegisterContextPOSIXCore_ppc64le.cpp ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIXCore_ppc64le.h"
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+#include <memory>
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_ppc64le::RegisterContextCorePOSIX_ppc64le(
+ Thread &thread, RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
+ : RegisterContextPOSIX_ppc64le(thread, 0, register_info) {
+ m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
+ gpregset.GetByteSize());
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+
+ ArchSpec arch = register_info->GetTargetArchitecture();
+ DataExtractor fpregset = getRegset(notes, arch.GetTriple(), FPR_Desc);
+ m_fpr_buffer = std::make_shared<DataBufferHeap>(fpregset.GetDataStart(),
+ fpregset.GetByteSize());
+ m_fpr.SetData(m_fpr_buffer);
+ m_fpr.SetByteOrder(fpregset.GetByteOrder());
+
+ DataExtractor vmxregset = getRegset(notes, arch.GetTriple(), PPC_VMX_Desc);
+ m_vmx_buffer = std::make_shared<DataBufferHeap>(vmxregset.GetDataStart(),
+ vmxregset.GetByteSize());
+ m_vmx.SetData(m_vmx_buffer);
+ m_vmx.SetByteOrder(vmxregset.GetByteOrder());
+
+ DataExtractor vsxregset = getRegset(notes, arch.GetTriple(), PPC_VSX_Desc);
+ m_vsx_buffer = std::make_shared<DataBufferHeap>(vsxregset.GetDataStart(),
+ vsxregset.GetByteSize());
+ m_vsx.SetData(m_vsx_buffer);
+ m_vsx.SetByteOrder(vsxregset.GetByteOrder());
+}
+
+size_t RegisterContextCorePOSIX_ppc64le::GetFPRSize() const {
+ return k_num_fpr_registers_ppc64le * sizeof(uint64_t);
+}
+
+size_t RegisterContextCorePOSIX_ppc64le::GetVMXSize() const {
+ return (k_num_vmx_registers_ppc64le - 1) * sizeof(uint64_t) * 2 +
+ sizeof(uint32_t);
+}
+
+size_t RegisterContextCorePOSIX_ppc64le::GetVSXSize() const {
+ return k_num_vsx_registers_ppc64le * sizeof(uint64_t) * 2;
+}
+
+bool RegisterContextCorePOSIX_ppc64le::ReadRegister(
+ const RegisterInfo *reg_info, RegisterValue &value) {
+ lldb::offset_t offset = reg_info->byte_offset;
+
+ if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ uint64_t v;
+ offset -= GetGPRSize();
+ offset = m_fpr.CopyData(offset, reg_info->byte_size, &v);
+
+ if (offset == reg_info->byte_size) {
+ value.SetBytes(&v, reg_info->byte_size, m_fpr.GetByteOrder());
+ return true;
+ }
+ } else if (IsVMX(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ uint32_t v[4];
+ offset -= GetGPRSize() + GetFPRSize();
+ offset = m_vmx.CopyData(offset, reg_info->byte_size, &v);
+
+ if (offset == reg_info->byte_size) {
+ value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder());
+ return true;
+ }
+ } else if (IsVSX(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ uint32_t v[4];
+ lldb::offset_t tmp_offset;
+ offset -= GetGPRSize() + GetFPRSize() + GetVMXSize();
+
+ if (offset < GetVSXSize() / 2) {
+ tmp_offset = m_vsx.CopyData(offset / 2, reg_info->byte_size / 2, &v);
+
+ if (tmp_offset != reg_info->byte_size / 2) {
+ return false;
+ }
+
+ uint8_t *dst = (uint8_t *)&v + sizeof(uint64_t);
+ tmp_offset = m_fpr.CopyData(offset / 2, reg_info->byte_size / 2, dst);
+
+ if (tmp_offset != reg_info->byte_size / 2) {
+ return false;
+ }
+
+ value.SetBytes(&v, reg_info->byte_size, m_vsx.GetByteOrder());
+ return true;
+ } else {
+ offset =
+ m_vmx.CopyData(offset - GetVSXSize() / 2, reg_info->byte_size, &v);
+ if (offset == reg_info->byte_size) {
+ value.SetBytes(v, reg_info->byte_size, m_vmx.GetByteOrder());
+ return true;
+ }
+ }
+ } else {
+ uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+
+ if (offset == reg_info->byte_offset + reg_info->byte_size) {
+ if (reg_info->byte_size < sizeof(v))
+ value = (uint32_t)v;
+ else
+ value = v;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool RegisterContextCorePOSIX_ppc64le::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &value) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.h
new file mode 100644
index 000000000000..8de77a7e25bf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.h
@@ -0,0 +1,48 @@
+//===-- RegisterContextPOSIXCore_ppc64le.h ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_PPC64LE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_PPC64LE_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "lldb/Utility/DataExtractor.h"
+
+class RegisterContextCorePOSIX_ppc64le : public RegisterContextPOSIX_ppc64le {
+public:
+ RegisterContextCorePOSIX_ppc64le(
+ lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+protected:
+ size_t GetFPRSize() const;
+
+ size_t GetVMXSize() const;
+
+ size_t GetVSXSize() const;
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb::DataBufferSP m_fpr_buffer;
+ lldb::DataBufferSP m_vmx_buffer;
+ lldb::DataBufferSP m_vsx_buffer;
+ lldb_private::DataExtractor m_gpr;
+ lldb_private::DataExtractor m_fpr;
+ lldb_private::DataExtractor m_vmx;
+ lldb_private::DataExtractor m_vsx;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_PPC64LE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.cpp
new file mode 100644
index 000000000000..5ba18cdb9889
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.cpp
@@ -0,0 +1,82 @@
+//===-- RegisterContextPOSIXCore_riscv64.cpp ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIXCore_riscv64.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+
+using namespace lldb_private;
+
+std::unique_ptr<RegisterContextCorePOSIX_riscv64>
+RegisterContextCorePOSIX_riscv64::Create(Thread &thread, const ArchSpec &arch,
+ const DataExtractor &gpregset,
+ llvm::ArrayRef<CoreNote> notes) {
+ return std::unique_ptr<RegisterContextCorePOSIX_riscv64>(
+ new RegisterContextCorePOSIX_riscv64(
+ thread, std::make_unique<RegisterInfoPOSIX_riscv64>(arch, Flags()),
+ gpregset, notes));
+}
+
+RegisterContextCorePOSIX_riscv64::RegisterContextCorePOSIX_riscv64(
+ Thread &thread, std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info,
+ const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
+ : RegisterContextPOSIX_riscv64(thread, std::move(register_info)) {
+
+ m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
+ gpregset.GetByteSize());
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+
+ ArchSpec arch = m_register_info_up->GetTargetArchitecture();
+ DataExtractor fpregset = getRegset(notes, arch.GetTriple(), FPR_Desc);
+ m_fpr_buffer = std::make_shared<DataBufferHeap>(fpregset.GetDataStart(),
+ fpregset.GetByteSize());
+ m_fpr.SetData(m_fpr_buffer);
+ m_fpr.SetByteOrder(fpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_riscv64::~RegisterContextCorePOSIX_riscv64() = default;
+
+bool RegisterContextCorePOSIX_riscv64::ReadGPR() { return true; }
+
+bool RegisterContextCorePOSIX_riscv64::ReadFPR() { return true; }
+
+bool RegisterContextCorePOSIX_riscv64::WriteGPR() {
+ assert(false && "Writing registers is not allowed for core dumps");
+ return false;
+}
+
+bool RegisterContextCorePOSIX_riscv64::WriteFPR() {
+ assert(false && "Writing registers is not allowed for core dumps");
+ return false;
+}
+
+bool RegisterContextCorePOSIX_riscv64::ReadRegister(
+ const RegisterInfo *reg_info, RegisterValue &value) {
+ const uint8_t *src = nullptr;
+ lldb::offset_t offset = reg_info->byte_offset;
+
+ if (IsGPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ src = m_gpr.GetDataStart();
+ } else if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ src = m_fpr.GetDataStart();
+ offset -= GetGPRSize();
+ } else {
+ return false;
+ }
+
+ Status error;
+ value.SetFromMemoryData(*reg_info, src + offset, reg_info->byte_size,
+ lldb::eByteOrderLittle, error);
+ return error.Success();
+}
+
+bool RegisterContextCorePOSIX_riscv64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &value) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.h
new file mode 100644
index 000000000000..3cf9531df2c1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.h
@@ -0,0 +1,60 @@
+//===-- RegisterContextPOSIXCore_riscv64.h ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_RISCV64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_RISCV64_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_riscv64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h"
+
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include <memory>
+
+class RegisterContextCorePOSIX_riscv64 : public RegisterContextPOSIX_riscv64 {
+public:
+ static std::unique_ptr<RegisterContextCorePOSIX_riscv64>
+ Create(lldb_private::Thread &thread, const lldb_private::ArchSpec &arch,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ ~RegisterContextCorePOSIX_riscv64() override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+protected:
+ RegisterContextCorePOSIX_riscv64(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ bool ReadGPR() override;
+
+ bool ReadFPR() override;
+
+ bool WriteGPR() override;
+
+ bool WriteFPR() override;
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb::DataBufferSP m_fpr_buffer;
+
+ lldb_private::DataExtractor m_gpr;
+ lldb_private::DataExtractor m_fpr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_RISCV64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp
new file mode 100644
index 000000000000..69707eeb3f1e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp
@@ -0,0 +1,96 @@
+//===-- RegisterContextPOSIXCore_s390x.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIXCore_s390x.h"
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include <memory>
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_s390x::RegisterContextCorePOSIX_s390x(
+ Thread &thread, RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
+ : RegisterContextPOSIX_s390x(thread, 0, register_info) {
+ m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
+ gpregset.GetByteSize());
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+
+ DataExtractor fpregset = getRegset(
+ notes, register_info->GetTargetArchitecture().GetTriple(), FPR_Desc);
+ m_fpr_buffer = std::make_shared<DataBufferHeap>(fpregset.GetDataStart(),
+ fpregset.GetByteSize());
+ m_fpr.SetData(m_fpr_buffer);
+ m_fpr.SetByteOrder(fpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_s390x::~RegisterContextCorePOSIX_s390x() = default;
+
+bool RegisterContextCorePOSIX_s390x::ReadGPR() { return true; }
+
+bool RegisterContextCorePOSIX_s390x::ReadFPR() { return true; }
+
+bool RegisterContextCorePOSIX_s390x::WriteGPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_s390x::WriteFPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_s390x::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM)
+ return false;
+
+ if (IsGPR(reg)) {
+ lldb::offset_t offset = reg_info->byte_offset;
+ uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size) {
+ value.SetUInt(v, reg_info->byte_size);
+ return true;
+ }
+ }
+
+ if (IsFPR(reg)) {
+ lldb::offset_t offset = reg_info->byte_offset;
+ uint64_t v = m_fpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size) {
+ value.SetUInt(v, reg_info->byte_size);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool RegisterContextCorePOSIX_s390x::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_s390x::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_s390x::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_s390x::HardwareSingleStep(bool enable) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h
new file mode 100644
index 000000000000..edb7cbc9462f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h
@@ -0,0 +1,55 @@
+//===-- RegisterContextPOSIXCore_s390x.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_S390X_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_S390X_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_s390x.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "lldb/Utility/DataExtractor.h"
+
+class RegisterContextCorePOSIX_s390x : public RegisterContextPOSIX_s390x {
+public:
+ RegisterContextCorePOSIX_s390x(
+ lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ ~RegisterContextCorePOSIX_s390x() override;
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ bool HardwareSingleStep(bool enable) override;
+
+protected:
+ bool ReadGPR() override;
+
+ bool ReadFPR() override;
+
+ bool WriteGPR() override;
+
+ bool WriteFPR() override;
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb_private::DataExtractor m_gpr;
+
+ lldb::DataBufferSP m_fpr_buffer;
+ lldb_private::DataExtractor m_fpr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_S390X_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp
new file mode 100644
index 000000000000..845312f4c1ed
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp
@@ -0,0 +1,99 @@
+//===-- RegisterContextPOSIXCore_x86_64.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIXCore_x86_64.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/RegisterValue.h"
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_x86_64::RegisterContextCorePOSIX_x86_64(
+ Thread &thread, RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
+ : RegisterContextPOSIX_x86(thread, 0, register_info) {
+ size_t size, len;
+
+ size = GetGPRSize();
+ m_gpregset.reset(new uint8_t[size]);
+ len =
+ gpregset.ExtractBytes(0, size, lldb::eByteOrderLittle, m_gpregset.get());
+ if (len != size)
+ m_gpregset.reset();
+
+ DataExtractor fpregset = getRegset(
+ notes, register_info->GetTargetArchitecture().GetTriple(), FPR_Desc);
+ size = sizeof(FXSAVE);
+ m_fpregset.reset(new uint8_t[size]);
+ len =
+ fpregset.ExtractBytes(0, size, lldb::eByteOrderLittle, m_fpregset.get());
+ if (len != size)
+ m_fpregset.reset();
+}
+
+bool RegisterContextCorePOSIX_x86_64::ReadGPR() {
+ return m_gpregset != nullptr;
+}
+
+bool RegisterContextCorePOSIX_x86_64::ReadFPR() {
+ return m_fpregset != nullptr;
+}
+
+bool RegisterContextCorePOSIX_x86_64::WriteGPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_x86_64::WriteFPR() {
+ assert(0);
+ return false;
+}
+
+bool RegisterContextCorePOSIX_x86_64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ const uint8_t *src;
+ size_t offset;
+ const size_t fxsave_offset = reg_info->byte_offset - GetFXSAVEOffset();
+ // make the offset relative to the beginning of the FXSAVE structure because
+ // this is the data that we have (not the entire UserArea)
+
+ if (m_gpregset && reg_info->byte_offset < GetGPRSize()) {
+ src = m_gpregset.get();
+ offset = reg_info->byte_offset;
+ } else if (m_fpregset && fxsave_offset < sizeof(FXSAVE)) {
+ src = m_fpregset.get();
+ offset = fxsave_offset;
+ } else {
+ return false;
+ }
+
+ Status error;
+ value.SetFromMemoryData(*reg_info, src + offset, reg_info->byte_size,
+ lldb::eByteOrderLittle, error);
+
+ return error.Success();
+}
+
+bool RegisterContextCorePOSIX_x86_64::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_x86_64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &value) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_x86_64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ return false;
+}
+
+bool RegisterContextCorePOSIX_x86_64::HardwareSingleStep(bool enable) {
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h
new file mode 100644
index 000000000000..46416a2381db
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h
@@ -0,0 +1,49 @@
+//===-- RegisterContextPOSIXCore_x86_64.h -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_X86_64_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+class RegisterContextCorePOSIX_x86_64 : public RegisterContextPOSIX_x86 {
+public:
+ RegisterContextCorePOSIX_x86_64(
+ lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
+ bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value) override;
+
+ bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ bool HardwareSingleStep(bool enable) override;
+
+protected:
+ bool ReadGPR() override;
+
+ bool ReadFPR() override;
+
+ bool WriteGPR() override;
+
+ bool WriteFPR() override;
+
+private:
+ std::unique_ptr<uint8_t[]> m_gpregset;
+ std::unique_ptr<uint8_t[]> m_fpregset;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_X86_64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.cpp
new file mode 100644
index 000000000000..7455d78774ee
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.cpp
@@ -0,0 +1,39 @@
+//===-- RegisterUtilities.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "llvm/ADT/STLExtras.h"
+#include <optional>
+
+using namespace lldb_private;
+
+static std::optional<uint32_t>
+getNoteType(const llvm::Triple &Triple,
+ llvm::ArrayRef<RegsetDesc> RegsetDescs) {
+ for (const auto &Entry : RegsetDescs) {
+ if (Entry.OS != Triple.getOS())
+ continue;
+ if (Entry.Arch != llvm::Triple::UnknownArch &&
+ Entry.Arch != Triple.getArch())
+ continue;
+ return Entry.Note;
+ }
+ return std::nullopt;
+}
+
+DataExtractor lldb_private::getRegset(llvm::ArrayRef<CoreNote> Notes,
+ const llvm::Triple &Triple,
+ llvm::ArrayRef<RegsetDesc> RegsetDescs) {
+ auto TypeOr = getNoteType(Triple, RegsetDescs);
+ if (!TypeOr)
+ return DataExtractor();
+ uint32_t Type = *TypeOr;
+ auto Iter = llvm::find_if(
+ Notes, [Type](const CoreNote &Note) { return Note.info.n_type == Type; });
+ return Iter == Notes.end() ? DataExtractor() : DataExtractor(Iter->data);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
new file mode 100644
index 000000000000..12aa5f72371c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
@@ -0,0 +1,158 @@
+//===-- RegisterUtilities.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERUTILITIES_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERUTILITIES_H
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "llvm/BinaryFormat/ELF.h"
+
+namespace lldb_private {
+/// Core files PT_NOTE segment descriptor types
+
+namespace NETBSD {
+enum { NT_PROCINFO = 1, NT_AUXV = 2 };
+
+/* Size in bytes */
+enum { NT_PROCINFO_SIZE = 160 };
+
+/* Size in bytes */
+enum {
+ NT_PROCINFO_CPI_VERSION_SIZE = 4,
+ NT_PROCINFO_CPI_CPISIZE_SIZE = 4,
+ NT_PROCINFO_CPI_SIGNO_SIZE = 4,
+ NT_PROCINFO_CPI_SIGCODE_SIZE = 4,
+ NT_PROCINFO_CPI_SIGPEND_SIZE = 16,
+ NT_PROCINFO_CPI_SIGMASK_SIZE = 16,
+ NT_PROCINFO_CPI_SIGIGNORE_SIZE = 16,
+ NT_PROCINFO_CPI_SIGCATCH_SIZE = 16,
+ NT_PROCINFO_CPI_PID_SIZE = 4,
+ NT_PROCINFO_CPI_PPID_SIZE = 4,
+ NT_PROCINFO_CPI_PGRP_SIZE = 4,
+ NT_PROCINFO_CPI_SID_SIZE = 4,
+ NT_PROCINFO_CPI_RUID_SIZE = 4,
+ NT_PROCINFO_CPI_EUID_SIZE = 4,
+ NT_PROCINFO_CPI_SVUID_SIZE = 4,
+ NT_PROCINFO_CPI_RGID_SIZE = 4,
+ NT_PROCINFO_CPI_EGID_SIZE = 4,
+ NT_PROCINFO_CPI_SVGID_SIZE = 4,
+ NT_PROCINFO_CPI_NLWPS_SIZE = 4,
+ NT_PROCINFO_CPI_NAME_SIZE = 32,
+ NT_PROCINFO_CPI_SIGLWP_SIZE = 4,
+};
+
+namespace AARCH64 {
+enum { NT_REGS = 32, NT_FPREGS = 34 };
+}
+
+namespace AMD64 {
+enum { NT_REGS = 33, NT_FPREGS = 35 };
+}
+
+namespace I386 {
+enum { NT_REGS = 33, NT_FPREGS = 35 };
+}
+
+} // namespace NETBSD
+
+namespace OPENBSD {
+enum {
+ NT_PROCINFO = 10,
+ NT_AUXV = 11,
+ NT_REGS = 20,
+ NT_FPREGS = 21,
+};
+}
+
+struct CoreNote {
+ ELFNote info;
+ DataExtractor data;
+};
+
+// A structure describing how to find a register set in a core file from a given
+// OS.
+struct RegsetDesc {
+ // OS to which this entry applies to. Must not be UnknownOS.
+ llvm::Triple::OSType OS;
+
+ // Architecture to which this entry applies to. Can be UnknownArch, in which
+ // case it applies to all architectures of a given OS.
+ llvm::Triple::ArchType Arch;
+
+ // The note type under which the register set can be found.
+ uint32_t Note;
+};
+
+// Returns the register set in Notes which corresponds to the specified Triple
+// according to the list of register set descriptions in RegsetDescs. The list
+// is scanned linearly, so you can use a more specific entry (e.g. linux-i386)
+// to override a more general entry (e.g. general linux), as long as you place
+// it earlier in the list. If a register set is not found, it returns an empty
+// DataExtractor.
+DataExtractor getRegset(llvm::ArrayRef<CoreNote> Notes,
+ const llvm::Triple &Triple,
+ llvm::ArrayRef<RegsetDesc> RegsetDescs);
+
+constexpr RegsetDesc FPR_Desc[] = {
+ // FreeBSD/i386 core NT_FPREGSET is x87 FSAVE result but the XSAVE dump
+ // starts with FXSAVE struct, so use that instead if available.
+ {llvm::Triple::FreeBSD, llvm::Triple::x86, llvm::ELF::NT_X86_XSTATE},
+ {llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_FPREGSET},
+ // In a i386 core file NT_FPREGSET is present, but it's not the result
+ // of the FXSAVE instruction like in 64 bit files.
+ // The result from FXSAVE is in NT_PRXFPREG for i386 core files
+ {llvm::Triple::Linux, llvm::Triple::x86, llvm::ELF::NT_PRXFPREG},
+ {llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_FPREGSET},
+ {llvm::Triple::NetBSD, llvm::Triple::aarch64, NETBSD::AARCH64::NT_FPREGS},
+ {llvm::Triple::NetBSD, llvm::Triple::x86, NETBSD::I386::NT_FPREGS},
+ {llvm::Triple::NetBSD, llvm::Triple::x86_64, NETBSD::AMD64::NT_FPREGS},
+ {llvm::Triple::OpenBSD, llvm::Triple::UnknownArch, OPENBSD::NT_FPREGS},
+};
+
+constexpr RegsetDesc AARCH64_SVE_Desc[] = {
+ {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_SVE},
+};
+
+constexpr RegsetDesc AARCH64_SSVE_Desc[] = {
+ {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_SSVE},
+};
+
+constexpr RegsetDesc AARCH64_ZA_Desc[] = {
+ {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_ZA},
+};
+
+constexpr RegsetDesc AARCH64_ZT_Desc[] = {
+ {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_ZT},
+};
+
+constexpr RegsetDesc AARCH64_PAC_Desc[] = {
+ {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_PAC_MASK},
+};
+
+constexpr RegsetDesc AARCH64_TLS_Desc[] = {
+ {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_TLS},
+};
+
+constexpr RegsetDesc AARCH64_MTE_Desc[] = {
+ {llvm::Triple::Linux, llvm::Triple::aarch64,
+ llvm::ELF::NT_ARM_TAGGED_ADDR_CTRL},
+};
+
+constexpr RegsetDesc PPC_VMX_Desc[] = {
+ {llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},
+ {llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},
+};
+
+constexpr RegsetDesc PPC_VSX_Desc[] = {
+ {llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VSX},
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERUTILITIES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
new file mode 100644
index 000000000000..c931583cf21c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -0,0 +1,440 @@
+//===-- ThreadElfCore.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
+#ifdef LLDB_ENABLE_ALL
+#include "Plugins/Process/Utility/RegisterContextLinux_s390x.h"
+#endif // LLDB_ENABLE_ALL
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextOpenBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h"
+#include "ProcessElfCore.h"
+#include "RegisterContextLinuxCore_x86_64.h"
+#include "RegisterContextPOSIXCore_arm.h"
+#include "RegisterContextPOSIXCore_arm64.h"
+#include "RegisterContextPOSIXCore_mips64.h"
+#include "RegisterContextPOSIXCore_powerpc.h"
+#include "RegisterContextPOSIXCore_ppc64le.h"
+#include "RegisterContextPOSIXCore_riscv64.h"
+#ifdef LLDB_ENABLE_ALL
+#include "RegisterContextPOSIXCore_s390x.h"
+#endif // LLDB_ENABLE_ALL
+#include "RegisterContextPOSIXCore_x86_64.h"
+#include "ThreadElfCore.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Construct a Thread object with given data
+ThreadElfCore::ThreadElfCore(Process &process, const ThreadData &td)
+ : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(),
+ m_signo(td.signo), m_code(td.code), m_gpregset_data(td.gpregset),
+ m_notes(td.notes) {}
+
+ThreadElfCore::~ThreadElfCore() { DestroyThread(); }
+
+void ThreadElfCore::RefreshStateAfterStop() {
+ GetRegisterContext()->InvalidateIfNeeded(false);
+}
+
+RegisterContextSP ThreadElfCore::GetRegisterContext() {
+ if (!m_reg_context_sp) {
+ m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
+ }
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+ Log *log = GetLog(LLDBLog::Thread);
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+ bool is_linux = false;
+ if (concrete_frame_idx == 0) {
+ if (m_thread_reg_ctx_sp)
+ return m_thread_reg_ctx_sp;
+
+ ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get());
+ ArchSpec arch = process->GetArchitecture();
+ RegisterInfoInterface *reg_interface = nullptr;
+
+ switch (arch.GetTriple().getOS()) {
+ case llvm::Triple::FreeBSD: {
+ switch (arch.GetMachine()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
+ break;
+ case llvm::Triple::ppc:
+ reg_interface = new RegisterContextFreeBSD_powerpc32(arch);
+ break;
+ case llvm::Triple::ppc64:
+ reg_interface = new RegisterContextFreeBSD_powerpc64(arch);
+ break;
+ case llvm::Triple::mips64:
+ reg_interface = new RegisterContextFreeBSD_mips64(arch);
+ break;
+ case llvm::Triple::x86:
+ reg_interface = new RegisterContextFreeBSD_i386(arch);
+ break;
+ case llvm::Triple::x86_64:
+ reg_interface = new RegisterContextFreeBSD_x86_64(arch);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case llvm::Triple::NetBSD: {
+ switch (arch.GetMachine()) {
+ case llvm::Triple::aarch64:
+ break;
+ case llvm::Triple::x86:
+ reg_interface = new RegisterContextNetBSD_i386(arch);
+ break;
+ case llvm::Triple::x86_64:
+ reg_interface = new RegisterContextNetBSD_x86_64(arch);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case llvm::Triple::Linux: {
+ is_linux = true;
+ switch (arch.GetMachine()) {
+ case llvm::Triple::aarch64:
+ break;
+ case llvm::Triple::ppc64le:
+ reg_interface = new RegisterInfoPOSIX_ppc64le(arch);
+ break;
+#ifdef LLDB_ENABLE_ALL
+ case llvm::Triple::systemz:
+ reg_interface = new RegisterContextLinux_s390x(arch);
+ break;
+#endif // LLDB_ENABLE_ALL
+ case llvm::Triple::x86:
+ reg_interface = new RegisterContextLinux_i386(arch);
+ break;
+ case llvm::Triple::x86_64:
+ reg_interface = new RegisterContextLinux_x86_64(arch);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case llvm::Triple::OpenBSD: {
+ switch (arch.GetMachine()) {
+ case llvm::Triple::aarch64:
+ break;
+ case llvm::Triple::x86:
+ reg_interface = new RegisterContextOpenBSD_i386(arch);
+ break;
+ case llvm::Triple::x86_64:
+ reg_interface = new RegisterContextOpenBSD_x86_64(arch);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64 &&
+ arch.GetMachine() != llvm::Triple::arm &&
+ arch.GetMachine() != llvm::Triple::riscv64) {
+ LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported",
+ __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS());
+ assert(false && "Architecture or OS not supported");
+ }
+
+ switch (arch.GetMachine()) {
+ case llvm::Triple::aarch64:
+ m_thread_reg_ctx_sp = RegisterContextCorePOSIX_arm64::Create(
+ *this, arch, m_gpregset_data, m_notes);
+ break;
+ case llvm::Triple::arm:
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm>(
+ *this, std::make_unique<RegisterInfoPOSIX_arm>(arch), m_gpregset_data,
+ m_notes);
+ break;
+ case llvm::Triple::riscv64:
+ m_thread_reg_ctx_sp = RegisterContextCorePOSIX_riscv64::Create(
+ *this, arch, m_gpregset_data, m_notes);
+ break;
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips:
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>(
+ *this, reg_interface, m_gpregset_data, m_notes);
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>(
+ *this, reg_interface, m_gpregset_data, m_notes);
+ break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_powerpc>(
+ *this, reg_interface, m_gpregset_data, m_notes);
+ break;
+ case llvm::Triple::ppc64le:
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_ppc64le>(
+ *this, reg_interface, m_gpregset_data, m_notes);
+ break;
+#ifdef LLDB_ENABLE_ALL
+ case llvm::Triple::systemz:
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_s390x>(
+ *this, reg_interface, m_gpregset_data, m_notes);
+ break;
+#endif // LLDB_ENABLE_ALL
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (is_linux) {
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextLinuxCore_x86_64>(
+ *this, reg_interface, m_gpregset_data, m_notes);
+ } else {
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_x86_64>(
+ *this, reg_interface, m_gpregset_data, m_notes);
+ }
+ break;
+ default:
+ break;
+ }
+
+ reg_ctx_sp = m_thread_reg_ctx_sp;
+ } else {
+ reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool ThreadElfCore::CalculateStopInfo() {
+ ProcessSP process_sp(GetProcess());
+ if (!process_sp)
+ return false;
+
+ SetStopInfo(StopInfo::CreateStopReasonWithSignal(
+ *this, m_signo, /*description=*/nullptr, m_code));
+ return true;
+}
+
+// Parse PRSTATUS from NOTE entry
+ELFLinuxPrStatus::ELFLinuxPrStatus() {
+ memset(this, 0, sizeof(ELFLinuxPrStatus));
+}
+
+size_t ELFLinuxPrStatus::GetSize(const lldb_private::ArchSpec &arch) {
+ constexpr size_t mips_linux_pr_status_size_o32 = 96;
+ constexpr size_t mips_linux_pr_status_size_n32 = 72;
+ constexpr size_t num_ptr_size_members = 10;
+ if (arch.IsMIPS()) {
+ std::string abi = arch.GetTargetABI();
+ assert(!abi.empty() && "ABI is not set");
+ if (!abi.compare("n64"))
+ return sizeof(ELFLinuxPrStatus);
+ else if (!abi.compare("o32"))
+ return mips_linux_pr_status_size_o32;
+ // N32 ABI
+ return mips_linux_pr_status_size_n32;
+ }
+ switch (arch.GetCore()) {
+ case lldb_private::ArchSpec::eCore_x86_32_i386:
+ case lldb_private::ArchSpec::eCore_x86_32_i486:
+ return 72;
+ default:
+ if (arch.GetAddressByteSize() == 8)
+ return sizeof(ELFLinuxPrStatus);
+ else
+ return sizeof(ELFLinuxPrStatus) - num_ptr_size_members * 4;
+ }
+}
+
+Status ELFLinuxPrStatus::Parse(const DataExtractor &data,
+ const ArchSpec &arch) {
+ Status error;
+ if (GetSize(arch) > data.GetByteSize()) {
+ error.SetErrorStringWithFormat(
+ "NT_PRSTATUS size should be %zu, but the remaining bytes are: %" PRIu64,
+ GetSize(arch), data.GetByteSize());
+ return error;
+ }
+
+ // Read field by field to correctly account for endianess of both the core
+ // dump and the platform running lldb.
+ offset_t offset = 0;
+ si_signo = data.GetU32(&offset);
+ si_code = data.GetU32(&offset);
+ si_errno = data.GetU32(&offset);
+
+ pr_cursig = data.GetU16(&offset);
+ offset += 2; // pad
+
+ pr_sigpend = data.GetAddress(&offset);
+ pr_sighold = data.GetAddress(&offset);
+
+ pr_pid = data.GetU32(&offset);
+ pr_ppid = data.GetU32(&offset);
+ pr_pgrp = data.GetU32(&offset);
+ pr_sid = data.GetU32(&offset);
+
+ pr_utime.tv_sec = data.GetAddress(&offset);
+ pr_utime.tv_usec = data.GetAddress(&offset);
+
+ pr_stime.tv_sec = data.GetAddress(&offset);
+ pr_stime.tv_usec = data.GetAddress(&offset);
+
+ pr_cutime.tv_sec = data.GetAddress(&offset);
+ pr_cutime.tv_usec = data.GetAddress(&offset);
+
+ pr_cstime.tv_sec = data.GetAddress(&offset);
+ pr_cstime.tv_usec = data.GetAddress(&offset);
+
+ return error;
+}
+
+// Parse PRPSINFO from NOTE entry
+ELFLinuxPrPsInfo::ELFLinuxPrPsInfo() {
+ memset(this, 0, sizeof(ELFLinuxPrPsInfo));
+}
+
+size_t ELFLinuxPrPsInfo::GetSize(const lldb_private::ArchSpec &arch) {
+ constexpr size_t mips_linux_pr_psinfo_size_o32_n32 = 128;
+ if (arch.IsMIPS()) {
+ uint8_t address_byte_size = arch.GetAddressByteSize();
+ if (address_byte_size == 8)
+ return sizeof(ELFLinuxPrPsInfo);
+ return mips_linux_pr_psinfo_size_o32_n32;
+ }
+
+ switch (arch.GetCore()) {
+ case lldb_private::ArchSpec::eCore_s390x_generic:
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return sizeof(ELFLinuxPrPsInfo);
+ case lldb_private::ArchSpec::eCore_x86_32_i386:
+ case lldb_private::ArchSpec::eCore_x86_32_i486:
+ return 124;
+ default:
+ return 0;
+ }
+}
+
+Status ELFLinuxPrPsInfo::Parse(const DataExtractor &data,
+ const ArchSpec &arch) {
+ Status error;
+ ByteOrder byteorder = data.GetByteOrder();
+ if (GetSize(arch) > data.GetByteSize()) {
+ error.SetErrorStringWithFormat(
+ "NT_PRPSINFO size should be %zu, but the remaining bytes are: %" PRIu64,
+ GetSize(arch), data.GetByteSize());
+ return error;
+ }
+ size_t size = 0;
+ offset_t offset = 0;
+
+ pr_state = data.GetU8(&offset);
+ pr_sname = data.GetU8(&offset);
+ pr_zomb = data.GetU8(&offset);
+ pr_nice = data.GetU8(&offset);
+ if (data.GetAddressByteSize() == 8) {
+ // Word align the next field on 64 bit.
+ offset += 4;
+ }
+
+ pr_flag = data.GetAddress(&offset);
+
+ if (arch.IsMIPS()) {
+ // The pr_uid and pr_gid is always 32 bit irrespective of platforms
+ pr_uid = data.GetU32(&offset);
+ pr_gid = data.GetU32(&offset);
+ } else {
+ // 16 bit on 32 bit platforms, 32 bit on 64 bit platforms
+ pr_uid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1);
+ pr_gid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1);
+ }
+
+ pr_pid = data.GetU32(&offset);
+ pr_ppid = data.GetU32(&offset);
+ pr_pgrp = data.GetU32(&offset);
+ pr_sid = data.GetU32(&offset);
+
+ size = 16;
+ data.ExtractBytes(offset, size, byteorder, pr_fname);
+ offset += size;
+
+ size = 80;
+ data.ExtractBytes(offset, size, byteorder, pr_psargs);
+ offset += size;
+
+ return error;
+}
+
+// Parse SIGINFO from NOTE entry
+ELFLinuxSigInfo::ELFLinuxSigInfo() { memset(this, 0, sizeof(ELFLinuxSigInfo)); }
+
+size_t ELFLinuxSigInfo::GetSize(const lldb_private::ArchSpec &arch) {
+ if (arch.IsMIPS())
+ return sizeof(ELFLinuxSigInfo);
+ switch (arch.GetCore()) {
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return sizeof(ELFLinuxSigInfo);
+ case lldb_private::ArchSpec::eCore_s390x_generic:
+ case lldb_private::ArchSpec::eCore_x86_32_i386:
+ case lldb_private::ArchSpec::eCore_x86_32_i486:
+ return 12;
+ default:
+ return 0;
+ }
+}
+
+Status ELFLinuxSigInfo::Parse(const DataExtractor &data, const ArchSpec &arch) {
+ Status error;
+ if (GetSize(arch) > data.GetByteSize()) {
+ error.SetErrorStringWithFormat(
+ "NT_SIGINFO size should be %zu, but the remaining bytes are: %" PRIu64,
+ GetSize(arch), data.GetByteSize());
+ return error;
+ }
+
+ // Parsing from a 32 bit ELF core file, and populating/reusing the structure
+ // properly, because the struct is for the 64 bit version
+ offset_t offset = 0;
+ si_signo = data.GetU32(&offset);
+ si_errno = data.GetU32(&offset);
+ si_code = data.GetU32(&offset);
+
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
new file mode 100644
index 000000000000..2f3ed2a01779
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
@@ -0,0 +1,178 @@
+//===-- ThreadElfCore.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_THREADELFCORE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_THREADELFCORE_H
+
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "llvm/ADT/DenseMap.h"
+#include <string>
+
+struct compat_timeval {
+ alignas(8) uint64_t tv_sec;
+ alignas(8) uint64_t tv_usec;
+};
+
+// PRSTATUS structure's size differs based on architecture.
+// This is the layout in the x86-64 arch.
+// In the i386 case we parse it manually and fill it again
+// in the same structure
+// The gp registers are also a part of this struct, but they are handled
+// separately
+
+#undef si_signo
+#undef si_code
+#undef si_errno
+
+struct ELFLinuxPrStatus {
+ int32_t si_signo;
+ int32_t si_code;
+ int32_t si_errno;
+
+ int16_t pr_cursig;
+
+ alignas(8) uint64_t pr_sigpend;
+ alignas(8) uint64_t pr_sighold;
+
+ uint32_t pr_pid;
+ uint32_t pr_ppid;
+ uint32_t pr_pgrp;
+ uint32_t pr_sid;
+
+ compat_timeval pr_utime;
+ compat_timeval pr_stime;
+ compat_timeval pr_cutime;
+ compat_timeval pr_cstime;
+
+ ELFLinuxPrStatus();
+
+ lldb_private::Status Parse(const lldb_private::DataExtractor &data,
+ const lldb_private::ArchSpec &arch);
+
+ // Return the bytesize of the structure
+ // 64 bit - just sizeof
+ // 32 bit - hardcoded because we are reusing the struct, but some of the
+ // members are smaller -
+ // so the layout is not the same
+ static size_t GetSize(const lldb_private::ArchSpec &arch);
+};
+
+static_assert(sizeof(ELFLinuxPrStatus) == 112,
+ "sizeof ELFLinuxPrStatus is not correct!");
+
+struct ELFLinuxSigInfo {
+ int32_t si_signo;
+ int32_t si_code;
+ int32_t si_errno;
+
+ ELFLinuxSigInfo();
+
+ lldb_private::Status Parse(const lldb_private::DataExtractor &data,
+ const lldb_private::ArchSpec &arch);
+
+ // Return the bytesize of the structure
+ // 64 bit - just sizeof
+ // 32 bit - hardcoded because we are reusing the struct, but some of the
+ // members are smaller -
+ // so the layout is not the same
+ static size_t GetSize(const lldb_private::ArchSpec &arch);
+};
+
+static_assert(sizeof(ELFLinuxSigInfo) == 12,
+ "sizeof ELFLinuxSigInfo is not correct!");
+
+// PRPSINFO structure's size differs based on architecture.
+// This is the layout in the x86-64 arch case.
+// In the i386 case we parse it manually and fill it again
+// in the same structure
+struct ELFLinuxPrPsInfo {
+ char pr_state;
+ char pr_sname;
+ char pr_zomb;
+ char pr_nice;
+ alignas(8) uint64_t pr_flag;
+ uint32_t pr_uid;
+ uint32_t pr_gid;
+ int32_t pr_pid;
+ int32_t pr_ppid;
+ int32_t pr_pgrp;
+ int32_t pr_sid;
+ char pr_fname[16];
+ char pr_psargs[80];
+
+ ELFLinuxPrPsInfo();
+
+ lldb_private::Status Parse(const lldb_private::DataExtractor &data,
+ const lldb_private::ArchSpec &arch);
+
+ // Return the bytesize of the structure
+ // 64 bit - just sizeof
+ // 32 bit - hardcoded because we are reusing the struct, but some of the
+ // members are smaller -
+ // so the layout is not the same
+ static size_t GetSize(const lldb_private::ArchSpec &arch);
+};
+
+static_assert(sizeof(ELFLinuxPrPsInfo) == 136,
+ "sizeof ELFLinuxPrPsInfo is not correct!");
+
+struct ThreadData {
+ lldb_private::DataExtractor gpregset;
+ std::vector<lldb_private::CoreNote> notes;
+ lldb::tid_t tid;
+ int signo = 0;
+ int code = 0;
+ int prstatus_sig = 0;
+ std::string name;
+};
+
+class ThreadElfCore : public lldb_private::Thread {
+public:
+ ThreadElfCore(lldb_private::Process &process, const ThreadData &td);
+
+ ~ThreadElfCore() override;
+
+ void RefreshStateAfterStop() override;
+
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+ static bool ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; }
+
+ const char *GetName() override {
+ if (m_thread_name.empty())
+ return nullptr;
+ return m_thread_name.c_str();
+ }
+
+ void SetName(const char *name) override {
+ if (name && name[0])
+ m_thread_name.assign(name);
+ else
+ m_thread_name.clear();
+ }
+
+protected:
+ // Member variables.
+ std::string m_thread_name;
+ lldb::RegisterContextSP m_thread_reg_ctx_sp;
+
+ int m_signo;
+ int m_code;
+
+ lldb_private::DataExtractor m_gpregset_data;
+ std::vector<lldb_private::CoreNote> m_notes;
+
+ bool CalculateStopInfo() override;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_THREADELFCORE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp
new file mode 100644
index 000000000000..394b62559da7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp
@@ -0,0 +1,404 @@
+//===-- GDBRemoteClientBase.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteClientBase.h"
+
+#include "llvm/ADT/StringExtras.h"
+
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+#include "ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace std::chrono;
+
+// When we've sent a continue packet and are waiting for the target to stop,
+// we wake up the wait with this interval to make sure the stub hasn't gone
+// away while we were waiting.
+static const seconds kWakeupInterval(5);
+
+/////////////////////////
+// GDBRemoteClientBase //
+/////////////////////////
+
+GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default;
+
+GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name)
+ : GDBRemoteCommunication(), Broadcaster(nullptr, comm_name),
+ m_async_count(0), m_is_running(false), m_should_stop(false) {}
+
+StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
+ ContinueDelegate &delegate, const UnixSignals &signals,
+ llvm::StringRef payload, std::chrono::seconds interrupt_timeout,
+ StringExtractorGDBRemote &response) {
+ Log *log = GetLog(GDBRLog::Process);
+ response.Clear();
+
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_continue_packet = std::string(payload);
+ m_should_stop = false;
+ }
+ ContinueLock cont_lock(*this);
+ if (!cont_lock)
+ return eStateInvalid;
+ OnRunPacketSent(true);
+ // The main ReadPacket loop wakes up at computed_timeout intervals, just to
+ // check that the connection hasn't dropped. When we wake up we also check
+ // whether there is an interrupt request that has reached its endpoint.
+ // If we want a shorter interrupt timeout that kWakeupInterval, we need to
+ // choose the shorter interval for the wake up as well.
+ std::chrono::seconds computed_timeout = std::min(interrupt_timeout,
+ kWakeupInterval);
+ for (;;) {
+ PacketResult read_result = ReadPacket(response, computed_timeout, false);
+ // Reset the computed_timeout to the default value in case we are going
+ // round again.
+ computed_timeout = std::min(interrupt_timeout, kWakeupInterval);
+ switch (read_result) {
+ case PacketResult::ErrorReplyTimeout: {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (m_async_count == 0) {
+ continue;
+ }
+ auto cur_time = steady_clock::now();
+ if (cur_time >= m_interrupt_endpoint)
+ return eStateInvalid;
+ else {
+ // We woke up and found an interrupt is in flight, but we haven't
+ // exceeded the interrupt wait time. So reset the wait time to the
+ // time left till the interrupt timeout. But don't wait longer
+ // than our wakeup timeout.
+ auto new_wait = m_interrupt_endpoint - cur_time;
+ computed_timeout = std::min(kWakeupInterval,
+ std::chrono::duration_cast<std::chrono::seconds>(new_wait));
+ continue;
+ }
+ break;
+ }
+ case PacketResult::Success:
+ break;
+ default:
+ LLDB_LOGF(log, "GDBRemoteClientBase::%s () ReadPacket(...) => false",
+ __FUNCTION__);
+ return eStateInvalid;
+ }
+ if (response.Empty())
+ return eStateInvalid;
+
+ const char stop_type = response.GetChar();
+ LLDB_LOGF(log, "GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
+ response.GetStringRef().data());
+
+ switch (stop_type) {
+ case 'W':
+ case 'X':
+ return eStateExited;
+ case 'E':
+ // ERROR
+ return eStateInvalid;
+ default:
+ LLDB_LOGF(log, "GDBRemoteClientBase::%s () unrecognized async packet",
+ __FUNCTION__);
+ return eStateInvalid;
+ case 'O': {
+ std::string inferior_stdout;
+ response.GetHexByteString(inferior_stdout);
+ delegate.HandleAsyncStdout(inferior_stdout);
+ break;
+ }
+ case 'A':
+ delegate.HandleAsyncMisc(
+ llvm::StringRef(response.GetStringRef()).substr(1));
+ break;
+ case 'J':
+ delegate.HandleAsyncStructuredDataPacket(response.GetStringRef());
+ break;
+ case 'T':
+ case 'S':
+ // Do this with the continue lock held.
+ const bool should_stop = ShouldStop(signals, response);
+ response.SetFilePos(0);
+
+ // The packet we should resume with. In the future we should check our
+ // thread list and "do the right thing" for new threads that show up
+ // while we stop and run async packets. Setting the packet to 'c' to
+ // continue all threads is the right thing to do 99.99% of the time
+ // because if a thread was single stepping, and we sent an interrupt, we
+ // will notice above that we didn't stop due to an interrupt but stopped
+ // due to stepping and we would _not_ continue. This packet may get
+ // modified by the async actions (e.g. to send a signal).
+ m_continue_packet = 'c';
+ cont_lock.unlock();
+
+ delegate.HandleStopReply();
+ if (should_stop)
+ return eStateStopped;
+
+ switch (cont_lock.lock()) {
+ case ContinueLock::LockResult::Success:
+ break;
+ case ContinueLock::LockResult::Failed:
+ return eStateInvalid;
+ case ContinueLock::LockResult::Cancelled:
+ return eStateStopped;
+ }
+ OnRunPacketSent(false);
+ break;
+ }
+ }
+}
+
+bool GDBRemoteClientBase::SendAsyncSignal(
+ int signo, std::chrono::seconds interrupt_timeout) {
+ Lock lock(*this, interrupt_timeout);
+ if (!lock || !lock.DidInterrupt())
+ return false;
+
+ m_continue_packet = 'C';
+ m_continue_packet += llvm::hexdigit((signo / 16) % 16);
+ m_continue_packet += llvm::hexdigit(signo % 16);
+ return true;
+}
+
+bool GDBRemoteClientBase::Interrupt(std::chrono::seconds interrupt_timeout) {
+ Lock lock(*this, interrupt_timeout);
+ if (!lock.DidInterrupt())
+ return false;
+ m_should_stop = true;
+ return true;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteClientBase::SendPacketAndWaitForResponse(
+ llvm::StringRef payload, StringExtractorGDBRemote &response,
+ std::chrono::seconds interrupt_timeout) {
+ Lock lock(*this, interrupt_timeout);
+ if (!lock) {
+ if (Log *log = GetLog(GDBRLog::Process))
+ LLDB_LOGF(log,
+ "GDBRemoteClientBase::%s failed to get mutex, not sending "
+ "packet '%.*s'",
+ __FUNCTION__, int(payload.size()), payload.data());
+ return PacketResult::ErrorSendFailed;
+ }
+
+ return SendPacketAndWaitForResponseNoLock(payload, response);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteClientBase::ReadPacketWithOutputSupport(
+ StringExtractorGDBRemote &response, Timeout<std::micro> timeout,
+ bool sync_on_timeout,
+ llvm::function_ref<void(llvm::StringRef)> output_callback) {
+ auto result = ReadPacket(response, timeout, sync_on_timeout);
+ while (result == PacketResult::Success && response.IsNormalResponse() &&
+ response.PeekChar() == 'O') {
+ response.GetChar();
+ std::string output;
+ if (response.GetHexByteString(output))
+ output_callback(output);
+ result = ReadPacket(response, timeout, sync_on_timeout);
+ }
+ return result;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport(
+ llvm::StringRef payload, StringExtractorGDBRemote &response,
+ std::chrono::seconds interrupt_timeout,
+ llvm::function_ref<void(llvm::StringRef)> output_callback) {
+ Lock lock(*this, interrupt_timeout);
+ if (!lock) {
+ if (Log *log = GetLog(GDBRLog::Process))
+ LLDB_LOGF(log,
+ "GDBRemoteClientBase::%s failed to get mutex, not sending "
+ "packet '%.*s'",
+ __FUNCTION__, int(payload.size()), payload.data());
+ return PacketResult::ErrorSendFailed;
+ }
+
+ PacketResult packet_result = SendPacketNoLock(payload);
+ if (packet_result != PacketResult::Success)
+ return packet_result;
+
+ return ReadPacketWithOutputSupport(response, GetPacketTimeout(), true,
+ output_callback);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(
+ llvm::StringRef payload, StringExtractorGDBRemote &response) {
+ PacketResult packet_result = SendPacketNoLock(payload);
+ if (packet_result != PacketResult::Success)
+ return packet_result;
+
+ const size_t max_response_retries = 3;
+ for (size_t i = 0; i < max_response_retries; ++i) {
+ packet_result = ReadPacket(response, GetPacketTimeout(), true);
+ // Make sure we received a response
+ if (packet_result != PacketResult::Success)
+ return packet_result;
+ // Make sure our response is valid for the payload that was sent
+ if (response.ValidateResponse())
+ return packet_result;
+ // Response says it wasn't valid
+ Log *log = GetLog(GDBRLog::Packets);
+ LLDB_LOGF(
+ log,
+ "error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
+ int(payload.size()), payload.data(), response.GetStringRef().data(),
+ (i == (max_response_retries - 1))
+ ? "using invalid response and giving up"
+ : "ignoring response and waiting for another");
+ }
+ return packet_result;
+}
+
+bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals,
+ StringExtractorGDBRemote &response) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ if (m_async_count == 0)
+ return true; // We were not interrupted. The process stopped on its own.
+
+ // Older debugserver stubs (before April 2016) can return two stop-reply
+ // packets in response to a ^C packet. Additionally, all debugservers still
+ // return two stop replies if the inferior stops due to some other reason
+ // before the remote stub manages to interrupt it. We need to wait for this
+ // additional packet to make sure the packet sequence does not get skewed.
+ StringExtractorGDBRemote extra_stop_reply_packet;
+ ReadPacket(extra_stop_reply_packet, milliseconds(100), false);
+
+ // Interrupting is typically done using SIGSTOP or SIGINT, so if the process
+ // stops with some other signal, we definitely want to stop.
+ const uint8_t signo = response.GetHexU8(UINT8_MAX);
+ if (signo != signals.GetSignalNumberFromName("SIGSTOP") &&
+ signo != signals.GetSignalNumberFromName("SIGINT"))
+ return true;
+
+ // We probably only stopped to perform some async processing, so continue
+ // after that is done.
+ // TODO: This is not 100% correct, as the process may have been stopped with
+ // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will
+ // normally cause a stop, but if it's done concurrently with a async
+ // interrupt, that stop will get eaten (llvm.org/pr20231).
+ return false;
+}
+
+void GDBRemoteClientBase::OnRunPacketSent(bool first) {
+ if (first)
+ BroadcastEvent(eBroadcastBitRunPacketSent, nullptr);
+}
+
+///////////////////////////////////////
+// GDBRemoteClientBase::ContinueLock //
+///////////////////////////////////////
+
+GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm)
+ : m_comm(comm), m_acquired(false) {
+ lock();
+}
+
+GDBRemoteClientBase::ContinueLock::~ContinueLock() {
+ if (m_acquired)
+ unlock();
+}
+
+void GDBRemoteClientBase::ContinueLock::unlock() {
+ lldbassert(m_acquired);
+ {
+ std::unique_lock<std::mutex> lock(m_comm.m_mutex);
+ m_comm.m_is_running = false;
+ }
+ m_comm.m_cv.notify_all();
+ m_acquired = false;
+}
+
+GDBRemoteClientBase::ContinueLock::LockResult
+GDBRemoteClientBase::ContinueLock::lock() {
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() resuming with %s",
+ __FUNCTION__, m_comm.m_continue_packet.c_str());
+
+ lldbassert(!m_acquired);
+ std::unique_lock<std::mutex> lock(m_comm.m_mutex);
+ m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; });
+ if (m_comm.m_should_stop) {
+ m_comm.m_should_stop = false;
+ LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() cancelled",
+ __FUNCTION__);
+ return LockResult::Cancelled;
+ }
+ if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) !=
+ PacketResult::Success)
+ return LockResult::Failed;
+
+ lldbassert(!m_comm.m_is_running);
+ m_comm.m_is_running = true;
+ m_acquired = true;
+ return LockResult::Success;
+}
+
+///////////////////////////////
+// GDBRemoteClientBase::Lock //
+///////////////////////////////
+
+GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm,
+ std::chrono::seconds interrupt_timeout)
+ : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm),
+ m_interrupt_timeout(interrupt_timeout), m_acquired(false),
+ m_did_interrupt(false) {
+ SyncWithContinueThread();
+ if (m_acquired)
+ m_async_lock.lock();
+}
+
+void GDBRemoteClientBase::Lock::SyncWithContinueThread() {
+ Log *log = GetLog(GDBRLog::Process|GDBRLog::Packets);
+ std::unique_lock<std::mutex> lock(m_comm.m_mutex);
+ if (m_comm.m_is_running && m_interrupt_timeout == std::chrono::seconds(0))
+ return; // We were asked to avoid interrupting the sender. Lock is not
+ // acquired.
+
+ ++m_comm.m_async_count;
+ if (m_comm.m_is_running) {
+ if (m_comm.m_async_count == 1) {
+ // The sender has sent the continue packet and we are the first async
+ // packet. Let's interrupt it.
+ const char ctrl_c = '\x03';
+ ConnectionStatus status = eConnectionStatusSuccess;
+ size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, nullptr);
+ if (bytes_written == 0) {
+ --m_comm.m_async_count;
+ LLDB_LOGF(log, "GDBRemoteClientBase::Lock::Lock failed to send "
+ "interrupt packet");
+ return;
+ }
+ m_comm.m_interrupt_endpoint = steady_clock::now() + m_interrupt_timeout;
+ if (log)
+ log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
+ }
+ m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; });
+ m_did_interrupt = true;
+ }
+ m_acquired = true;
+}
+
+GDBRemoteClientBase::Lock::~Lock() {
+ if (!m_acquired)
+ return;
+ {
+ std::unique_lock<std::mutex> lock(m_comm.m_mutex);
+ --m_comm.m_async_count;
+ }
+ m_comm.m_cv.notify_one();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h
new file mode 100644
index 000000000000..b47fee76a2ab
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h
@@ -0,0 +1,175 @@
+//===-- GDBRemoteClientBase.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H
+
+#include "GDBRemoteCommunication.h"
+
+#include <condition_variable>
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class GDBRemoteClientBase : public GDBRemoteCommunication, public Broadcaster {
+public:
+ enum {
+ eBroadcastBitRunPacketSent = (1u << 0),
+ };
+
+ struct ContinueDelegate {
+ virtual ~ContinueDelegate();
+ virtual void HandleAsyncStdout(llvm::StringRef out) = 0;
+ virtual void HandleAsyncMisc(llvm::StringRef data) = 0;
+ virtual void HandleStopReply() = 0;
+
+ /// Process asynchronously-received structured data.
+ ///
+ /// \param[in] data
+ /// The complete data packet, expected to start with JSON-async.
+ virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0;
+ };
+
+ GDBRemoteClientBase(const char *comm_name);
+
+ bool SendAsyncSignal(int signo, std::chrono::seconds interrupt_timeout);
+
+ bool Interrupt(std::chrono::seconds interrupt_timeout);
+
+ lldb::StateType SendContinuePacketAndWaitForResponse(
+ ContinueDelegate &delegate, const UnixSignals &signals,
+ llvm::StringRef payload, std::chrono::seconds interrupt_timeout,
+ StringExtractorGDBRemote &response);
+
+ // If interrupt_timeout == 0 seconds, don't interrupt the target.
+ // Only send the packet if the target is stopped.
+ // If you want to use this mode, use the fact that the timeout is defaulted
+ // so it's clear from the call-site that you are using no-interrupt.
+ // If it is non-zero, interrupt the target if it is running, and
+ // send the packet.
+ // It the target doesn't respond within the given timeout, it returns
+ // ErrorReplyTimeout.
+ PacketResult SendPacketAndWaitForResponse(
+ llvm::StringRef payload, StringExtractorGDBRemote &response,
+ std::chrono::seconds interrupt_timeout = std::chrono::seconds(0));
+
+ PacketResult ReadPacketWithOutputSupport(
+ StringExtractorGDBRemote &response, Timeout<std::micro> timeout,
+ bool sync_on_timeout,
+ llvm::function_ref<void(llvm::StringRef)> output_callback);
+
+ PacketResult SendPacketAndReceiveResponseWithOutputSupport(
+ llvm::StringRef payload, StringExtractorGDBRemote &response,
+ std::chrono::seconds interrupt_timeout,
+ llvm::function_ref<void(llvm::StringRef)> output_callback);
+
+ class Lock {
+ public:
+ // If interrupt_timeout == 0 seconds, only take the lock if the target is
+ // not running. If using this option, use the fact that the
+ // interrupt_timeout is defaulted so it will be obvious at the call site
+ // that you are choosing this mode. If it is non-zero, interrupt the target
+ // if it is running, waiting for the given timeout for the interrupt to
+ // succeed.
+ Lock(GDBRemoteClientBase &comm,
+ std::chrono::seconds interrupt_timeout = std::chrono::seconds(0));
+ ~Lock();
+
+ explicit operator bool() { return m_acquired; }
+
+ // Whether we had to interrupt the continue thread to acquire the
+ // connection.
+ bool DidInterrupt() const { return m_did_interrupt; }
+
+ private:
+ std::unique_lock<std::recursive_mutex> m_async_lock;
+ GDBRemoteClientBase &m_comm;
+ std::chrono::seconds m_interrupt_timeout;
+ bool m_acquired;
+ bool m_did_interrupt;
+
+ void SyncWithContinueThread();
+ };
+
+protected:
+ PacketResult
+ SendPacketAndWaitForResponseNoLock(llvm::StringRef payload,
+ StringExtractorGDBRemote &response);
+
+ virtual void OnRunPacketSent(bool first);
+
+private:
+ /// Variables handling synchronization between the Continue thread and any
+ /// other threads wishing to send packets over the connection. Either the
+ /// continue thread has control over the connection (m_is_running == true) or
+ /// the connection is free for an arbitrary number of other senders to take
+ /// which indicate their interest by incrementing m_async_count.
+ ///
+ /// Semantics of individual states:
+ ///
+ /// - m_continue_packet == false, m_async_count == 0:
+ /// connection is free
+ /// - m_continue_packet == true, m_async_count == 0:
+ /// only continue thread is present
+ /// - m_continue_packet == true, m_async_count > 0:
+ /// continue thread has control, async threads should interrupt it and wait
+ /// for it to set m_continue_packet to false
+ /// - m_continue_packet == false, m_async_count > 0:
+ /// async threads have control, continue thread needs to wait for them to
+ /// finish (m_async_count goes down to 0).
+ /// @{
+ std::mutex m_mutex;
+ std::condition_variable m_cv;
+
+ /// Packet with which to resume after an async interrupt. Can be changed by
+ /// an async thread e.g. to inject a signal.
+ std::string m_continue_packet;
+
+ /// When was the interrupt packet sent. Used to make sure we time out if the
+ /// stub does not respond to interrupt requests.
+ std::chrono::time_point<std::chrono::steady_clock> m_interrupt_endpoint;
+
+ /// Number of threads interested in sending.
+ uint32_t m_async_count;
+
+ /// Whether the continue thread has control.
+ bool m_is_running;
+
+ /// Whether we should resume after a stop.
+ bool m_should_stop;
+ /// @}
+
+ /// This handles the synchronization between individual async threads. For
+ /// now they just use a simple mutex.
+ std::recursive_mutex m_async_mutex;
+
+ bool ShouldStop(const UnixSignals &signals,
+ StringExtractorGDBRemote &response);
+
+ class ContinueLock {
+ public:
+ enum class LockResult { Success, Cancelled, Failed };
+
+ explicit ContinueLock(GDBRemoteClientBase &comm);
+ ~ContinueLock();
+ explicit operator bool() { return m_acquired; }
+
+ LockResult lock();
+
+ void unlock();
+
+ private:
+ GDBRemoteClientBase &m_comm;
+ bool m_acquired;
+ };
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
new file mode 100644
index 000000000000..187370eb36ca
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -0,0 +1,1320 @@
+//===-- GDBRemoteCommunication.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteCommunication.h"
+
+#include <climits>
+#include <cstring>
+#include <future>
+#include <sys/stat.h>
+
+#include "lldb/Host/Config.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/Pipe.h"
+#include "lldb/Host/ProcessLaunchInfo.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Utility/Event.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#include "ProcessGDBRemoteLog.h"
+
+#if defined(__APPLE__)
+#define DEBUGSERVER_BASENAME "debugserver"
+#elif defined(_WIN32)
+#define DEBUGSERVER_BASENAME "lldb-server.exe"
+#else
+#define DEBUGSERVER_BASENAME "lldb-server"
+#endif
+
+#if defined(HAVE_LIBCOMPRESSION)
+#include <compression.h>
+#endif
+
+#if LLVM_ENABLE_ZLIB
+#include <zlib.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+// GDBRemoteCommunication constructor
+GDBRemoteCommunication::GDBRemoteCommunication()
+ : Communication(),
+#ifdef LLDB_CONFIGURATION_DEBUG
+ m_packet_timeout(1000),
+#else
+ m_packet_timeout(1),
+#endif
+ m_echo_number(0), m_supports_qEcho(eLazyBoolCalculate), m_history(512),
+ m_send_acks(true), m_is_platform(false),
+ m_compression_type(CompressionType::None), m_listen_url() {
+}
+
+// Destructor
+GDBRemoteCommunication::~GDBRemoteCommunication() {
+ if (IsConnected()) {
+ Disconnect();
+ }
+
+#if defined(HAVE_LIBCOMPRESSION)
+ if (m_decompression_scratch)
+ free (m_decompression_scratch);
+#endif
+}
+
+char GDBRemoteCommunication::CalculcateChecksum(llvm::StringRef payload) {
+ int checksum = 0;
+
+ for (char c : payload)
+ checksum += c;
+
+ return checksum & 255;
+}
+
+size_t GDBRemoteCommunication::SendAck() {
+ Log *log = GetLog(GDBRLog::Packets);
+ ConnectionStatus status = eConnectionStatusSuccess;
+ char ch = '+';
+ const size_t bytes_written = WriteAll(&ch, 1, status, nullptr);
+ LLDB_LOGF(log, "<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch);
+ m_history.AddPacket(ch, GDBRemotePacket::ePacketTypeSend, bytes_written);
+ return bytes_written;
+}
+
+size_t GDBRemoteCommunication::SendNack() {
+ Log *log = GetLog(GDBRLog::Packets);
+ ConnectionStatus status = eConnectionStatusSuccess;
+ char ch = '-';
+ const size_t bytes_written = WriteAll(&ch, 1, status, nullptr);
+ LLDB_LOGF(log, "<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch);
+ m_history.AddPacket(ch, GDBRemotePacket::ePacketTypeSend, bytes_written);
+ return bytes_written;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) {
+ StreamString packet(0, 4, eByteOrderBig);
+ packet.PutChar('$');
+ packet.Write(payload.data(), payload.size());
+ packet.PutChar('#');
+ packet.PutHex8(CalculcateChecksum(payload));
+ std::string packet_str = std::string(packet.GetString());
+
+ return SendRawPacketNoLock(packet_str);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::SendNotificationPacketNoLock(
+ llvm::StringRef notify_type, std::deque<std::string> &queue,
+ llvm::StringRef payload) {
+ PacketResult ret = PacketResult::Success;
+
+ // If there are no notification in the queue, send the notification
+ // packet.
+ if (queue.empty()) {
+ StreamString packet(0, 4, eByteOrderBig);
+ packet.PutChar('%');
+ packet.Write(notify_type.data(), notify_type.size());
+ packet.PutChar(':');
+ packet.Write(payload.data(), payload.size());
+ packet.PutChar('#');
+ packet.PutHex8(CalculcateChecksum(payload));
+ ret = SendRawPacketNoLock(packet.GetString(), true);
+ }
+
+ queue.push_back(payload.str());
+ return ret;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::SendRawPacketNoLock(llvm::StringRef packet,
+ bool skip_ack) {
+ if (IsConnected()) {
+ Log *log = GetLog(GDBRLog::Packets);
+ ConnectionStatus status = eConnectionStatusSuccess;
+ const char *packet_data = packet.data();
+ const size_t packet_length = packet.size();
+ size_t bytes_written = WriteAll(packet_data, packet_length, status, nullptr);
+ if (log) {
+ size_t binary_start_offset = 0;
+ if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) ==
+ 0) {
+ const char *first_comma = strchr(packet_data, ',');
+ if (first_comma) {
+ const char *second_comma = strchr(first_comma + 1, ',');
+ if (second_comma)
+ binary_start_offset = second_comma - packet_data + 1;
+ }
+ }
+
+ // If logging was just enabled and we have history, then dump out what we
+ // have to the log so we get the historical context. The Dump() call that
+ // logs all of the packet will set a boolean so that we don't dump this
+ // more than once
+ if (!m_history.DidDumpToLog())
+ m_history.Dump(log);
+
+ if (binary_start_offset) {
+ StreamString strm;
+ // Print non binary data header
+ strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written,
+ (int)binary_start_offset, packet_data);
+ const uint8_t *p;
+ // Print binary data exactly as sent
+ for (p = (const uint8_t *)packet_data + binary_start_offset; *p != '#';
+ ++p)
+ strm.Printf("\\x%2.2x", *p);
+ // Print the checksum
+ strm.Printf("%*s", (int)3, p);
+ log->PutString(strm.GetString());
+ } else
+ LLDB_LOGF(log, "<%4" PRIu64 "> send packet: %.*s",
+ (uint64_t)bytes_written, (int)packet_length, packet_data);
+ }
+
+ m_history.AddPacket(packet.str(), packet_length,
+ GDBRemotePacket::ePacketTypeSend, bytes_written);
+
+ if (bytes_written == packet_length) {
+ if (!skip_ack && GetSendAcks())
+ return GetAck();
+ else
+ return PacketResult::Success;
+ } else {
+ LLDB_LOGF(log, "error: failed to send packet: %.*s", (int)packet_length,
+ packet_data);
+ }
+ }
+ return PacketResult::ErrorSendFailed;
+}
+
+GDBRemoteCommunication::PacketResult GDBRemoteCommunication::GetAck() {
+ StringExtractorGDBRemote packet;
+ PacketResult result = WaitForPacketNoLock(packet, GetPacketTimeout(), false);
+ if (result == PacketResult::Success) {
+ if (packet.GetResponseType() ==
+ StringExtractorGDBRemote::ResponseType::eAck)
+ return PacketResult::Success;
+ else
+ return PacketResult::ErrorSendAck;
+ }
+ return result;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response,
+ Timeout<std::micro> timeout,
+ bool sync_on_timeout) {
+ using ResponseType = StringExtractorGDBRemote::ResponseType;
+
+ Log *log = GetLog(GDBRLog::Packets);
+ for (;;) {
+ PacketResult result =
+ WaitForPacketNoLock(response, timeout, sync_on_timeout);
+ if (result != PacketResult::Success ||
+ (response.GetResponseType() != ResponseType::eAck &&
+ response.GetResponseType() != ResponseType::eNack))
+ return result;
+ LLDB_LOG(log, "discarding spurious `{0}` packet", response.GetStringRef());
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet,
+ Timeout<std::micro> timeout,
+ bool sync_on_timeout) {
+ uint8_t buffer[8192];
+ Status error;
+
+ Log *log = GetLog(GDBRLog::Packets);
+
+ // Check for a packet from our cache first without trying any reading...
+ if (CheckForPacket(nullptr, 0, packet) != PacketType::Invalid)
+ return PacketResult::Success;
+
+ bool timed_out = false;
+ bool disconnected = false;
+ while (IsConnected() && !timed_out) {
+ lldb::ConnectionStatus status = eConnectionStatusNoConnection;
+ size_t bytes_read = Read(buffer, sizeof(buffer), timeout, status, &error);
+
+ LLDB_LOGV(log,
+ "Read(buffer, sizeof(buffer), timeout = {0}, "
+ "status = {1}, error = {2}) => bytes_read = {3}",
+ timeout, Communication::ConnectionStatusAsString(status), error,
+ bytes_read);
+
+ if (bytes_read > 0) {
+ if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid)
+ return PacketResult::Success;
+ } else {
+ switch (status) {
+ case eConnectionStatusTimedOut:
+ case eConnectionStatusInterrupted:
+ if (sync_on_timeout) {
+ /// Sync the remote GDB server and make sure we get a response that
+ /// corresponds to what we send.
+ ///
+ /// Sends a "qEcho" packet and makes sure it gets the exact packet
+ /// echoed back. If the qEcho packet isn't supported, we send a qC
+ /// packet and make sure we get a valid thread ID back. We use the
+ /// "qC" packet since its response if very unique: is responds with
+ /// "QC%x" where %x is the thread ID of the current thread. This
+ /// makes the response unique enough from other packet responses to
+ /// ensure we are back on track.
+ ///
+ /// This packet is needed after we time out sending a packet so we
+ /// can ensure that we are getting the response for the packet we
+ /// are sending. There are no sequence IDs in the GDB remote
+ /// protocol (there used to be, but they are not supported anymore)
+ /// so if you timeout sending packet "abc", you might then send
+ /// packet "cde" and get the response for the previous "abc" packet.
+ /// Many responses are "OK" or "" (unsupported) or "EXX" (error) so
+ /// many responses for packets can look like responses for other
+ /// packets. So if we timeout, we need to ensure that we can get
+ /// back on track. If we can't get back on track, we must
+ /// disconnect.
+ bool sync_success = false;
+ bool got_actual_response = false;
+ // We timed out, we need to sync back up with the
+ char echo_packet[32];
+ int echo_packet_len = 0;
+ RegularExpression response_regex;
+
+ if (m_supports_qEcho == eLazyBoolYes) {
+ echo_packet_len = ::snprintf(echo_packet, sizeof(echo_packet),
+ "qEcho:%u", ++m_echo_number);
+ std::string regex_str = "^";
+ regex_str += echo_packet;
+ regex_str += "$";
+ response_regex = RegularExpression(regex_str);
+ } else {
+ echo_packet_len =
+ ::snprintf(echo_packet, sizeof(echo_packet), "qC");
+ response_regex =
+ RegularExpression(llvm::StringRef("^QC[0-9A-Fa-f]+$"));
+ }
+
+ PacketResult echo_packet_result =
+ SendPacketNoLock(llvm::StringRef(echo_packet, echo_packet_len));
+ if (echo_packet_result == PacketResult::Success) {
+ const uint32_t max_retries = 3;
+ uint32_t successful_responses = 0;
+ for (uint32_t i = 0; i < max_retries; ++i) {
+ StringExtractorGDBRemote echo_response;
+ echo_packet_result =
+ WaitForPacketNoLock(echo_response, timeout, false);
+ if (echo_packet_result == PacketResult::Success) {
+ ++successful_responses;
+ if (response_regex.Execute(echo_response.GetStringRef())) {
+ sync_success = true;
+ break;
+ } else if (successful_responses == 1) {
+ // We got something else back as the first successful
+ // response, it probably is the response to the packet we
+ // actually wanted, so copy it over if this is the first
+ // success and continue to try to get the qEcho response
+ packet = echo_response;
+ got_actual_response = true;
+ }
+ } else if (echo_packet_result == PacketResult::ErrorReplyTimeout)
+ continue; // Packet timed out, continue waiting for a response
+ else
+ break; // Something else went wrong getting the packet back, we
+ // failed and are done trying
+ }
+ }
+
+ // We weren't able to sync back up with the server, we must abort
+ // otherwise all responses might not be from the right packets...
+ if (sync_success) {
+ // We timed out, but were able to recover
+ if (got_actual_response) {
+ // We initially timed out, but we did get a response that came in
+ // before the successful reply to our qEcho packet, so lets say
+ // everything is fine...
+ return PacketResult::Success;
+ }
+ } else {
+ disconnected = true;
+ Disconnect();
+ }
+ }
+ 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:
+ disconnected = true;
+ Disconnect();
+ break;
+ }
+ }
+ }
+ packet.Clear();
+ if (disconnected)
+ return PacketResult::ErrorDisconnected;
+ if (timed_out)
+ return PacketResult::ErrorReplyTimeout;
+ else
+ return PacketResult::ErrorReplyFailed;
+}
+
+bool GDBRemoteCommunication::DecompressPacket() {
+ Log *log = GetLog(GDBRLog::Packets);
+
+ if (!CompressionIsEnabled())
+ return true;
+
+ size_t pkt_size = m_bytes.size();
+
+ // Smallest possible compressed packet is $N#00 - an uncompressed empty
+ // reply, most commonly indicating an unsupported packet. Anything less than
+ // 5 characters, it's definitely not a compressed packet.
+ if (pkt_size < 5)
+ return true;
+
+ if (m_bytes[0] != '$' && m_bytes[0] != '%')
+ return true;
+ if (m_bytes[1] != 'C' && m_bytes[1] != 'N')
+ return true;
+
+ size_t hash_mark_idx = m_bytes.find('#');
+ if (hash_mark_idx == std::string::npos)
+ return true;
+ if (hash_mark_idx + 2 >= m_bytes.size())
+ return true;
+
+ if (!::isxdigit(m_bytes[hash_mark_idx + 1]) ||
+ !::isxdigit(m_bytes[hash_mark_idx + 2]))
+ return true;
+
+ size_t content_length =
+ pkt_size -
+ 5; // not counting '$', 'C' | 'N', '#', & the two hex checksum chars
+ size_t content_start = 2; // The first character of the
+ // compressed/not-compressed text of the packet
+ size_t checksum_idx =
+ hash_mark_idx +
+ 1; // The first character of the two hex checksum characters
+
+ // Normally size_of_first_packet == m_bytes.size() but m_bytes may contain
+ // multiple packets. size_of_first_packet is the size of the initial packet
+ // which we'll replace with the decompressed version of, leaving the rest of
+ // m_bytes unmodified.
+ size_t size_of_first_packet = hash_mark_idx + 3;
+
+ // Compressed packets ("$C") start with a base10 number which is the size of
+ // the uncompressed payload, then a : and then the compressed data. e.g.
+ // $C1024:<binary>#00 Update content_start and content_length to only include
+ // the <binary> part of the packet.
+
+ uint64_t decompressed_bufsize = ULONG_MAX;
+ if (m_bytes[1] == 'C') {
+ size_t i = content_start;
+ while (i < hash_mark_idx && isdigit(m_bytes[i]))
+ i++;
+ if (i < hash_mark_idx && m_bytes[i] == ':') {
+ i++;
+ content_start = i;
+ content_length = hash_mark_idx - content_start;
+ std::string bufsize_str(m_bytes.data() + 2, i - 2 - 1);
+ errno = 0;
+ decompressed_bufsize = ::strtoul(bufsize_str.c_str(), nullptr, 10);
+ if (errno != 0 || decompressed_bufsize == ULONG_MAX) {
+ m_bytes.erase(0, size_of_first_packet);
+ return false;
+ }
+ }
+ }
+
+ if (GetSendAcks()) {
+ char packet_checksum_cstr[3];
+ packet_checksum_cstr[0] = m_bytes[checksum_idx];
+ packet_checksum_cstr[1] = m_bytes[checksum_idx + 1];
+ packet_checksum_cstr[2] = '\0';
+ long packet_checksum = strtol(packet_checksum_cstr, nullptr, 16);
+
+ long actual_checksum = CalculcateChecksum(
+ llvm::StringRef(m_bytes).substr(1, hash_mark_idx - 1));
+ bool success = packet_checksum == actual_checksum;
+ if (!success) {
+ LLDB_LOGF(log,
+ "error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x",
+ (int)(pkt_size), m_bytes.c_str(), (uint8_t)packet_checksum,
+ (uint8_t)actual_checksum);
+ }
+ // Send the ack or nack if needed
+ if (!success) {
+ SendNack();
+ m_bytes.erase(0, size_of_first_packet);
+ return false;
+ } else {
+ SendAck();
+ }
+ }
+
+ if (m_bytes[1] == 'N') {
+ // This packet was not compressed -- delete the 'N' character at the start
+ // and the packet may be processed as-is.
+ m_bytes.erase(1, 1);
+ return true;
+ }
+
+ // Reverse the gdb-remote binary escaping that was done to the compressed
+ // text to guard characters like '$', '#', '}', etc.
+ std::vector<uint8_t> unescaped_content;
+ unescaped_content.reserve(content_length);
+ size_t i = content_start;
+ while (i < hash_mark_idx) {
+ if (m_bytes[i] == '}') {
+ i++;
+ unescaped_content.push_back(m_bytes[i] ^ 0x20);
+ } else {
+ unescaped_content.push_back(m_bytes[i]);
+ }
+ i++;
+ }
+
+ uint8_t *decompressed_buffer = nullptr;
+ size_t decompressed_bytes = 0;
+
+ if (decompressed_bufsize != ULONG_MAX) {
+ decompressed_buffer = (uint8_t *)malloc(decompressed_bufsize);
+ if (decompressed_buffer == nullptr) {
+ m_bytes.erase(0, size_of_first_packet);
+ return false;
+ }
+ }
+
+#if defined(HAVE_LIBCOMPRESSION)
+ if (m_compression_type == CompressionType::ZlibDeflate ||
+ m_compression_type == CompressionType::LZFSE ||
+ m_compression_type == CompressionType::LZ4 ||
+ m_compression_type == CompressionType::LZMA) {
+ compression_algorithm compression_type;
+ if (m_compression_type == CompressionType::LZFSE)
+ compression_type = COMPRESSION_LZFSE;
+ else if (m_compression_type == CompressionType::ZlibDeflate)
+ compression_type = COMPRESSION_ZLIB;
+ else if (m_compression_type == CompressionType::LZ4)
+ compression_type = COMPRESSION_LZ4_RAW;
+ else if (m_compression_type == CompressionType::LZMA)
+ compression_type = COMPRESSION_LZMA;
+
+ if (m_decompression_scratch_type != m_compression_type) {
+ if (m_decompression_scratch) {
+ free (m_decompression_scratch);
+ m_decompression_scratch = nullptr;
+ }
+ size_t scratchbuf_size = 0;
+ if (m_compression_type == CompressionType::LZFSE)
+ scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE);
+ else if (m_compression_type == CompressionType::LZ4)
+ scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZ4_RAW);
+ else if (m_compression_type == CompressionType::ZlibDeflate)
+ scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_ZLIB);
+ else if (m_compression_type == CompressionType::LZMA)
+ scratchbuf_size =
+ compression_decode_scratch_buffer_size(COMPRESSION_LZMA);
+ if (scratchbuf_size > 0) {
+ m_decompression_scratch = (void*) malloc (scratchbuf_size);
+ m_decompression_scratch_type = m_compression_type;
+ }
+ }
+
+ if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr) {
+ decompressed_bytes = compression_decode_buffer(
+ decompressed_buffer, decompressed_bufsize,
+ (uint8_t *)unescaped_content.data(), unescaped_content.size(),
+ m_decompression_scratch, compression_type);
+ }
+ }
+#endif
+
+#if LLVM_ENABLE_ZLIB
+ if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX &&
+ decompressed_buffer != nullptr &&
+ m_compression_type == CompressionType::ZlibDeflate) {
+ z_stream stream;
+ memset(&stream, 0, sizeof(z_stream));
+ stream.next_in = (Bytef *)unescaped_content.data();
+ stream.avail_in = (uInt)unescaped_content.size();
+ stream.total_in = 0;
+ stream.next_out = (Bytef *)decompressed_buffer;
+ stream.avail_out = decompressed_bufsize;
+ stream.total_out = 0;
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = Z_NULL;
+
+ if (inflateInit2(&stream, -15) == Z_OK) {
+ int status = inflate(&stream, Z_NO_FLUSH);
+ inflateEnd(&stream);
+ if (status == Z_STREAM_END) {
+ decompressed_bytes = stream.total_out;
+ }
+ }
+ }
+#endif
+
+ if (decompressed_bytes == 0 || decompressed_buffer == nullptr) {
+ if (decompressed_buffer)
+ free(decompressed_buffer);
+ m_bytes.erase(0, size_of_first_packet);
+ return false;
+ }
+
+ std::string new_packet;
+ new_packet.reserve(decompressed_bytes + 6);
+ new_packet.push_back(m_bytes[0]);
+ new_packet.append((const char *)decompressed_buffer, decompressed_bytes);
+ new_packet.push_back('#');
+ if (GetSendAcks()) {
+ uint8_t decompressed_checksum = CalculcateChecksum(
+ llvm::StringRef((const char *)decompressed_buffer, decompressed_bytes));
+ char decompressed_checksum_str[3];
+ snprintf(decompressed_checksum_str, 3, "%02x", decompressed_checksum);
+ new_packet.append(decompressed_checksum_str);
+ } else {
+ new_packet.push_back('0');
+ new_packet.push_back('0');
+ }
+
+ m_bytes.replace(0, size_of_first_packet, new_packet.data(),
+ new_packet.size());
+
+ free(decompressed_buffer);
+ return true;
+}
+
+GDBRemoteCommunication::PacketType
+GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len,
+ StringExtractorGDBRemote &packet) {
+ // Put the packet data into the buffer in a thread safe fashion
+ std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex);
+
+ Log *log = GetLog(GDBRLog::Packets);
+
+ if (src && src_len > 0) {
+ if (log && log->GetVerbose()) {
+ StreamString s;
+ LLDB_LOGF(log, "GDBRemoteCommunication::%s adding %u bytes: %.*s",
+ __FUNCTION__, (uint32_t)src_len, (uint32_t)src_len, src);
+ }
+ m_bytes.append((const char *)src, src_len);
+ }
+
+ bool isNotifyPacket = false;
+
+ // Parse up the packets into gdb remote packets
+ if (!m_bytes.empty()) {
+ // end_idx must be one past the last valid packet byte. Start it off with
+ // an invalid value that is the same as the current index.
+ size_t content_start = 0;
+ size_t content_length = 0;
+ size_t total_length = 0;
+ size_t checksum_idx = std::string::npos;
+
+ // Size of packet before it is decompressed, for logging purposes
+ size_t original_packet_size = m_bytes.size();
+ if (CompressionIsEnabled()) {
+ if (!DecompressPacket()) {
+ packet.Clear();
+ return GDBRemoteCommunication::PacketType::Standard;
+ }
+ }
+
+ switch (m_bytes[0]) {
+ case '+': // Look for ack
+ case '-': // Look for cancel
+ case '\x03': // ^C to halt target
+ content_length = total_length = 1; // The command is one byte long...
+ break;
+
+ case '%': // Async notify packet
+ isNotifyPacket = true;
+ [[fallthrough]];
+
+ case '$':
+ // Look for a standard gdb packet?
+ {
+ size_t hash_pos = m_bytes.find('#');
+ if (hash_pos != std::string::npos) {
+ if (hash_pos + 2 < m_bytes.size()) {
+ checksum_idx = hash_pos + 1;
+ // Skip the dollar sign
+ content_start = 1;
+ // Don't include the # in the content or the $ in the content
+ // length
+ content_length = hash_pos - 1;
+
+ total_length =
+ hash_pos + 3; // Skip the # and the two hex checksum bytes
+ } else {
+ // Checksum bytes aren't all here yet
+ content_length = std::string::npos;
+ }
+ }
+ }
+ break;
+
+ default: {
+ // We have an unexpected byte and we need to flush all bad data that is
+ // in m_bytes, so we need to find the first byte that is a '+' (ACK), '-'
+ // (NACK), \x03 (CTRL+C interrupt), or '$' character (start of packet
+ // header) or of course, the end of the data in m_bytes...
+ const size_t bytes_len = m_bytes.size();
+ bool done = false;
+ uint32_t idx;
+ for (idx = 1; !done && idx < bytes_len; ++idx) {
+ switch (m_bytes[idx]) {
+ case '+':
+ case '-':
+ case '\x03':
+ case '%':
+ case '$':
+ done = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ LLDB_LOGF(log, "GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'",
+ __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str());
+ m_bytes.erase(0, idx - 1);
+ } break;
+ }
+
+ if (content_length == std::string::npos) {
+ packet.Clear();
+ return GDBRemoteCommunication::PacketType::Invalid;
+ } else if (total_length > 0) {
+
+ // We have a valid packet...
+ assert(content_length <= m_bytes.size());
+ assert(total_length <= m_bytes.size());
+ assert(content_length <= total_length);
+ size_t content_end = content_start + content_length;
+
+ bool success = true;
+ if (log) {
+ // If logging was just enabled and we have history, then dump out what
+ // we have to the log so we get the historical context. The Dump() call
+ // that logs all of the packet will set a boolean so that we don't dump
+ // this more than once
+ if (!m_history.DidDumpToLog())
+ m_history.Dump(log);
+
+ bool binary = false;
+ // Only detect binary for packets that start with a '$' and have a
+ // '#CC' checksum
+ if (m_bytes[0] == '$' && total_length > 4) {
+ for (size_t i = 0; !binary && i < total_length; ++i) {
+ unsigned char c = m_bytes[i];
+ if (!llvm::isPrint(c) && !llvm::isSpace(c)) {
+ binary = true;
+ }
+ }
+ }
+ if (binary) {
+ StreamString strm;
+ // Packet header...
+ if (CompressionIsEnabled())
+ strm.Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %c",
+ (uint64_t)original_packet_size, (uint64_t)total_length,
+ m_bytes[0]);
+ else
+ strm.Printf("<%4" PRIu64 "> read packet: %c",
+ (uint64_t)total_length, m_bytes[0]);
+ for (size_t i = content_start; i < content_end; ++i) {
+ // Remove binary escaped bytes when displaying the packet...
+ const char ch = m_bytes[i];
+ if (ch == 0x7d) {
+ // 0x7d is the escape character. The next character is to be
+ // XOR'd with 0x20.
+ const char escapee = m_bytes[++i] ^ 0x20;
+ strm.Printf("%2.2x", escapee);
+ } else {
+ strm.Printf("%2.2x", (uint8_t)ch);
+ }
+ }
+ // Packet footer...
+ strm.Printf("%c%c%c", m_bytes[total_length - 3],
+ m_bytes[total_length - 2], m_bytes[total_length - 1]);
+ log->PutString(strm.GetString());
+ } else {
+ if (CompressionIsEnabled())
+ LLDB_LOGF(log, "<%4" PRIu64 ":%" PRIu64 "> read packet: %.*s",
+ (uint64_t)original_packet_size, (uint64_t)total_length,
+ (int)(total_length), m_bytes.c_str());
+ else
+ LLDB_LOGF(log, "<%4" PRIu64 "> read packet: %.*s",
+ (uint64_t)total_length, (int)(total_length),
+ m_bytes.c_str());
+ }
+ }
+
+ m_history.AddPacket(m_bytes, total_length,
+ GDBRemotePacket::ePacketTypeRecv, total_length);
+
+ // Copy the packet from m_bytes to packet_str expanding the run-length
+ // encoding in the process.
+ std ::string packet_str =
+ ExpandRLE(m_bytes.substr(content_start, content_end - content_start));
+ packet = StringExtractorGDBRemote(packet_str);
+
+ if (m_bytes[0] == '$' || m_bytes[0] == '%') {
+ assert(checksum_idx < m_bytes.size());
+ if (::isxdigit(m_bytes[checksum_idx + 0]) ||
+ ::isxdigit(m_bytes[checksum_idx + 1])) {
+ if (GetSendAcks()) {
+ const char *packet_checksum_cstr = &m_bytes[checksum_idx];
+ char packet_checksum = strtol(packet_checksum_cstr, nullptr, 16);
+ char actual_checksum = CalculcateChecksum(
+ llvm::StringRef(m_bytes).slice(content_start, content_end));
+ success = packet_checksum == actual_checksum;
+ if (!success) {
+ LLDB_LOGF(log,
+ "error: checksum mismatch: %.*s expected 0x%2.2x, "
+ "got 0x%2.2x",
+ (int)(total_length), m_bytes.c_str(),
+ (uint8_t)packet_checksum, (uint8_t)actual_checksum);
+ }
+ // Send the ack or nack if needed
+ if (!success)
+ SendNack();
+ else
+ SendAck();
+ }
+ } else {
+ success = false;
+ LLDB_LOGF(log, "error: invalid checksum in packet: '%s'\n",
+ m_bytes.c_str());
+ }
+ }
+
+ m_bytes.erase(0, total_length);
+ packet.SetFilePos(0);
+
+ if (isNotifyPacket)
+ return GDBRemoteCommunication::PacketType::Notify;
+ else
+ return GDBRemoteCommunication::PacketType::Standard;
+ }
+ }
+ packet.Clear();
+ return GDBRemoteCommunication::PacketType::Invalid;
+}
+
+Status GDBRemoteCommunication::StartListenThread(const char *hostname,
+ uint16_t port) {
+ if (m_listen_thread.IsJoinable())
+ return Status("listen thread already running");
+
+ char listen_url[512];
+ if (hostname && hostname[0])
+ snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port);
+ else
+ snprintf(listen_url, sizeof(listen_url), "listen://%i", port);
+ m_listen_url = listen_url;
+ SetConnection(std::make_unique<ConnectionFileDescriptor>());
+ llvm::Expected<HostThread> listen_thread = ThreadLauncher::LaunchThread(
+ listen_url, [this] { return GDBRemoteCommunication::ListenThread(); });
+ if (!listen_thread)
+ return Status(listen_thread.takeError());
+ m_listen_thread = *listen_thread;
+
+ return Status();
+}
+
+bool GDBRemoteCommunication::JoinListenThread() {
+ if (m_listen_thread.IsJoinable())
+ m_listen_thread.Join(nullptr);
+ return true;
+}
+
+lldb::thread_result_t GDBRemoteCommunication::ListenThread() {
+ Status error;
+ ConnectionFileDescriptor *connection =
+ (ConnectionFileDescriptor *)GetConnection();
+
+ if (connection) {
+ // Do the listen on another thread so we can continue on...
+ if (connection->Connect(
+ m_listen_url.c_str(),
+ [this](llvm::StringRef port_str) {
+ uint16_t port = 0;
+ llvm::to_integer(port_str, port, 10);
+ m_port_promise.set_value(port);
+ },
+ &error) != eConnectionStatusSuccess)
+ SetConnection(nullptr);
+ }
+ return {};
+}
+
+Status GDBRemoteCommunication::StartDebugserverProcess(
+ const char *url, Platform *platform, ProcessLaunchInfo &launch_info,
+ uint16_t *port, const Args *inferior_args, int pass_comm_fd) {
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOGF(log, "GDBRemoteCommunication::%s(url=%s, port=%" PRIu16 ")",
+ __FUNCTION__, url ? url : "<empty>", port ? *port : uint16_t(0));
+
+ Status error;
+ // If we locate debugserver, keep that located version around
+ static FileSpec g_debugserver_file_spec;
+
+ char debugserver_path[PATH_MAX];
+ FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
+
+ Environment host_env = Host::GetEnvironment();
+
+ // Always check to see if we have an environment override for the path to the
+ // debugserver to use and use it if we do.
+ std::string env_debugserver_path = host_env.lookup("LLDB_DEBUGSERVER_PATH");
+ if (!env_debugserver_path.empty()) {
+ debugserver_file_spec.SetFile(env_debugserver_path,
+ FileSpec::Style::native);
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s() gdb-remote stub exe path set "
+ "from environment variable: %s",
+ __FUNCTION__, env_debugserver_path.c_str());
+ } else
+ debugserver_file_spec = g_debugserver_file_spec;
+ bool debugserver_exists =
+ FileSystem::Instance().Exists(debugserver_file_spec);
+ if (!debugserver_exists) {
+ // The debugserver binary is in the LLDB.framework/Resources directory.
+ debugserver_file_spec = HostInfo::GetSupportExeDir();
+ if (debugserver_file_spec) {
+ debugserver_file_spec.AppendPathComponent(DEBUGSERVER_BASENAME);
+ debugserver_exists = FileSystem::Instance().Exists(debugserver_file_spec);
+ if (debugserver_exists) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'",
+ __FUNCTION__, debugserver_file_spec.GetPath().c_str());
+
+ g_debugserver_file_spec = debugserver_file_spec;
+ } else {
+ if (platform)
+ debugserver_file_spec =
+ platform->LocateExecutable(DEBUGSERVER_BASENAME);
+ else
+ debugserver_file_spec.Clear();
+ if (debugserver_file_spec) {
+ // Platform::LocateExecutable() wouldn't return a path if it doesn't
+ // exist
+ debugserver_exists = true;
+ } else {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s() could not find "
+ "gdb-remote stub exe '%s'",
+ __FUNCTION__, debugserver_file_spec.GetPath().c_str());
+ }
+ // Don't cache the platform specific GDB server binary as it could
+ // change from platform to platform
+ g_debugserver_file_spec.Clear();
+ }
+ }
+ }
+
+ if (debugserver_exists) {
+ debugserver_file_spec.GetPath(debugserver_path, sizeof(debugserver_path));
+
+ Args &debugserver_args = launch_info.GetArguments();
+ debugserver_args.Clear();
+
+ // Start args with "debugserver /file/path -r --"
+ debugserver_args.AppendArgument(llvm::StringRef(debugserver_path));
+
+#if !defined(__APPLE__)
+ // First argument to lldb-server must be mode in which to run.
+ debugserver_args.AppendArgument(llvm::StringRef("gdbserver"));
+#endif
+
+ // If a url is supplied then use it
+ if (url)
+ debugserver_args.AppendArgument(llvm::StringRef(url));
+
+ if (pass_comm_fd >= 0) {
+ StreamString fd_arg;
+ fd_arg.Printf("--fd=%i", pass_comm_fd);
+ debugserver_args.AppendArgument(fd_arg.GetString());
+ // Send "pass_comm_fd" down to the inferior so it can use it to
+ // communicate back with this process
+ launch_info.AppendDuplicateFileAction(pass_comm_fd, pass_comm_fd);
+ }
+
+ // use native registers, not the GDB registers
+ debugserver_args.AppendArgument(llvm::StringRef("--native-regs"));
+
+ if (launch_info.GetLaunchInSeparateProcessGroup()) {
+ debugserver_args.AppendArgument(llvm::StringRef("--setsid"));
+ }
+
+ llvm::SmallString<128> named_pipe_path;
+ // socket_pipe is used by debug server to communicate back either
+ // TCP port or domain socket name which it listens on.
+ // The second purpose of the pipe to serve as a synchronization point -
+ // once data is written to the pipe, debug server is up and running.
+ Pipe socket_pipe;
+
+ // port is null when debug server should listen on domain socket - we're
+ // not interested in port value but rather waiting for debug server to
+ // become available.
+ if (pass_comm_fd == -1) {
+ if (url) {
+// Create a temporary file to get the stdout/stderr and redirect the output of
+// the command into this file. We will later read this file if all goes well
+// and fill the data into "command_output_ptr"
+#if defined(__APPLE__)
+ // Binding to port zero, we need to figure out what port it ends up
+ // using using a named pipe...
+ error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe",
+ false, named_pipe_path);
+ if (error.Fail()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s() "
+ "named pipe creation failed: %s",
+ __FUNCTION__, error.AsCString());
+ return error;
+ }
+ debugserver_args.AppendArgument(llvm::StringRef("--named-pipe"));
+ debugserver_args.AppendArgument(named_pipe_path);
+#else
+ // Binding to port zero, we need to figure out what port it ends up
+ // using using an unnamed pipe...
+ error = socket_pipe.CreateNew(true);
+ if (error.Fail()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s() "
+ "unnamed pipe creation failed: %s",
+ __FUNCTION__, error.AsCString());
+ return error;
+ }
+ pipe_t write = socket_pipe.GetWritePipe();
+ debugserver_args.AppendArgument(llvm::StringRef("--pipe"));
+ debugserver_args.AppendArgument(llvm::to_string(write));
+ launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor());
+#endif
+ } else {
+ // No host and port given, so lets listen on our end and make the
+ // debugserver connect to us..
+ error = StartListenThread("127.0.0.1", 0);
+ if (error.Fail()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s() unable to start listen "
+ "thread: %s",
+ __FUNCTION__, error.AsCString());
+ return error;
+ }
+
+ // Wait for 10 seconds to resolve the bound port
+ std::future<uint16_t> port_future = m_port_promise.get_future();
+ uint16_t port_ = port_future.wait_for(std::chrono::seconds(10)) ==
+ std::future_status::ready
+ ? port_future.get()
+ : 0;
+ if (port_ > 0) {
+ char port_cstr[32];
+ snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", port_);
+ // Send the host and port down that debugserver and specify an option
+ // so that it connects back to the port we are listening to in this
+ // process
+ debugserver_args.AppendArgument(llvm::StringRef("--reverse-connect"));
+ debugserver_args.AppendArgument(llvm::StringRef(port_cstr));
+ if (port)
+ *port = port_;
+ } else {
+ error.SetErrorString("failed to bind to port 0 on 127.0.0.1");
+ LLDB_LOGF(log, "GDBRemoteCommunication::%s() failed: %s",
+ __FUNCTION__, error.AsCString());
+ return error;
+ }
+ }
+ }
+ std::string env_debugserver_log_file =
+ host_env.lookup("LLDB_DEBUGSERVER_LOG_FILE");
+ if (!env_debugserver_log_file.empty()) {
+ debugserver_args.AppendArgument(
+ llvm::formatv("--log-file={0}", env_debugserver_log_file).str());
+ }
+
+#if defined(__APPLE__)
+ const char *env_debugserver_log_flags =
+ getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
+ if (env_debugserver_log_flags) {
+ debugserver_args.AppendArgument(
+ llvm::formatv("--log-flags={0}", env_debugserver_log_flags).str());
+ }
+#else
+ std::string env_debugserver_log_channels =
+ host_env.lookup("LLDB_SERVER_LOG_CHANNELS");
+ if (!env_debugserver_log_channels.empty()) {
+ debugserver_args.AppendArgument(
+ llvm::formatv("--log-channels={0}", env_debugserver_log_channels)
+ .str());
+ }
+#endif
+
+ // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an
+ // env var doesn't come back.
+ uint32_t env_var_index = 1;
+ bool has_env_var;
+ do {
+ char env_var_name[64];
+ snprintf(env_var_name, sizeof(env_var_name),
+ "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++);
+ std::string extra_arg = host_env.lookup(env_var_name);
+ has_env_var = !extra_arg.empty();
+
+ if (has_env_var) {
+ debugserver_args.AppendArgument(llvm::StringRef(extra_arg));
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s adding env var %s contents "
+ "to stub command line (%s)",
+ __FUNCTION__, env_var_name, extra_arg.c_str());
+ }
+ } while (has_env_var);
+
+ if (inferior_args && inferior_args->GetArgumentCount() > 0) {
+ debugserver_args.AppendArgument(llvm::StringRef("--"));
+ debugserver_args.AppendArguments(*inferior_args);
+ }
+
+ // Copy the current environment to the gdbserver/debugserver instance
+ launch_info.GetEnvironment() = host_env;
+
+ // Close STDIN, STDOUT and STDERR.
+ launch_info.AppendCloseFileAction(STDIN_FILENO);
+ launch_info.AppendCloseFileAction(STDOUT_FILENO);
+ launch_info.AppendCloseFileAction(STDERR_FILENO);
+
+ // Redirect STDIN, STDOUT and STDERR to "/dev/null".
+ launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false);
+ launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true);
+ launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true);
+
+ if (log) {
+ StreamString string_stream;
+ Platform *const platform = nullptr;
+ launch_info.Dump(string_stream, platform);
+ LLDB_LOGF(log, "launch info for gdb-remote stub:\n%s",
+ string_stream.GetData());
+ }
+ error = Host::LaunchProcess(launch_info);
+
+ if (error.Success() &&
+ (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) &&
+ pass_comm_fd == -1) {
+ if (named_pipe_path.size() > 0) {
+ error = socket_pipe.OpenAsReader(named_pipe_path, false);
+ if (error.Fail())
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s() "
+ "failed to open named pipe %s for reading: %s",
+ __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
+ }
+
+ if (socket_pipe.CanWrite())
+ socket_pipe.CloseWriteFileDescriptor();
+ if (socket_pipe.CanRead()) {
+ char port_cstr[PATH_MAX] = {0};
+ port_cstr[0] = '\0';
+ size_t num_bytes = sizeof(port_cstr);
+ // Read port from pipe with 10 second timeout.
+ error = socket_pipe.ReadWithTimeout(
+ port_cstr, num_bytes, std::chrono::seconds{10}, num_bytes);
+ if (error.Success() && (port != nullptr)) {
+ assert(num_bytes > 0 && port_cstr[num_bytes - 1] == '\0');
+ uint16_t child_port = 0;
+ // FIXME: improve error handling
+ llvm::to_integer(port_cstr, child_port);
+ if (*port == 0 || *port == child_port) {
+ *port = child_port;
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s() "
+ "debugserver listens %u port",
+ __FUNCTION__, *port);
+ } else {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s() "
+ "debugserver listening on port "
+ "%d but requested port was %d",
+ __FUNCTION__, (uint32_t)child_port, (uint32_t)(*port));
+ }
+ } else {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s() "
+ "failed to read a port value from pipe %s: %s",
+ __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
+ }
+ socket_pipe.Close();
+ }
+
+ if (named_pipe_path.size() > 0) {
+ const auto err = socket_pipe.Delete(named_pipe_path);
+ if (err.Fail()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunication::%s failed to delete pipe %s: %s",
+ __FUNCTION__, named_pipe_path.c_str(), err.AsCString());
+ }
+ }
+
+ // Make sure we actually connect with the debugserver...
+ JoinListenThread();
+ }
+ } else {
+ error.SetErrorStringWithFormat("unable to locate " DEBUGSERVER_BASENAME);
+ }
+
+ if (error.Fail()) {
+ LLDB_LOGF(log, "GDBRemoteCommunication::%s() failed: %s", __FUNCTION__,
+ error.AsCString());
+ }
+
+ return error;
+}
+
+void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); }
+
+llvm::Error
+GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
+ GDBRemoteCommunication &server) {
+ const bool child_processes_inherit = false;
+ const int backlog = 5;
+ TCPSocket listen_socket(true, child_processes_inherit);
+ if (llvm::Error error =
+ listen_socket.Listen("localhost:0", backlog).ToError())
+ return error;
+
+ Socket *accept_socket = nullptr;
+ std::future<Status> accept_status = std::async(
+ std::launch::async, [&] { return listen_socket.Accept(accept_socket); });
+
+ llvm::SmallString<32> remote_addr;
+ llvm::raw_svector_ostream(remote_addr)
+ << "connect://localhost:" << listen_socket.GetLocalPortNumber();
+
+ std::unique_ptr<ConnectionFileDescriptor> conn_up(
+ new ConnectionFileDescriptor());
+ Status status;
+ if (conn_up->Connect(remote_addr, &status) != lldb::eConnectionStatusSuccess)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Unable to connect: %s", status.AsCString());
+
+ client.SetConnection(std::move(conn_up));
+ if (llvm::Error error = accept_status.get().ToError())
+ return error;
+
+ server.SetConnection(
+ std::make_unique<ConnectionFileDescriptor>(accept_socket));
+ return llvm::Error::success();
+}
+
+GDBRemoteCommunication::ScopedTimeout::ScopedTimeout(
+ GDBRemoteCommunication &gdb_comm, std::chrono::seconds timeout)
+ : m_gdb_comm(gdb_comm), m_saved_timeout(0), m_timeout_modified(false) {
+ auto curr_timeout = gdb_comm.GetPacketTimeout();
+ // Only update the timeout if the timeout is greater than the current
+ // timeout. If the current timeout is larger, then just use that.
+ if (curr_timeout < timeout) {
+ m_timeout_modified = true;
+ m_saved_timeout = m_gdb_comm.SetPacketTimeout(timeout);
+ }
+}
+
+GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout() {
+ // Only restore the timeout if we set it in the constructor.
+ if (m_timeout_modified)
+ m_gdb_comm.SetPacketTimeout(m_saved_timeout);
+}
+
+void llvm::format_provider<GDBRemoteCommunication::PacketResult>::format(
+ const GDBRemoteCommunication::PacketResult &result, raw_ostream &Stream,
+ StringRef Style) {
+ using PacketResult = GDBRemoteCommunication::PacketResult;
+
+ switch (result) {
+ case PacketResult::Success:
+ Stream << "Success";
+ break;
+ case PacketResult::ErrorSendFailed:
+ Stream << "ErrorSendFailed";
+ break;
+ case PacketResult::ErrorSendAck:
+ Stream << "ErrorSendAck";
+ break;
+ case PacketResult::ErrorReplyFailed:
+ Stream << "ErrorReplyFailed";
+ break;
+ case PacketResult::ErrorReplyTimeout:
+ Stream << "ErrorReplyTimeout";
+ break;
+ case PacketResult::ErrorReplyInvalid:
+ Stream << "ErrorReplyInvalid";
+ break;
+ case PacketResult::ErrorReplyAck:
+ Stream << "ErrorReplyAck";
+ break;
+ case PacketResult::ErrorDisconnected:
+ Stream << "ErrorDisconnected";
+ break;
+ case PacketResult::ErrorNoSequenceLock:
+ Stream << "ErrorNoSequenceLock";
+ break;
+ }
+}
+
+std::string GDBRemoteCommunication::ExpandRLE(std::string packet) {
+ // Reserve enough byte for the most common case (no RLE used).
+ std::string decoded;
+ decoded.reserve(packet.size());
+ for (std::string::const_iterator c = packet.begin(); c != packet.end(); ++c) {
+ if (*c == '*') {
+ // '*' indicates RLE. Next character will give us the repeat count and
+ // previous character is what is to be repeated.
+ char char_to_repeat = decoded.back();
+ // Number of time the previous character is repeated.
+ int repeat_count = *++c + 3 - ' ';
+ // We have the char_to_repeat and repeat_count. Now push it in the
+ // packet.
+ for (int i = 0; i < repeat_count; ++i)
+ decoded.push_back(char_to_repeat);
+ } else if (*c == 0x7d) {
+ // 0x7d is the escape character. The next character is to be XOR'd with
+ // 0x20.
+ char escapee = *++c ^ 0x20;
+ decoded.push_back(escapee);
+ } else {
+ decoded.push_back(*c);
+ }
+ }
+ return decoded;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
new file mode 100644
index 000000000000..4e59bd5ec8be
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -0,0 +1,249 @@
+//===-- GDBRemoteCommunication.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H
+
+#include "GDBRemoteCommunicationHistory.h"
+
+#include <condition_variable>
+#include <future>
+#include <mutex>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "lldb/Core/Communication.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/Listener.h"
+#include "lldb/Utility/Predicate.h"
+#include "lldb/Utility/StringExtractorGDBRemote.h"
+#include "lldb/lldb-public.h"
+
+namespace lldb_private {
+namespace repro {
+class PacketRecorder;
+}
+namespace process_gdb_remote {
+
+enum GDBStoppointType {
+ eStoppointInvalid = -1,
+ eBreakpointSoftware = 0,
+ eBreakpointHardware,
+ eWatchpointWrite,
+ eWatchpointRead,
+ eWatchpointReadWrite
+};
+
+enum class CompressionType {
+ None = 0, // no compression
+ ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's
+ // libcompression
+ LZFSE, // an Apple compression scheme, requires Apple's libcompression
+ LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with
+ // https://code.google.com/p/lz4/
+ LZMA, // Lempel–Ziv–Markov chain algorithm
+};
+
+// Data included in the vFile:fstat packet.
+// https://sourceware.org/gdb/onlinedocs/gdb/struct-stat.html#struct-stat
+struct GDBRemoteFStatData {
+ llvm::support::ubig32_t gdb_st_dev;
+ llvm::support::ubig32_t gdb_st_ino;
+ llvm::support::ubig32_t gdb_st_mode;
+ llvm::support::ubig32_t gdb_st_nlink;
+ llvm::support::ubig32_t gdb_st_uid;
+ llvm::support::ubig32_t gdb_st_gid;
+ llvm::support::ubig32_t gdb_st_rdev;
+ llvm::support::ubig64_t gdb_st_size;
+ llvm::support::ubig64_t gdb_st_blksize;
+ llvm::support::ubig64_t gdb_st_blocks;
+ llvm::support::ubig32_t gdb_st_atime;
+ llvm::support::ubig32_t gdb_st_mtime;
+ llvm::support::ubig32_t gdb_st_ctime;
+};
+static_assert(sizeof(GDBRemoteFStatData) == 64,
+ "size of GDBRemoteFStatData is not 64");
+
+enum GDBErrno {
+#define HANDLE_ERRNO(name, value) GDB_##name = value,
+#include "Plugins/Process/gdb-remote/GDBRemoteErrno.def"
+ GDB_EUNKNOWN = 9999
+};
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunication : public Communication {
+public:
+ enum class PacketType { Invalid = 0, Standard, Notify };
+
+ enum class PacketResult {
+ Success = 0, // Success
+ ErrorSendFailed, // Status sending the packet
+ ErrorSendAck, // Didn't get an ack back after sending a packet
+ ErrorReplyFailed, // Status getting the reply
+ ErrorReplyTimeout, // Timed out waiting for reply
+ ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that
+ // was sent
+ ErrorReplyAck, // Sending reply ack failed
+ ErrorDisconnected, // We were disconnected
+ ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet
+ // request
+ };
+
+ // Class to change the timeout for a given scope and restore it to the
+ // original value when the
+ // created ScopedTimeout object got out of scope
+ class ScopedTimeout {
+ public:
+ ScopedTimeout(GDBRemoteCommunication &gdb_comm,
+ std::chrono::seconds timeout);
+ ~ScopedTimeout();
+
+ private:
+ GDBRemoteCommunication &m_gdb_comm;
+ std::chrono::seconds m_saved_timeout;
+ // Don't ever reduce the timeout for a packet, only increase it. If the
+ // requested timeout if less than the current timeout, we don't set it
+ // and won't need to restore it.
+ bool m_timeout_modified;
+ };
+
+ GDBRemoteCommunication();
+
+ ~GDBRemoteCommunication() override;
+
+ PacketResult GetAck();
+
+ size_t SendAck();
+
+ size_t SendNack();
+
+ char CalculcateChecksum(llvm::StringRef payload);
+
+ PacketType CheckForPacket(const uint8_t *src, size_t src_len,
+ StringExtractorGDBRemote &packet);
+
+ bool GetSendAcks() { return m_send_acks; }
+
+ // Set the global packet timeout.
+ //
+ // For clients, this is the timeout that gets used when sending
+ // packets and waiting for responses. For servers, this is used when waiting
+ // for ACKs.
+ std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) {
+ const auto old_packet_timeout = m_packet_timeout;
+ m_packet_timeout = packet_timeout;
+ return old_packet_timeout;
+ }
+
+ std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; }
+
+ // Start a debugserver instance on the current host using the
+ // supplied connection URL.
+ Status StartDebugserverProcess(
+ const char *url,
+ Platform *platform, // If non nullptr, then check with the platform for
+ // the GDB server binary if it can't be located
+ ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args,
+ int pass_comm_fd); // Communication file descriptor to pass during
+ // fork/exec to avoid having to connect/accept
+
+ void DumpHistory(Stream &strm);
+
+ void SetPacketRecorder(repro::PacketRecorder *recorder);
+
+ static llvm::Error ConnectLocally(GDBRemoteCommunication &client,
+ GDBRemoteCommunication &server);
+
+ /// Expand GDB run-length encoding.
+ static std::string ExpandRLE(std::string);
+
+protected:
+ std::chrono::seconds m_packet_timeout;
+ uint32_t m_echo_number;
+ LazyBool m_supports_qEcho;
+ GDBRemoteCommunicationHistory m_history;
+ bool m_send_acks;
+ bool m_is_platform; // Set to true if this class represents a platform,
+ // false if this class represents a debug session for
+ // a single process
+
+ std::string m_bytes;
+ std::recursive_mutex m_bytes_mutex;
+ CompressionType m_compression_type;
+
+ PacketResult SendPacketNoLock(llvm::StringRef payload);
+ PacketResult SendNotificationPacketNoLock(llvm::StringRef notify_type,
+ std::deque<std::string>& queue,
+ llvm::StringRef payload);
+ PacketResult SendRawPacketNoLock(llvm::StringRef payload,
+ bool skip_ack = false);
+
+ PacketResult ReadPacket(StringExtractorGDBRemote &response,
+ Timeout<std::micro> timeout, bool sync_on_timeout);
+
+ PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response,
+ Timeout<std::micro> timeout,
+ bool sync_on_timeout);
+
+ bool CompressionIsEnabled() {
+ return m_compression_type != CompressionType::None;
+ }
+
+ // If compression is enabled, decompress the packet in m_bytes and update
+ // m_bytes with the uncompressed version.
+ // Returns 'true' packet was decompressed and m_bytes is the now-decompressed
+ // text.
+ // Returns 'false' if unable to decompress or if the checksum was invalid.
+ //
+ // NB: Once the packet has been decompressed, checksum cannot be computed
+ // based
+ // on m_bytes. The checksum was for the compressed packet.
+ bool DecompressPacket();
+
+ Status StartListenThread(const char *hostname = "127.0.0.1",
+ uint16_t port = 0);
+
+ bool JoinListenThread();
+
+ lldb::thread_result_t ListenThread();
+
+private:
+ // Promise used to grab the port number from listening thread
+ std::promise<uint16_t> m_port_promise;
+
+ HostThread m_listen_thread;
+ std::string m_listen_url;
+
+#if defined(HAVE_LIBCOMPRESSION)
+ CompressionType m_decompression_scratch_type = CompressionType::None;
+ void *m_decompression_scratch = nullptr;
+#endif
+
+ GDBRemoteCommunication(const GDBRemoteCommunication &) = delete;
+ const GDBRemoteCommunication &
+ operator=(const GDBRemoteCommunication &) = delete;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+namespace llvm {
+template <>
+struct format_provider<
+ lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult> {
+ static void format(const lldb_private::process_gdb_remote::
+ GDBRemoteCommunication::PacketResult &state,
+ raw_ostream &Stream, StringRef Style);
+};
+} // namespace llvm
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATION_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
new file mode 100644
index 000000000000..74e392249a94
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -0,0 +1,4353 @@
+//===-- GDBRemoteCommunicationClient.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteCommunicationClient.h"
+
+#include <cmath>
+#include <sys/stat.h>
+
+#include <numeric>
+#include <optional>
+#include <sstream>
+
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/SafeMachO.h"
+#include "lldb/Host/XML.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Utility/StringExtractorGDBRemote.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/JSON.h"
+
+#if defined(HAVE_LIBCOMPRESSION)
+#include <compression.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private;
+using namespace std::chrono;
+
+llvm::raw_ostream &process_gdb_remote::operator<<(llvm::raw_ostream &os,
+ const QOffsets &offsets) {
+ return os << llvm::formatv(
+ "QOffsets({0}, [{1:@[x]}])", offsets.segments,
+ llvm::make_range(offsets.offsets.begin(), offsets.offsets.end()));
+}
+
+// GDBRemoteCommunicationClient constructor
+GDBRemoteCommunicationClient::GDBRemoteCommunicationClient()
+ : GDBRemoteClientBase("gdb-remote.client"),
+
+ m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true),
+ m_supports_qUserName(true), m_supports_qGroupName(true),
+ m_supports_qThreadStopInfo(true), m_supports_z0(true),
+ m_supports_z1(true), m_supports_z2(true), m_supports_z3(true),
+ m_supports_z4(true), m_supports_QEnvironment(true),
+ m_supports_QEnvironmentHexEncoded(true), m_supports_qSymbol(true),
+ m_qSymbol_requests_done(false), m_supports_qModuleInfo(true),
+ m_supports_jThreadsInfo(true), m_supports_jModulesInfo(true),
+ m_supports_vFileSize(true), m_supports_vFileMode(true),
+ m_supports_vFileExists(true), m_supports_vRun(true),
+
+ m_host_arch(), m_host_distribution_id(), m_process_arch(), m_os_build(),
+ m_os_kernel(), m_hostname(), m_gdb_server_name(),
+ m_default_packet_timeout(0), m_qSupported_response(),
+ m_supported_async_json_packets_sp(), m_qXfer_memory_map() {}
+
+// Destructor
+GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() {
+ if (IsConnected())
+ Disconnect();
+}
+
+bool GDBRemoteCommunicationClient::HandshakeWithServer(Status *error_ptr) {
+ ResetDiscoverableSettings(false);
+
+ // Start the read thread after we send the handshake ack since if we fail to
+ // send the handshake ack, there is no reason to continue...
+ std::chrono::steady_clock::time_point start_of_handshake =
+ std::chrono::steady_clock::now();
+ if (SendAck()) {
+ // The return value from QueryNoAckModeSupported() is true if the packet
+ // was sent and _any_ response (including UNIMPLEMENTED) was received), or
+ // false if no response was received. This quickly tells us if we have a
+ // live connection to a remote GDB server...
+ if (QueryNoAckModeSupported()) {
+ return true;
+ } else {
+ std::chrono::steady_clock::time_point end_of_handshake =
+ std::chrono::steady_clock::now();
+ auto handshake_timeout =
+ std::chrono::duration<double>(end_of_handshake - start_of_handshake)
+ .count();
+ if (error_ptr) {
+ if (!IsConnected())
+ error_ptr->SetErrorString("Connection shut down by remote side "
+ "while waiting for reply to initial "
+ "handshake packet");
+ else
+ error_ptr->SetErrorStringWithFormat(
+ "failed to get reply to handshake packet within timeout of "
+ "%.1f seconds",
+ handshake_timeout);
+ }
+ }
+ } else {
+ if (error_ptr)
+ error_ptr->SetErrorString("failed to send the handshake ack");
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationClient::GetEchoSupported() {
+ if (m_supports_qEcho == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_qEcho == eLazyBoolYes;
+}
+
+bool GDBRemoteCommunicationClient::GetQPassSignalsSupported() {
+ if (m_supports_QPassSignals == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_QPassSignals == eLazyBoolYes;
+}
+
+bool GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported() {
+ if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_augmented_libraries_svr4_read == eLazyBoolYes;
+}
+
+bool GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported() {
+ if (m_supports_qXfer_libraries_svr4_read == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_libraries_svr4_read == eLazyBoolYes;
+}
+
+bool GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported() {
+ if (m_supports_qXfer_libraries_read == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_libraries_read == eLazyBoolYes;
+}
+
+bool GDBRemoteCommunicationClient::GetQXferAuxvReadSupported() {
+ if (m_supports_qXfer_auxv_read == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_auxv_read == eLazyBoolYes;
+}
+
+bool GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported() {
+ if (m_supports_qXfer_features_read == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_features_read == eLazyBoolYes;
+}
+
+bool GDBRemoteCommunicationClient::GetQXferMemoryMapReadSupported() {
+ if (m_supports_qXfer_memory_map_read == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_memory_map_read == eLazyBoolYes;
+}
+
+bool GDBRemoteCommunicationClient::GetQXferSigInfoReadSupported() {
+ if (m_supports_qXfer_siginfo_read == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_siginfo_read == eLazyBoolYes;
+}
+
+bool GDBRemoteCommunicationClient::GetMultiprocessSupported() {
+ if (m_supports_memory_tagging == eLazyBoolCalculate)
+ GetRemoteQSupported();
+ return m_supports_multiprocess == eLazyBoolYes;
+}
+
+uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() {
+ if (m_max_packet_size == 0) {
+ GetRemoteQSupported();
+ }
+ return m_max_packet_size;
+}
+
+bool GDBRemoteCommunicationClient::QueryNoAckModeSupported() {
+ if (m_supports_not_sending_acks == eLazyBoolCalculate) {
+ m_send_acks = true;
+ m_supports_not_sending_acks = eLazyBoolNo;
+
+ // This is the first real packet that we'll send in a debug session and it
+ // may take a little longer than normal to receive a reply. Wait at least
+ // 6 seconds for a reply to this packet.
+
+ ScopedTimeout timeout(*this, std::max(GetPacketTimeout(), seconds(6)));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("QStartNoAckMode", response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ m_send_acks = false;
+ m_supports_not_sending_acks = eLazyBoolYes;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported() {
+ if (m_supports_threads_in_stop_reply == eLazyBoolCalculate) {
+ m_supports_threads_in_stop_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ m_supports_threads_in_stop_reply = eLazyBoolYes;
+ }
+ }
+}
+
+bool GDBRemoteCommunicationClient::GetVAttachOrWaitSupported() {
+ if (m_attach_or_wait_reply == eLazyBoolCalculate) {
+ m_attach_or_wait_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ m_attach_or_wait_reply = eLazyBoolYes;
+ }
+ }
+ return m_attach_or_wait_reply == eLazyBoolYes;
+}
+
+bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported() {
+ if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate) {
+ m_prepare_for_reg_writing_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ m_prepare_for_reg_writing_reply = eLazyBoolYes;
+ }
+ }
+ return m_prepare_for_reg_writing_reply == eLazyBoolYes;
+}
+
+void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
+ if (!did_exec) {
+ // Hard reset everything, this is when we first connect to a GDB server
+ m_supports_not_sending_acks = eLazyBoolCalculate;
+ m_supports_thread_suffix = eLazyBoolCalculate;
+ m_supports_threads_in_stop_reply = eLazyBoolCalculate;
+ m_supports_vCont_c = eLazyBoolCalculate;
+ m_supports_vCont_C = eLazyBoolCalculate;
+ m_supports_vCont_s = eLazyBoolCalculate;
+ m_supports_vCont_S = eLazyBoolCalculate;
+ m_supports_p = eLazyBoolCalculate;
+ m_supports_x = eLazyBoolCalculate;
+ m_supports_QSaveRegisterState = eLazyBoolCalculate;
+ m_qHostInfo_is_valid = eLazyBoolCalculate;
+ m_curr_pid_is_valid = eLazyBoolCalculate;
+ m_qGDBServerVersion_is_valid = eLazyBoolCalculate;
+ m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
+ m_supports_memory_region_info = eLazyBoolCalculate;
+ m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
+ m_attach_or_wait_reply = eLazyBoolCalculate;
+ m_avoid_g_packets = eLazyBoolCalculate;
+ m_supports_multiprocess = eLazyBoolCalculate;
+ m_supports_qSaveCore = eLazyBoolCalculate;
+ m_supports_qXfer_auxv_read = eLazyBoolCalculate;
+ m_supports_qXfer_libraries_read = eLazyBoolCalculate;
+ m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;
+ m_supports_qXfer_features_read = eLazyBoolCalculate;
+ m_supports_qXfer_memory_map_read = eLazyBoolCalculate;
+ m_supports_qXfer_siginfo_read = eLazyBoolCalculate;
+ m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;
+ m_uses_native_signals = eLazyBoolCalculate;
+ m_supports_qProcessInfoPID = true;
+ m_supports_qfProcessInfo = true;
+ m_supports_qUserName = true;
+ m_supports_qGroupName = true;
+ m_supports_qThreadStopInfo = true;
+ m_supports_z0 = true;
+ m_supports_z1 = true;
+ m_supports_z2 = true;
+ m_supports_z3 = true;
+ m_supports_z4 = true;
+ m_supports_QEnvironment = true;
+ m_supports_QEnvironmentHexEncoded = true;
+ m_supports_qSymbol = true;
+ m_qSymbol_requests_done = false;
+ m_supports_qModuleInfo = true;
+ m_host_arch.Clear();
+ m_host_distribution_id.clear();
+ m_os_version = llvm::VersionTuple();
+ m_os_build.clear();
+ m_os_kernel.clear();
+ m_hostname.clear();
+ m_gdb_server_name.clear();
+ m_gdb_server_version = UINT32_MAX;
+ m_default_packet_timeout = seconds(0);
+ m_target_vm_page_size = 0;
+ m_max_packet_size = 0;
+ m_qSupported_response.clear();
+ m_supported_async_json_packets_is_valid = false;
+ m_supported_async_json_packets_sp.reset();
+ m_supports_jModulesInfo = true;
+ }
+
+ // These flags should be reset when we first connect to a GDB server and when
+ // our inferior process execs
+ m_qProcessInfo_is_valid = eLazyBoolCalculate;
+ m_process_arch.Clear();
+}
+
+void GDBRemoteCommunicationClient::GetRemoteQSupported() {
+ // Clear out any capabilities we expect to see in the qSupported response
+ m_supports_qXfer_auxv_read = eLazyBoolNo;
+ m_supports_qXfer_libraries_read = eLazyBoolNo;
+ m_supports_qXfer_libraries_svr4_read = eLazyBoolNo;
+ m_supports_augmented_libraries_svr4_read = eLazyBoolNo;
+ m_supports_qXfer_features_read = eLazyBoolNo;
+ m_supports_qXfer_memory_map_read = eLazyBoolNo;
+ m_supports_qXfer_siginfo_read = eLazyBoolNo;
+ m_supports_multiprocess = eLazyBoolNo;
+ m_supports_qEcho = eLazyBoolNo;
+ m_supports_QPassSignals = eLazyBoolNo;
+ m_supports_memory_tagging = eLazyBoolNo;
+ m_supports_qSaveCore = eLazyBoolNo;
+ m_uses_native_signals = eLazyBoolNo;
+
+ m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if
+ // not, we assume no limit
+
+ // build the qSupported packet
+ std::vector<std::string> features = {"xmlRegisters=i386,arm,mips,arc",
+ "multiprocess+", "fork-events+",
+ "vfork-events+"};
+ StreamString packet;
+ packet.PutCString("qSupported");
+ for (uint32_t i = 0; i < features.size(); ++i) {
+ packet.PutCString(i == 0 ? ":" : ";");
+ packet.PutCString(features[i]);
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success) {
+ // Hang on to the qSupported packet, so that platforms can do custom
+ // configuration of the transport before attaching/launching the process.
+ m_qSupported_response = response.GetStringRef().str();
+
+ for (llvm::StringRef x : llvm::split(response.GetStringRef(), ';')) {
+ if (x == "qXfer:auxv:read+")
+ m_supports_qXfer_auxv_read = eLazyBoolYes;
+ else if (x == "qXfer:libraries-svr4:read+")
+ m_supports_qXfer_libraries_svr4_read = eLazyBoolYes;
+ else if (x == "augmented-libraries-svr4-read") {
+ m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied
+ m_supports_augmented_libraries_svr4_read = eLazyBoolYes;
+ } else if (x == "qXfer:libraries:read+")
+ m_supports_qXfer_libraries_read = eLazyBoolYes;
+ else if (x == "qXfer:features:read+")
+ m_supports_qXfer_features_read = eLazyBoolYes;
+ else if (x == "qXfer:memory-map:read+")
+ m_supports_qXfer_memory_map_read = eLazyBoolYes;
+ else if (x == "qXfer:siginfo:read+")
+ m_supports_qXfer_siginfo_read = eLazyBoolYes;
+ else if (x == "qEcho")
+ m_supports_qEcho = eLazyBoolYes;
+ else if (x == "QPassSignals+")
+ m_supports_QPassSignals = eLazyBoolYes;
+ else if (x == "multiprocess+")
+ m_supports_multiprocess = eLazyBoolYes;
+ else if (x == "memory-tagging+")
+ m_supports_memory_tagging = eLazyBoolYes;
+ else if (x == "qSaveCore+")
+ m_supports_qSaveCore = eLazyBoolYes;
+ else if (x == "native-signals+")
+ m_uses_native_signals = eLazyBoolYes;
+ // Look for a list of compressions in the features list e.g.
+ // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-
+ // deflate,lzma
+ else if (x.consume_front("SupportedCompressions=")) {
+ llvm::SmallVector<llvm::StringRef, 4> compressions;
+ x.split(compressions, ',');
+ if (!compressions.empty())
+ MaybeEnableCompression(compressions);
+ } else if (x.consume_front("SupportedWatchpointTypes=")) {
+ llvm::SmallVector<llvm::StringRef, 4> watchpoint_types;
+ x.split(watchpoint_types, ',');
+ m_watchpoint_types = eWatchpointHardwareFeatureUnknown;
+ for (auto wp_type : watchpoint_types) {
+ if (wp_type == "x86_64")
+ m_watchpoint_types |= eWatchpointHardwareX86;
+ if (wp_type == "aarch64-mask")
+ m_watchpoint_types |= eWatchpointHardwareArmMASK;
+ if (wp_type == "aarch64-bas")
+ m_watchpoint_types |= eWatchpointHardwareArmBAS;
+ }
+ } else if (x.consume_front("PacketSize=")) {
+ StringExtractorGDBRemote packet_response(x);
+ m_max_packet_size =
+ packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX);
+ if (m_max_packet_size == 0) {
+ m_max_packet_size = UINT64_MAX; // Must have been a garbled response
+ Log *log(GetLog(GDBRLog::Process));
+ LLDB_LOGF(log, "Garbled PacketSize spec in qSupported response");
+ }
+ }
+ }
+ }
+}
+
+bool GDBRemoteCommunicationClient::GetThreadSuffixSupported() {
+ if (m_supports_thread_suffix == eLazyBoolCalculate) {
+ StringExtractorGDBRemote response;
+ m_supports_thread_suffix = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ m_supports_thread_suffix = eLazyBoolYes;
+ }
+ }
+ return m_supports_thread_suffix;
+}
+bool GDBRemoteCommunicationClient::GetVContSupported(char flavor) {
+ if (m_supports_vCont_c == eLazyBoolCalculate) {
+ StringExtractorGDBRemote response;
+ m_supports_vCont_any = eLazyBoolNo;
+ m_supports_vCont_all = eLazyBoolNo;
+ m_supports_vCont_c = eLazyBoolNo;
+ m_supports_vCont_C = eLazyBoolNo;
+ m_supports_vCont_s = eLazyBoolNo;
+ m_supports_vCont_S = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("vCont?", response) ==
+ PacketResult::Success) {
+ const char *response_cstr = response.GetStringRef().data();
+ if (::strstr(response_cstr, ";c"))
+ m_supports_vCont_c = eLazyBoolYes;
+
+ if (::strstr(response_cstr, ";C"))
+ m_supports_vCont_C = eLazyBoolYes;
+
+ if (::strstr(response_cstr, ";s"))
+ m_supports_vCont_s = eLazyBoolYes;
+
+ if (::strstr(response_cstr, ";S"))
+ m_supports_vCont_S = eLazyBoolYes;
+
+ if (m_supports_vCont_c == eLazyBoolYes &&
+ m_supports_vCont_C == eLazyBoolYes &&
+ m_supports_vCont_s == eLazyBoolYes &&
+ m_supports_vCont_S == eLazyBoolYes) {
+ m_supports_vCont_all = eLazyBoolYes;
+ }
+
+ if (m_supports_vCont_c == eLazyBoolYes ||
+ m_supports_vCont_C == eLazyBoolYes ||
+ m_supports_vCont_s == eLazyBoolYes ||
+ m_supports_vCont_S == eLazyBoolYes) {
+ m_supports_vCont_any = eLazyBoolYes;
+ }
+ }
+ }
+
+ switch (flavor) {
+ case 'a':
+ return m_supports_vCont_any;
+ case 'A':
+ return m_supports_vCont_all;
+ case 'c':
+ return m_supports_vCont_c;
+ case 'C':
+ return m_supports_vCont_C;
+ case 's':
+ return m_supports_vCont_s;
+ case 'S':
+ return m_supports_vCont_S;
+ default:
+ break;
+ }
+ return false;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationClient::SendThreadSpecificPacketAndWaitForResponse(
+ lldb::tid_t tid, StreamString &&payload,
+ StringExtractorGDBRemote &response) {
+ Lock lock(*this);
+ if (!lock) {
+ if (Log *log = GetLog(GDBRLog::Process | GDBRLog::Packets))
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationClient::%s: Didn't get sequence mutex "
+ "for %s packet.",
+ __FUNCTION__, payload.GetData());
+ return PacketResult::ErrorNoSequenceLock;
+ }
+
+ if (GetThreadSuffixSupported())
+ payload.Printf(";thread:%4.4" PRIx64 ";", tid);
+ else {
+ if (!SetCurrentThread(tid))
+ return PacketResult::ErrorSendFailed;
+ }
+
+ return SendPacketAndWaitForResponseNoLock(payload.GetString(), response);
+}
+
+// Check if the target supports 'p' packet. It sends out a 'p' packet and
+// checks the response. A normal packet will tell us that support is available.
+//
+// Takes a valid thread ID because p needs to apply to a thread.
+bool GDBRemoteCommunicationClient::GetpPacketSupported(lldb::tid_t tid) {
+ if (m_supports_p == eLazyBoolCalculate)
+ m_supports_p = GetThreadPacketSupported(tid, "p0");
+ return m_supports_p;
+}
+
+LazyBool GDBRemoteCommunicationClient::GetThreadPacketSupported(
+ lldb::tid_t tid, llvm::StringRef packetStr) {
+ StreamString payload;
+ payload.PutCString(packetStr);
+ StringExtractorGDBRemote response;
+ if (SendThreadSpecificPacketAndWaitForResponse(
+ tid, std::move(payload), response) == PacketResult::Success &&
+ response.IsNormalResponse()) {
+ return eLazyBoolYes;
+ }
+ return eLazyBoolNo;
+}
+
+bool GDBRemoteCommunicationClient::GetSaveCoreSupported() const {
+ return m_supports_qSaveCore == eLazyBoolYes;
+}
+
+StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() {
+ // Get information on all threads at one using the "jThreadsInfo" packet
+ StructuredData::ObjectSP object_sp;
+
+ if (m_supports_jThreadsInfo) {
+ StringExtractorGDBRemote response;
+ response.SetResponseValidatorToJSON();
+ if (SendPacketAndWaitForResponse("jThreadsInfo", response) ==
+ PacketResult::Success) {
+ if (response.IsUnsupportedResponse()) {
+ m_supports_jThreadsInfo = false;
+ } else if (!response.Empty()) {
+ object_sp = StructuredData::ParseJSON(response.GetStringRef());
+ }
+ }
+ }
+ return object_sp;
+}
+
+bool GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported() {
+ if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate) {
+ StringExtractorGDBRemote response;
+ m_supports_jThreadExtendedInfo = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ m_supports_jThreadExtendedInfo = eLazyBoolYes;
+ }
+ }
+ }
+ return m_supports_jThreadExtendedInfo;
+}
+
+void GDBRemoteCommunicationClient::EnableErrorStringInPacket() {
+ if (m_supports_error_string_reply == eLazyBoolCalculate) {
+ StringExtractorGDBRemote response;
+ // We try to enable error strings in remote packets but if we fail, we just
+ // work in the older way.
+ m_supports_error_string_reply = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("QEnableErrorStrings", response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ m_supports_error_string_reply = eLazyBoolYes;
+ }
+ }
+ }
+}
+
+bool GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported() {
+ if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) {
+ StringExtractorGDBRemote response;
+ m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:",
+ response) == PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes;
+ }
+ }
+ }
+ return m_supports_jLoadedDynamicLibrariesInfos;
+}
+
+bool GDBRemoteCommunicationClient::GetSharedCacheInfoSupported() {
+ if (m_supports_jGetSharedCacheInfo == eLazyBoolCalculate) {
+ StringExtractorGDBRemote response;
+ m_supports_jGetSharedCacheInfo = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jGetSharedCacheInfo:", response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ m_supports_jGetSharedCacheInfo = eLazyBoolYes;
+ }
+ }
+ }
+ return m_supports_jGetSharedCacheInfo;
+}
+
+bool GDBRemoteCommunicationClient::GetDynamicLoaderProcessStateSupported() {
+ if (m_supports_jGetDyldProcessState == eLazyBoolCalculate) {
+ StringExtractorGDBRemote response;
+ m_supports_jGetDyldProcessState = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jGetDyldProcessState", response) ==
+ PacketResult::Success) {
+ if (!response.IsUnsupportedResponse())
+ m_supports_jGetDyldProcessState = eLazyBoolYes;
+ }
+ }
+ return m_supports_jGetDyldProcessState;
+}
+
+bool GDBRemoteCommunicationClient::GetMemoryTaggingSupported() {
+ if (m_supports_memory_tagging == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_memory_tagging == eLazyBoolYes;
+}
+
+DataBufferSP GDBRemoteCommunicationClient::ReadMemoryTags(lldb::addr_t addr,
+ size_t len,
+ int32_t type) {
+ StreamString packet;
+ packet.Printf("qMemTags:%" PRIx64 ",%zx:%" PRIx32, addr, len, type);
+ StringExtractorGDBRemote response;
+
+ Log *log = GetLog(GDBRLog::Memory);
+
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ PacketResult::Success ||
+ !response.IsNormalResponse()) {
+ LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s: qMemTags packet failed",
+ __FUNCTION__);
+ return nullptr;
+ }
+
+ // We are expecting
+ // m<hex encoded bytes>
+
+ if (response.GetChar() != 'm') {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationClient::%s: qMemTags response did not "
+ "begin with \"m\"",
+ __FUNCTION__);
+ return nullptr;
+ }
+
+ size_t expected_bytes = response.GetBytesLeft() / 2;
+ WritableDataBufferSP buffer_sp(new DataBufferHeap(expected_bytes, 0));
+ size_t got_bytes = response.GetHexBytesAvail(buffer_sp->GetData());
+ // Check both because in some situations chars are consumed even
+ // if the decoding fails.
+ if (response.GetBytesLeft() || (expected_bytes != got_bytes)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationClient::%s: Invalid data in qMemTags response",
+ __FUNCTION__);
+ return nullptr;
+ }
+
+ return buffer_sp;
+}
+
+Status GDBRemoteCommunicationClient::WriteMemoryTags(
+ lldb::addr_t addr, size_t len, int32_t type,
+ const std::vector<uint8_t> &tags) {
+ // Format QMemTags:address,length:type:tags
+ StreamString packet;
+ packet.Printf("QMemTags:%" PRIx64 ",%zx:%" PRIx32 ":", addr, len, type);
+ packet.PutBytesAsRawHex8(tags.data(), tags.size());
+
+ Status status;
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ PacketResult::Success ||
+ !response.IsOKResponse()) {
+ status.SetErrorString("QMemTags packet failed");
+ }
+ return status;
+}
+
+bool GDBRemoteCommunicationClient::GetxPacketSupported() {
+ if (m_supports_x == eLazyBoolCalculate) {
+ StringExtractorGDBRemote response;
+ m_supports_x = eLazyBoolNo;
+ char packet[256];
+ snprintf(packet, sizeof(packet), "x0,0");
+ if (SendPacketAndWaitForResponse(packet, response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ m_supports_x = eLazyBoolYes;
+ }
+ }
+ return m_supports_x;
+}
+
+lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) {
+ if (allow_lazy && m_curr_pid_is_valid == eLazyBoolYes)
+ return m_curr_pid;
+
+ // First try to retrieve the pid via the qProcessInfo request.
+ GetCurrentProcessInfo(allow_lazy);
+ if (m_curr_pid_is_valid == eLazyBoolYes) {
+ // We really got it.
+ return m_curr_pid;
+ } else {
+ // If we don't get a response for qProcessInfo, check if $qC gives us a
+ // result. $qC only returns a real process id on older debugserver and
+ // lldb-platform stubs. The gdb remote protocol documents $qC as returning
+ // the thread id, which newer debugserver and lldb-gdbserver stubs return
+ // correctly.
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC", response) == PacketResult::Success) {
+ if (response.GetChar() == 'Q') {
+ if (response.GetChar() == 'C') {
+ m_curr_pid_run = m_curr_pid =
+ response.GetHexMaxU64(false, LLDB_INVALID_PROCESS_ID);
+ if (m_curr_pid != LLDB_INVALID_PROCESS_ID) {
+ m_curr_pid_is_valid = eLazyBoolYes;
+ return m_curr_pid;
+ }
+ }
+ }
+ }
+
+ // If we don't get a response for $qC, check if $qfThreadID gives us a
+ // result.
+ if (m_curr_pid == LLDB_INVALID_PROCESS_ID) {
+ bool sequence_mutex_unavailable;
+ auto ids = GetCurrentProcessAndThreadIDs(sequence_mutex_unavailable);
+ if (!ids.empty() && !sequence_mutex_unavailable) {
+ // If server returned an explicit PID, use that.
+ m_curr_pid_run = m_curr_pid = ids.front().first;
+ // Otherwise, use the TID of the first thread (Linux hack).
+ if (m_curr_pid == LLDB_INVALID_PROCESS_ID)
+ m_curr_pid_run = m_curr_pid = ids.front().second;
+ m_curr_pid_is_valid = eLazyBoolYes;
+ return m_curr_pid;
+ }
+ }
+ }
+
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+llvm::Error GDBRemoteCommunicationClient::LaunchProcess(const Args &args) {
+ if (!args.GetArgumentAtIndex(0))
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Nothing to launch");
+ // try vRun first
+ if (m_supports_vRun) {
+ StreamString packet;
+ packet.PutCString("vRun");
+ for (const Args::ArgEntry &arg : args) {
+ packet.PutChar(';');
+ packet.PutStringAsRawHex8(arg.ref());
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ PacketResult::Success)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Sending vRun packet failed");
+
+ if (response.IsErrorResponse())
+ return response.GetStatus().ToError();
+
+ // vRun replies with a stop reason packet
+ // FIXME: right now we just discard the packet and LLDB queries
+ // for stop reason again
+ if (!response.IsUnsupportedResponse())
+ return llvm::Error::success();
+
+ m_supports_vRun = false;
+ }
+
+ // fallback to A
+ StreamString packet;
+ packet.PutChar('A');
+ llvm::ListSeparator LS(",");
+ for (const auto &arg : llvm::enumerate(args)) {
+ packet << LS;
+ packet.Format("{0},{1},", arg.value().ref().size() * 2, arg.index());
+ packet.PutStringAsRawHex8(arg.value().ref());
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ PacketResult::Success) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Sending A packet failed");
+ }
+ if (!response.IsOKResponse())
+ return response.GetStatus().ToError();
+
+ if (SendPacketAndWaitForResponse("qLaunchSuccess", response) !=
+ PacketResult::Success) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Sending qLaunchSuccess packet failed");
+ }
+ if (response.IsOKResponse())
+ return llvm::Error::success();
+ if (response.GetChar() == 'E') {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ response.GetStringRef().substr(1));
+ }
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "unknown error occurred launching process");
+}
+
+int GDBRemoteCommunicationClient::SendEnvironment(const Environment &env) {
+ llvm::SmallVector<std::pair<llvm::StringRef, llvm::StringRef>, 0> vec;
+ for (const auto &kv : env)
+ vec.emplace_back(kv.first(), kv.second);
+ llvm::sort(vec, llvm::less_first());
+ for (const auto &[k, v] : vec) {
+ int r = SendEnvironmentPacket((k + "=" + v).str().c_str());
+ if (r != 0)
+ return r;
+ }
+ return 0;
+}
+
+int GDBRemoteCommunicationClient::SendEnvironmentPacket(
+ char const *name_equal_value) {
+ if (name_equal_value && name_equal_value[0]) {
+ bool send_hex_encoding = false;
+ for (const char *p = name_equal_value; *p != '\0' && !send_hex_encoding;
+ ++p) {
+ if (llvm::isPrint(*p)) {
+ switch (*p) {
+ case '$':
+ case '#':
+ case '*':
+ case '}':
+ send_hex_encoding = true;
+ break;
+ default:
+ break;
+ }
+ } else {
+ // We have non printable characters, lets hex encode this...
+ send_hex_encoding = true;
+ }
+ }
+
+ StringExtractorGDBRemote response;
+ // Prefer sending unencoded, if possible and the server supports it.
+ if (!send_hex_encoding && m_supports_QEnvironment) {
+ StreamString packet;
+ packet.Printf("QEnvironment:%s", name_equal_value);
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ PacketResult::Success)
+ return -1;
+
+ if (response.IsOKResponse())
+ return 0;
+ if (response.IsUnsupportedResponse())
+ m_supports_QEnvironment = false;
+ else {
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ return -1;
+ }
+ }
+
+ if (m_supports_QEnvironmentHexEncoded) {
+ StreamString packet;
+ packet.PutCString("QEnvironmentHexEncoded:");
+ packet.PutBytesAsRawHex8(name_equal_value, strlen(name_equal_value));
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ PacketResult::Success)
+ return -1;
+
+ if (response.IsOKResponse())
+ return 0;
+ if (response.IsUnsupportedResponse())
+ m_supports_QEnvironmentHexEncoded = false;
+ else {
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ return -1;
+ }
+ }
+ }
+ return -1;
+}
+
+int GDBRemoteCommunicationClient::SendLaunchArchPacket(char const *arch) {
+ if (arch && arch[0]) {
+ StreamString packet;
+ packet.Printf("QLaunchArch:%s", arch);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int GDBRemoteCommunicationClient::SendLaunchEventDataPacket(
+ char const *data, bool *was_supported) {
+ if (data && *data != '\0') {
+ StreamString packet;
+ packet.Printf("QSetProcessEvent:%s", data);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ if (was_supported)
+ *was_supported = true;
+ return 0;
+ } else if (response.IsUnsupportedResponse()) {
+ if (was_supported)
+ *was_supported = false;
+ return -1;
+ } else {
+ uint8_t error = response.GetError();
+ if (was_supported)
+ *was_supported = true;
+ if (error)
+ return error;
+ }
+ }
+ }
+ return -1;
+}
+
+llvm::VersionTuple GDBRemoteCommunicationClient::GetOSVersion() {
+ GetHostInfo();
+ return m_os_version;
+}
+
+llvm::VersionTuple GDBRemoteCommunicationClient::GetMacCatalystVersion() {
+ GetHostInfo();
+ return m_maccatalyst_version;
+}
+
+std::optional<std::string> GDBRemoteCommunicationClient::GetOSBuildString() {
+ if (GetHostInfo()) {
+ if (!m_os_build.empty())
+ return m_os_build;
+ }
+ return std::nullopt;
+}
+
+std::optional<std::string>
+GDBRemoteCommunicationClient::GetOSKernelDescription() {
+ if (GetHostInfo()) {
+ if (!m_os_kernel.empty())
+ return m_os_kernel;
+ }
+ return std::nullopt;
+}
+
+bool GDBRemoteCommunicationClient::GetHostname(std::string &s) {
+ if (GetHostInfo()) {
+ if (!m_hostname.empty()) {
+ s = m_hostname;
+ return true;
+ }
+ }
+ s.clear();
+ return false;
+}
+
+ArchSpec GDBRemoteCommunicationClient::GetSystemArchitecture() {
+ if (GetHostInfo())
+ return m_host_arch;
+ return ArchSpec();
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunicationClient::GetProcessArchitecture() {
+ if (m_qProcessInfo_is_valid == eLazyBoolCalculate)
+ GetCurrentProcessInfo();
+ return m_process_arch;
+}
+
+bool GDBRemoteCommunicationClient::GetProcessStandaloneBinary(
+ UUID &uuid, addr_t &value, bool &value_is_offset) {
+ if (m_qProcessInfo_is_valid == eLazyBoolCalculate)
+ GetCurrentProcessInfo();
+
+ // Return true if we have a UUID or an address/offset of the
+ // main standalone / firmware binary being used.
+ if (!m_process_standalone_uuid.IsValid() &&
+ m_process_standalone_value == LLDB_INVALID_ADDRESS)
+ return false;
+
+ uuid = m_process_standalone_uuid;
+ value = m_process_standalone_value;
+ value_is_offset = m_process_standalone_value_is_offset;
+ return true;
+}
+
+std::vector<addr_t>
+GDBRemoteCommunicationClient::GetProcessStandaloneBinaries() {
+ if (m_qProcessInfo_is_valid == eLazyBoolCalculate)
+ GetCurrentProcessInfo();
+ return m_binary_addresses;
+}
+
+bool GDBRemoteCommunicationClient::GetGDBServerVersion() {
+ if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) {
+ m_gdb_server_name.clear();
+ m_gdb_server_version = 0;
+ m_qGDBServerVersion_is_valid = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qGDBServerVersion", response) ==
+ PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ llvm::StringRef name, value;
+ bool success = false;
+ while (response.GetNameColonValue(name, value)) {
+ if (name == "name") {
+ success = true;
+ m_gdb_server_name = std::string(value);
+ } else if (name == "version") {
+ llvm::StringRef major, minor;
+ std::tie(major, minor) = value.split('.');
+ if (!major.getAsInteger(0, m_gdb_server_version))
+ success = true;
+ }
+ }
+ if (success)
+ m_qGDBServerVersion_is_valid = eLazyBoolYes;
+ }
+ }
+ }
+ return m_qGDBServerVersion_is_valid == eLazyBoolYes;
+}
+
+void GDBRemoteCommunicationClient::MaybeEnableCompression(
+ llvm::ArrayRef<llvm::StringRef> supported_compressions) {
+ CompressionType avail_type = CompressionType::None;
+ llvm::StringRef avail_name;
+
+#if defined(HAVE_LIBCOMPRESSION)
+ if (avail_type == CompressionType::None) {
+ for (auto compression : supported_compressions) {
+ if (compression == "lzfse") {
+ avail_type = CompressionType::LZFSE;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined(HAVE_LIBCOMPRESSION)
+ if (avail_type == CompressionType::None) {
+ for (auto compression : supported_compressions) {
+ if (compression == "zlib-deflate") {
+ avail_type = CompressionType::ZlibDeflate;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if LLVM_ENABLE_ZLIB
+ if (avail_type == CompressionType::None) {
+ for (auto compression : supported_compressions) {
+ if (compression == "zlib-deflate") {
+ avail_type = CompressionType::ZlibDeflate;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined(HAVE_LIBCOMPRESSION)
+ if (avail_type == CompressionType::None) {
+ for (auto compression : supported_compressions) {
+ if (compression == "lz4") {
+ avail_type = CompressionType::LZ4;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined(HAVE_LIBCOMPRESSION)
+ if (avail_type == CompressionType::None) {
+ for (auto compression : supported_compressions) {
+ if (compression == "lzma") {
+ avail_type = CompressionType::LZMA;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (avail_type != CompressionType::None) {
+ StringExtractorGDBRemote response;
+ std::string packet = "QEnableCompression:type:" + avail_name.str() + ";";
+ if (SendPacketAndWaitForResponse(packet, response) != PacketResult::Success)
+ return;
+
+ if (response.IsOKResponse()) {
+ m_compression_type = avail_type;
+ }
+ }
+}
+
+const char *GDBRemoteCommunicationClient::GetGDBServerProgramName() {
+ if (GetGDBServerVersion()) {
+ if (!m_gdb_server_name.empty())
+ return m_gdb_server_name.c_str();
+ }
+ return nullptr;
+}
+
+uint32_t GDBRemoteCommunicationClient::GetGDBServerProgramVersion() {
+ if (GetGDBServerVersion())
+ return m_gdb_server_version;
+ return 0;
+}
+
+bool GDBRemoteCommunicationClient::GetDefaultThreadId(lldb::tid_t &tid) {
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC", response) != PacketResult::Success)
+ return false;
+
+ if (!response.IsNormalResponse())
+ return false;
+
+ if (response.GetChar() == 'Q' && response.GetChar() == 'C') {
+ auto pid_tid = response.GetPidTid(0);
+ if (!pid_tid)
+ return false;
+
+ lldb::pid_t pid = pid_tid->first;
+ // invalid
+ if (pid == StringExtractorGDBRemote::AllProcesses)
+ return false;
+
+ // if we get pid as well, update m_curr_pid
+ if (pid != 0) {
+ m_curr_pid_run = m_curr_pid = pid;
+ m_curr_pid_is_valid = eLazyBoolYes;
+ }
+ tid = pid_tid->second;
+ }
+
+ return true;
+}
+
+static void ParseOSType(llvm::StringRef value, std::string &os_name,
+ std::string &environment) {
+ if (value == "iossimulator" || value == "tvossimulator" ||
+ value == "watchossimulator" || value == "xrossimulator" ||
+ value == "visionossimulator") {
+ environment = "simulator";
+ os_name = value.drop_back(environment.size()).str();
+ } else if (value == "maccatalyst") {
+ os_name = "ios";
+ environment = "macabi";
+ } else {
+ os_name = value.str();
+ }
+}
+
+bool GDBRemoteCommunicationClient::GetHostInfo(bool force) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) {
+ // host info computation can require DNS traffic and shelling out to external processes.
+ // Increase the timeout to account for that.
+ ScopedTimeout timeout(*this, seconds(10));
+ m_qHostInfo_is_valid = eLazyBoolNo;
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qHostInfo", response) ==
+ PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ llvm::StringRef name;
+ llvm::StringRef value;
+ uint32_t cpu = LLDB_INVALID_CPUTYPE;
+ uint32_t sub = 0;
+ std::string arch_name;
+ std::string os_name;
+ std::string environment;
+ std::string vendor_name;
+ std::string triple;
+ uint32_t pointer_byte_size = 0;
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t num_keys_decoded = 0;
+ while (response.GetNameColonValue(name, value)) {
+ if (name == "cputype") {
+ // exception type in big endian hex
+ if (!value.getAsInteger(0, cpu))
+ ++num_keys_decoded;
+ } else if (name == "cpusubtype") {
+ // exception count in big endian hex
+ if (!value.getAsInteger(0, sub))
+ ++num_keys_decoded;
+ } else if (name == "arch") {
+ arch_name = std::string(value);
+ ++num_keys_decoded;
+ } else if (name == "triple") {
+ StringExtractor extractor(value);
+ extractor.GetHexByteString(triple);
+ ++num_keys_decoded;
+ } else if (name == "distribution_id") {
+ StringExtractor extractor(value);
+ extractor.GetHexByteString(m_host_distribution_id);
+ ++num_keys_decoded;
+ } else if (name == "os_build") {
+ StringExtractor extractor(value);
+ extractor.GetHexByteString(m_os_build);
+ ++num_keys_decoded;
+ } else if (name == "hostname") {
+ StringExtractor extractor(value);
+ extractor.GetHexByteString(m_hostname);
+ ++num_keys_decoded;
+ } else if (name == "os_kernel") {
+ StringExtractor extractor(value);
+ extractor.GetHexByteString(m_os_kernel);
+ ++num_keys_decoded;
+ } else if (name == "ostype") {
+ ParseOSType(value, os_name, environment);
+ ++num_keys_decoded;
+ } else if (name == "vendor") {
+ vendor_name = std::string(value);
+ ++num_keys_decoded;
+ } else if (name == "endian") {
+ byte_order = llvm::StringSwitch<lldb::ByteOrder>(value)
+ .Case("little", eByteOrderLittle)
+ .Case("big", eByteOrderBig)
+ .Case("pdp", eByteOrderPDP)
+ .Default(eByteOrderInvalid);
+ if (byte_order != eByteOrderInvalid)
+ ++num_keys_decoded;
+ } else if (name == "ptrsize") {
+ if (!value.getAsInteger(0, pointer_byte_size))
+ ++num_keys_decoded;
+ } else if (name == "addressing_bits") {
+ if (!value.getAsInteger(0, m_low_mem_addressing_bits)) {
+ ++num_keys_decoded;
+ }
+ } else if (name == "high_mem_addressing_bits") {
+ if (!value.getAsInteger(0, m_high_mem_addressing_bits))
+ ++num_keys_decoded;
+ } else if (name == "low_mem_addressing_bits") {
+ if (!value.getAsInteger(0, m_low_mem_addressing_bits))
+ ++num_keys_decoded;
+ } else if (name == "os_version" ||
+ name == "version") // Older debugserver binaries used
+ // the "version" key instead of
+ // "os_version"...
+ {
+ if (!m_os_version.tryParse(value))
+ ++num_keys_decoded;
+ } else if (name == "maccatalyst_version") {
+ if (!m_maccatalyst_version.tryParse(value))
+ ++num_keys_decoded;
+ } else if (name == "watchpoint_exceptions_received") {
+ m_watchpoints_trigger_after_instruction =
+ llvm::StringSwitch<LazyBool>(value)
+ .Case("before", eLazyBoolNo)
+ .Case("after", eLazyBoolYes)
+ .Default(eLazyBoolCalculate);
+ if (m_watchpoints_trigger_after_instruction != eLazyBoolCalculate)
+ ++num_keys_decoded;
+ } else if (name == "default_packet_timeout") {
+ uint32_t timeout_seconds;
+ if (!value.getAsInteger(0, timeout_seconds)) {
+ m_default_packet_timeout = seconds(timeout_seconds);
+ SetPacketTimeout(m_default_packet_timeout);
+ ++num_keys_decoded;
+ }
+ } else if (name == "vm-page-size") {
+ int page_size;
+ if (!value.getAsInteger(0, page_size)) {
+ m_target_vm_page_size = page_size;
+ ++num_keys_decoded;
+ }
+ }
+ }
+
+ if (num_keys_decoded > 0)
+ m_qHostInfo_is_valid = eLazyBoolYes;
+
+ if (triple.empty()) {
+ if (arch_name.empty()) {
+ if (cpu != LLDB_INVALID_CPUTYPE) {
+ m_host_arch.SetArchitecture(eArchTypeMachO, cpu, sub);
+ if (pointer_byte_size) {
+ assert(pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid) {
+ assert(byte_order == m_host_arch.GetByteOrder());
+ }
+
+ if (!vendor_name.empty())
+ m_host_arch.GetTriple().setVendorName(
+ llvm::StringRef(vendor_name));
+ if (!os_name.empty())
+ m_host_arch.GetTriple().setOSName(llvm::StringRef(os_name));
+ if (!environment.empty())
+ m_host_arch.GetTriple().setEnvironmentName(environment);
+ }
+ } else {
+ std::string triple;
+ triple += arch_name;
+ if (!vendor_name.empty() || !os_name.empty()) {
+ triple += '-';
+ if (vendor_name.empty())
+ triple += "unknown";
+ else
+ triple += vendor_name;
+ triple += '-';
+ if (os_name.empty())
+ triple += "unknown";
+ else
+ triple += os_name;
+ }
+ m_host_arch.SetTriple(triple.c_str());
+
+ llvm::Triple &host_triple = m_host_arch.GetTriple();
+ if (host_triple.getVendor() == llvm::Triple::Apple &&
+ host_triple.getOS() == llvm::Triple::Darwin) {
+ switch (m_host_arch.GetMachine()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ host_triple.setOS(llvm::Triple::IOS);
+ break;
+ default:
+ host_triple.setOS(llvm::Triple::MacOSX);
+ break;
+ }
+ }
+ if (pointer_byte_size) {
+ assert(pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid) {
+ assert(byte_order == m_host_arch.GetByteOrder());
+ }
+ }
+ } else {
+ m_host_arch.SetTriple(triple.c_str());
+ if (pointer_byte_size) {
+ assert(pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid) {
+ assert(byte_order == m_host_arch.GetByteOrder());
+ }
+
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationClient::%s parsed host "
+ "architecture as %s, triple as %s from triple text %s",
+ __FUNCTION__,
+ m_host_arch.GetArchitectureName()
+ ? m_host_arch.GetArchitectureName()
+ : "<null-arch-name>",
+ m_host_arch.GetTriple().getTriple().c_str(),
+ triple.c_str());
+ }
+ }
+ }
+ }
+ return m_qHostInfo_is_valid == eLazyBoolYes;
+}
+
+int GDBRemoteCommunicationClient::SendStdinNotification(const char *data,
+ size_t data_len) {
+ StreamString packet;
+ packet.PutCString("I");
+ packet.PutBytesAsRawHex8(data, data_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success) {
+ return 0;
+ }
+ return response.GetError();
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunicationClient::GetHostArchitecture() {
+ if (m_qHostInfo_is_valid == eLazyBoolCalculate)
+ GetHostInfo();
+ return m_host_arch;
+}
+
+AddressableBits GDBRemoteCommunicationClient::GetAddressableBits() {
+ AddressableBits addressable_bits;
+ if (m_qHostInfo_is_valid == eLazyBoolCalculate)
+ GetHostInfo();
+
+ if (m_low_mem_addressing_bits == m_high_mem_addressing_bits)
+ addressable_bits.SetAddressableBits(m_low_mem_addressing_bits);
+ else
+ addressable_bits.SetAddressableBits(m_low_mem_addressing_bits,
+ m_high_mem_addressing_bits);
+ return addressable_bits;
+}
+
+seconds GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout() {
+ if (m_qHostInfo_is_valid == eLazyBoolCalculate)
+ GetHostInfo();
+ return m_default_packet_timeout;
+}
+
+addr_t GDBRemoteCommunicationClient::AllocateMemory(size_t size,
+ uint32_t permissions) {
+ if (m_supports_alloc_dealloc_memory != eLazyBoolNo) {
+ m_supports_alloc_dealloc_memory = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf(
+ packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s", (uint64_t)size,
+ permissions & lldb::ePermissionsReadable ? "r" : "",
+ permissions & lldb::ePermissionsWritable ? "w" : "",
+ permissions & lldb::ePermissionsExecutable ? "x" : "");
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, response) ==
+ PacketResult::Success) {
+ if (response.IsUnsupportedResponse())
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ else if (!response.IsErrorResponse())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ } else {
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool GDBRemoteCommunicationClient::DeallocateMemory(addr_t addr) {
+ if (m_supports_alloc_dealloc_memory != eLazyBoolNo) {
+ m_supports_alloc_dealloc_memory = eLazyBoolYes;
+ char packet[64];
+ const int packet_len =
+ ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr);
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, response) ==
+ PacketResult::Success) {
+ if (response.IsUnsupportedResponse())
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ else if (response.IsOKResponse())
+ return true;
+ } else {
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ }
+ }
+ return false;
+}
+
+Status GDBRemoteCommunicationClient::Detach(bool keep_stopped,
+ lldb::pid_t pid) {
+ Status error;
+ lldb_private::StreamString packet;
+
+ packet.PutChar('D');
+ if (keep_stopped) {
+ if (m_supports_detach_stay_stopped == eLazyBoolCalculate) {
+ char packet[64];
+ const int packet_len =
+ ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:");
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, response) ==
+ PacketResult::Success &&
+ response.IsOKResponse()) {
+ m_supports_detach_stay_stopped = eLazyBoolYes;
+ } else {
+ m_supports_detach_stay_stopped = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_detach_stay_stopped == eLazyBoolNo) {
+ error.SetErrorString("Stays stopped not supported by this target.");
+ return error;
+ } else {
+ packet.PutChar('1');
+ }
+ }
+
+ if (GetMultiprocessSupported()) {
+ // Some servers (e.g. qemu) require specifying the PID even if only a single
+ // process is running.
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ pid = GetCurrentProcessID();
+ packet.PutChar(';');
+ packet.PutHex64(pid);
+ } else if (pid != LLDB_INVALID_PROCESS_ID) {
+ error.SetErrorString("Multiprocess extension not supported by the server.");
+ return error;
+ }
+
+ StringExtractorGDBRemote response;
+ PacketResult packet_result =
+ SendPacketAndWaitForResponse(packet.GetString(), response);
+ if (packet_result != PacketResult::Success)
+ error.SetErrorString("Sending isconnect packet failed.");
+ return error;
+}
+
+Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
+ lldb::addr_t addr, lldb_private::MemoryRegionInfo &region_info) {
+ Status error;
+ region_info.Clear();
+
+ if (m_supports_memory_region_info != eLazyBoolNo) {
+ m_supports_memory_region_info = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf(
+ packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr);
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, response) ==
+ PacketResult::Success &&
+ response.GetResponseType() == StringExtractorGDBRemote::eResponse) {
+ llvm::StringRef name;
+ llvm::StringRef value;
+ addr_t addr_value = LLDB_INVALID_ADDRESS;
+ bool success = true;
+ bool saw_permissions = false;
+ while (success && response.GetNameColonValue(name, value)) {
+ if (name == "start") {
+ if (!value.getAsInteger(16, addr_value))
+ region_info.GetRange().SetRangeBase(addr_value);
+ } else if (name == "size") {
+ if (!value.getAsInteger(16, addr_value)) {
+ region_info.GetRange().SetByteSize(addr_value);
+ if (region_info.GetRange().GetRangeEnd() <
+ region_info.GetRange().GetRangeBase()) {
+ // Range size overflowed, truncate it.
+ region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
+ }
+ }
+ } else if (name == "permissions" && region_info.GetRange().IsValid()) {
+ saw_permissions = true;
+ if (region_info.GetRange().Contains(addr)) {
+ if (value.contains('r'))
+ region_info.SetReadable(MemoryRegionInfo::eYes);
+ else
+ region_info.SetReadable(MemoryRegionInfo::eNo);
+
+ if (value.contains('w'))
+ region_info.SetWritable(MemoryRegionInfo::eYes);
+ else
+ region_info.SetWritable(MemoryRegionInfo::eNo);
+
+ if (value.contains('x'))
+ region_info.SetExecutable(MemoryRegionInfo::eYes);
+ else
+ region_info.SetExecutable(MemoryRegionInfo::eNo);
+
+ region_info.SetMapped(MemoryRegionInfo::eYes);
+ } else {
+ // The reported region does not contain this address -- we're
+ // looking at an unmapped page
+ region_info.SetReadable(MemoryRegionInfo::eNo);
+ region_info.SetWritable(MemoryRegionInfo::eNo);
+ region_info.SetExecutable(MemoryRegionInfo::eNo);
+ region_info.SetMapped(MemoryRegionInfo::eNo);
+ }
+ } else if (name == "name") {
+ StringExtractorGDBRemote name_extractor(value);
+ std::string name;
+ name_extractor.GetHexByteString(name);
+ region_info.SetName(name.c_str());
+ } else if (name == "flags") {
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
+
+ llvm::StringRef flags = value;
+ llvm::StringRef flag;
+ while (flags.size()) {
+ flags = flags.ltrim();
+ std::tie(flag, flags) = flags.split(' ');
+ // To account for trailing whitespace
+ if (flag.size()) {
+ if (flag == "mt") {
+ region_info.SetMemoryTagged(MemoryRegionInfo::eYes);
+ break;
+ }
+ }
+ }
+ } else if (name == "type") {
+ std::string comma_sep_str = value.str();
+ size_t comma_pos;
+ while ((comma_pos = comma_sep_str.find(',')) != std::string::npos) {
+ comma_sep_str[comma_pos] = '\0';
+ if (comma_sep_str == "stack") {
+ region_info.SetIsStackMemory(MemoryRegionInfo::eYes);
+ }
+ }
+ // handle final (or only) type of "stack"
+ if (comma_sep_str == "stack") {
+ region_info.SetIsStackMemory(MemoryRegionInfo::eYes);
+ }
+ } else if (name == "error") {
+ StringExtractorGDBRemote error_extractor(value);
+ std::string error_string;
+ // Now convert the HEX bytes into a string value
+ error_extractor.GetHexByteString(error_string);
+ error.SetErrorString(error_string.c_str());
+ } else if (name == "dirty-pages") {
+ std::vector<addr_t> dirty_page_list;
+ for (llvm::StringRef x : llvm::split(value, ',')) {
+ addr_t page;
+ x.consume_front("0x");
+ if (llvm::to_integer(x, page, 16))
+ dirty_page_list.push_back(page);
+ }
+ region_info.SetDirtyPageList(dirty_page_list);
+ }
+ }
+
+ if (m_target_vm_page_size != 0)
+ region_info.SetPageSize(m_target_vm_page_size);
+
+ if (region_info.GetRange().IsValid()) {
+ // We got a valid address range back but no permissions -- which means
+ // this is an unmapped page
+ if (!saw_permissions) {
+ region_info.SetReadable(MemoryRegionInfo::eNo);
+ region_info.SetWritable(MemoryRegionInfo::eNo);
+ region_info.SetExecutable(MemoryRegionInfo::eNo);
+ region_info.SetMapped(MemoryRegionInfo::eNo);
+ }
+ } else {
+ // We got an invalid address range back
+ error.SetErrorString("Server returned invalid range");
+ }
+ } else {
+ m_supports_memory_region_info = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_memory_region_info == eLazyBoolNo) {
+ error.SetErrorString("qMemoryRegionInfo is not supported");
+ }
+
+ // Try qXfer:memory-map:read to get region information not included in
+ // qMemoryRegionInfo
+ MemoryRegionInfo qXfer_region_info;
+ Status qXfer_error = GetQXferMemoryMapRegionInfo(addr, qXfer_region_info);
+
+ if (error.Fail()) {
+ // If qMemoryRegionInfo failed, but qXfer:memory-map:read succeeded, use
+ // the qXfer result as a fallback
+ if (qXfer_error.Success()) {
+ region_info = qXfer_region_info;
+ error.Clear();
+ } else {
+ region_info.Clear();
+ }
+ } else if (qXfer_error.Success()) {
+ // If both qMemoryRegionInfo and qXfer:memory-map:read succeeded, and if
+ // both regions are the same range, update the result to include the flash-
+ // memory information that is specific to the qXfer result.
+ if (region_info.GetRange() == qXfer_region_info.GetRange()) {
+ region_info.SetFlash(qXfer_region_info.GetFlash());
+ region_info.SetBlocksize(qXfer_region_info.GetBlocksize());
+ }
+ }
+ return error;
+}
+
+Status GDBRemoteCommunicationClient::GetQXferMemoryMapRegionInfo(
+ lldb::addr_t addr, MemoryRegionInfo &region) {
+ Status error = LoadQXferMemoryMap();
+ if (!error.Success())
+ return error;
+ for (const auto &map_region : m_qXfer_memory_map) {
+ if (map_region.GetRange().Contains(addr)) {
+ region = map_region;
+ return error;
+ }
+ }
+ error.SetErrorString("Region not found");
+ return error;
+}
+
+Status GDBRemoteCommunicationClient::LoadQXferMemoryMap() {
+
+ Status error;
+
+ if (m_qXfer_memory_map_loaded)
+ // Already loaded, return success
+ return error;
+
+ if (!XMLDocument::XMLEnabled()) {
+ error.SetErrorString("XML is not supported");
+ return error;
+ }
+
+ if (!GetQXferMemoryMapReadSupported()) {
+ error.SetErrorString("Memory map is not supported");
+ return error;
+ }
+
+ llvm::Expected<std::string> xml = ReadExtFeature("memory-map", "");
+ if (!xml)
+ return Status(xml.takeError());
+
+ XMLDocument xml_document;
+
+ if (!xml_document.ParseMemory(xml->c_str(), xml->size())) {
+ error.SetErrorString("Failed to parse memory map xml");
+ return error;
+ }
+
+ XMLNode map_node = xml_document.GetRootElement("memory-map");
+ if (!map_node) {
+ error.SetErrorString("Invalid root node in memory map xml");
+ return error;
+ }
+
+ m_qXfer_memory_map.clear();
+
+ map_node.ForEachChildElement([this](const XMLNode &memory_node) -> bool {
+ if (!memory_node.IsElement())
+ return true;
+ if (memory_node.GetName() != "memory")
+ return true;
+ auto type = memory_node.GetAttributeValue("type", "");
+ uint64_t start;
+ uint64_t length;
+ if (!memory_node.GetAttributeValueAsUnsigned("start", start))
+ return true;
+ if (!memory_node.GetAttributeValueAsUnsigned("length", length))
+ return true;
+ MemoryRegionInfo region;
+ region.GetRange().SetRangeBase(start);
+ region.GetRange().SetByteSize(length);
+ if (type == "rom") {
+ region.SetReadable(MemoryRegionInfo::eYes);
+ this->m_qXfer_memory_map.push_back(region);
+ } else if (type == "ram") {
+ region.SetReadable(MemoryRegionInfo::eYes);
+ region.SetWritable(MemoryRegionInfo::eYes);
+ this->m_qXfer_memory_map.push_back(region);
+ } else if (type == "flash") {
+ region.SetFlash(MemoryRegionInfo::eYes);
+ memory_node.ForEachChildElement(
+ [&region](const XMLNode &prop_node) -> bool {
+ if (!prop_node.IsElement())
+ return true;
+ if (prop_node.GetName() != "property")
+ return true;
+ auto propname = prop_node.GetAttributeValue("name", "");
+ if (propname == "blocksize") {
+ uint64_t blocksize;
+ if (prop_node.GetElementTextAsUnsigned(blocksize))
+ region.SetBlocksize(blocksize);
+ }
+ return true;
+ });
+ this->m_qXfer_memory_map.push_back(region);
+ }
+ return true;
+ });
+
+ m_qXfer_memory_map_loaded = true;
+
+ return error;
+}
+
+std::optional<uint32_t> GDBRemoteCommunicationClient::GetWatchpointSlotCount() {
+ if (m_supports_watchpoint_support_info == eLazyBoolYes) {
+ return m_num_supported_hardware_watchpoints;
+ }
+
+ std::optional<uint32_t> num;
+ if (m_supports_watchpoint_support_info != eLazyBoolNo) {
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qWatchpointSupportInfo:", response) ==
+ PacketResult::Success) {
+ m_supports_watchpoint_support_info = eLazyBoolYes;
+ llvm::StringRef name;
+ llvm::StringRef value;
+ while (response.GetNameColonValue(name, value)) {
+ if (name == "num") {
+ value.getAsInteger(0, m_num_supported_hardware_watchpoints);
+ num = m_num_supported_hardware_watchpoints;
+ }
+ }
+ if (!num) {
+ m_supports_watchpoint_support_info = eLazyBoolNo;
+ }
+ } else {
+ m_supports_watchpoint_support_info = eLazyBoolNo;
+ }
+ }
+
+ return num;
+}
+
+WatchpointHardwareFeature
+GDBRemoteCommunicationClient::GetSupportedWatchpointTypes() {
+ return m_watchpoint_types;
+}
+
+std::optional<bool> GDBRemoteCommunicationClient::GetWatchpointReportedAfter() {
+ if (m_qHostInfo_is_valid == eLazyBoolCalculate)
+ GetHostInfo();
+
+ // Process determines this by target CPU, but allow for the
+ // remote stub to override it via the qHostInfo
+ // watchpoint_exceptions_received key, if it is present.
+ if (m_qHostInfo_is_valid == eLazyBoolYes) {
+ if (m_watchpoints_trigger_after_instruction == eLazyBoolNo)
+ return false;
+ if (m_watchpoints_trigger_after_instruction == eLazyBoolYes)
+ return true;
+ }
+
+ return std::nullopt;
+}
+
+int GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec) {
+ if (file_spec) {
+ std::string path{file_spec.GetPath(false)};
+ StreamString packet;
+ packet.PutCString("QSetSTDIN:");
+ packet.PutStringAsRawHex8(path);
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec) {
+ if (file_spec) {
+ std::string path{file_spec.GetPath(false)};
+ StreamString packet;
+ packet.PutCString("QSetSTDOUT:");
+ packet.PutStringAsRawHex8(path);
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec) {
+ if (file_spec) {
+ std::string path{file_spec.GetPath(false)};
+ StreamString packet;
+ packet.PutCString("QSetSTDERR:");
+ packet.PutStringAsRawHex8(path);
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+bool GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) {
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qGetWorkingDir", response) ==
+ PacketResult::Success) {
+ if (response.IsUnsupportedResponse())
+ return false;
+ if (response.IsErrorResponse())
+ return false;
+ std::string cwd;
+ response.GetHexByteString(cwd);
+ working_dir.SetFile(cwd, GetHostArchitecture().GetTriple());
+ return !cwd.empty();
+ }
+ return false;
+}
+
+int GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir) {
+ if (working_dir) {
+ std::string path{working_dir.GetPath(false)};
+ StreamString packet;
+ packet.PutCString("QSetWorkingDir:");
+ packet.PutStringAsRawHex8(path);
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int GDBRemoteCommunicationClient::SetDisableASLR(bool enable) {
+ char packet[32];
+ const int packet_len =
+ ::snprintf(packet, sizeof(packet), "QSetDisableASLR:%i", enable ? 1 : 0);
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ return -1;
+}
+
+int GDBRemoteCommunicationClient::SetDetachOnError(bool enable) {
+ char packet[32];
+ const int packet_len = ::snprintf(packet, sizeof(packet),
+ "QSetDetachOnError:%i", enable ? 1 : 0);
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ return -1;
+}
+
+bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse(
+ StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) {
+ if (response.IsNormalResponse()) {
+ llvm::StringRef name;
+ llvm::StringRef value;
+ StringExtractor extractor;
+
+ uint32_t cpu = LLDB_INVALID_CPUTYPE;
+ uint32_t sub = 0;
+ std::string vendor;
+ std::string os_type;
+
+ while (response.GetNameColonValue(name, value)) {
+ if (name == "pid") {
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ value.getAsInteger(0, pid);
+ process_info.SetProcessID(pid);
+ } else if (name == "ppid") {
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ value.getAsInteger(0, pid);
+ process_info.SetParentProcessID(pid);
+ } else if (name == "uid") {
+ uint32_t uid = UINT32_MAX;
+ value.getAsInteger(0, uid);
+ process_info.SetUserID(uid);
+ } else if (name == "euid") {
+ uint32_t uid = UINT32_MAX;
+ value.getAsInteger(0, uid);
+ process_info.SetEffectiveUserID(uid);
+ } else if (name == "gid") {
+ uint32_t gid = UINT32_MAX;
+ value.getAsInteger(0, gid);
+ process_info.SetGroupID(gid);
+ } else if (name == "egid") {
+ uint32_t gid = UINT32_MAX;
+ value.getAsInteger(0, gid);
+ process_info.SetEffectiveGroupID(gid);
+ } else if (name == "triple") {
+ StringExtractor extractor(value);
+ std::string triple;
+ extractor.GetHexByteString(triple);
+ process_info.GetArchitecture().SetTriple(triple.c_str());
+ } else if (name == "name") {
+ StringExtractor extractor(value);
+ // The process name from ASCII hex bytes since we can't control the
+ // characters in a process name
+ std::string name;
+ extractor.GetHexByteString(name);
+ process_info.GetExecutableFile().SetFile(name, FileSpec::Style::native);
+ } else if (name == "args") {
+ llvm::StringRef encoded_args(value), hex_arg;
+
+ bool is_arg0 = true;
+ while (!encoded_args.empty()) {
+ std::tie(hex_arg, encoded_args) = encoded_args.split('-');
+ std::string arg;
+ StringExtractor extractor(hex_arg);
+ if (extractor.GetHexByteString(arg) * 2 != hex_arg.size()) {
+ // In case of wrong encoding, we discard all the arguments
+ process_info.GetArguments().Clear();
+ process_info.SetArg0("");
+ break;
+ }
+ if (is_arg0)
+ process_info.SetArg0(arg);
+ else
+ process_info.GetArguments().AppendArgument(arg);
+ is_arg0 = false;
+ }
+ } else if (name == "cputype") {
+ value.getAsInteger(0, cpu);
+ } else if (name == "cpusubtype") {
+ value.getAsInteger(0, sub);
+ } else if (name == "vendor") {
+ vendor = std::string(value);
+ } else if (name == "ostype") {
+ os_type = std::string(value);
+ }
+ }
+
+ if (cpu != LLDB_INVALID_CPUTYPE && !vendor.empty() && !os_type.empty()) {
+ if (vendor == "apple") {
+ process_info.GetArchitecture().SetArchitecture(eArchTypeMachO, cpu,
+ sub);
+ process_info.GetArchitecture().GetTriple().setVendorName(
+ llvm::StringRef(vendor));
+ process_info.GetArchitecture().GetTriple().setOSName(
+ llvm::StringRef(os_type));
+ }
+ }
+
+ if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ return true;
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationClient::GetProcessInfo(
+ lldb::pid_t pid, ProcessInstanceInfo &process_info) {
+ process_info.Clear();
+
+ if (m_supports_qProcessInfoPID) {
+ char packet[32];
+ const int packet_len =
+ ::snprintf(packet, sizeof(packet), "qProcessInfoPID:%" PRIu64, pid);
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, response) ==
+ PacketResult::Success) {
+ return DecodeProcessInfoResponse(response, process_info);
+ } else {
+ m_supports_qProcessInfoPID = false;
+ return false;
+ }
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) {
+ Log *log(GetLog(GDBRLog::Process | GDBRLog::Packets));
+
+ if (allow_lazy) {
+ if (m_qProcessInfo_is_valid == eLazyBoolYes)
+ return true;
+ if (m_qProcessInfo_is_valid == eLazyBoolNo)
+ return false;
+ }
+
+ GetHostInfo();
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qProcessInfo", response) ==
+ PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ llvm::StringRef name;
+ llvm::StringRef value;
+ uint32_t cpu = LLDB_INVALID_CPUTYPE;
+ uint32_t sub = 0;
+ std::string arch_name;
+ std::string os_name;
+ std::string environment;
+ std::string vendor_name;
+ std::string triple;
+ std::string elf_abi;
+ uint32_t pointer_byte_size = 0;
+ StringExtractor extractor;
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t num_keys_decoded = 0;
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ while (response.GetNameColonValue(name, value)) {
+ if (name == "cputype") {
+ if (!value.getAsInteger(16, cpu))
+ ++num_keys_decoded;
+ } else if (name == "cpusubtype") {
+ if (!value.getAsInteger(16, sub)) {
+ ++num_keys_decoded;
+ // Workaround for pre-2024 Apple debugserver, which always
+ // returns arm64e on arm64e-capable hardware regardless of
+ // what the process is. This can be deleted at some point
+ // in the future.
+ if (cpu == llvm::MachO::CPU_TYPE_ARM64 &&
+ sub == llvm::MachO::CPU_SUBTYPE_ARM64E) {
+ if (GetGDBServerVersion())
+ if (m_gdb_server_version >= 1000 &&
+ m_gdb_server_version <= 1504)
+ sub = 0;
+ }
+ }
+ } else if (name == "triple") {
+ StringExtractor extractor(value);
+ extractor.GetHexByteString(triple);
+ ++num_keys_decoded;
+ } else if (name == "ostype") {
+ ParseOSType(value, os_name, environment);
+ ++num_keys_decoded;
+ } else if (name == "vendor") {
+ vendor_name = std::string(value);
+ ++num_keys_decoded;
+ } else if (name == "endian") {
+ byte_order = llvm::StringSwitch<lldb::ByteOrder>(value)
+ .Case("little", eByteOrderLittle)
+ .Case("big", eByteOrderBig)
+ .Case("pdp", eByteOrderPDP)
+ .Default(eByteOrderInvalid);
+ if (byte_order != eByteOrderInvalid)
+ ++num_keys_decoded;
+ } else if (name == "ptrsize") {
+ if (!value.getAsInteger(16, pointer_byte_size))
+ ++num_keys_decoded;
+ } else if (name == "pid") {
+ if (!value.getAsInteger(16, pid))
+ ++num_keys_decoded;
+ } else if (name == "elf_abi") {
+ elf_abi = std::string(value);
+ ++num_keys_decoded;
+ } else if (name == "main-binary-uuid") {
+ m_process_standalone_uuid.SetFromStringRef(value);
+ ++num_keys_decoded;
+ } else if (name == "main-binary-slide") {
+ StringExtractor extractor(value);
+ m_process_standalone_value =
+ extractor.GetU64(LLDB_INVALID_ADDRESS, 16);
+ if (m_process_standalone_value != LLDB_INVALID_ADDRESS) {
+ m_process_standalone_value_is_offset = true;
+ ++num_keys_decoded;
+ }
+ } else if (name == "main-binary-address") {
+ StringExtractor extractor(value);
+ m_process_standalone_value =
+ extractor.GetU64(LLDB_INVALID_ADDRESS, 16);
+ if (m_process_standalone_value != LLDB_INVALID_ADDRESS) {
+ m_process_standalone_value_is_offset = false;
+ ++num_keys_decoded;
+ }
+ } else if (name == "binary-addresses") {
+ m_binary_addresses.clear();
+ ++num_keys_decoded;
+ for (llvm::StringRef x : llvm::split(value, ',')) {
+ addr_t vmaddr;
+ x.consume_front("0x");
+ if (llvm::to_integer(x, vmaddr, 16))
+ m_binary_addresses.push_back(vmaddr);
+ }
+ }
+ }
+ if (num_keys_decoded > 0)
+ m_qProcessInfo_is_valid = eLazyBoolYes;
+ if (pid != LLDB_INVALID_PROCESS_ID) {
+ m_curr_pid_is_valid = eLazyBoolYes;
+ m_curr_pid_run = m_curr_pid = pid;
+ }
+
+ // Set the ArchSpec from the triple if we have it.
+ if (!triple.empty()) {
+ m_process_arch.SetTriple(triple.c_str());
+ m_process_arch.SetFlags(elf_abi);
+ if (pointer_byte_size) {
+ assert(pointer_byte_size == m_process_arch.GetAddressByteSize());
+ }
+ } else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() &&
+ !vendor_name.empty()) {
+ llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name);
+ if (!environment.empty())
+ triple.setEnvironmentName(environment);
+
+ assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat);
+ assert(triple.getObjectFormat() != llvm::Triple::Wasm);
+ assert(triple.getObjectFormat() != llvm::Triple::XCOFF);
+ switch (triple.getObjectFormat()) {
+ case llvm::Triple::MachO:
+ m_process_arch.SetArchitecture(eArchTypeMachO, cpu, sub);
+ break;
+ case llvm::Triple::ELF:
+ m_process_arch.SetArchitecture(eArchTypeELF, cpu, sub);
+ break;
+ case llvm::Triple::COFF:
+ m_process_arch.SetArchitecture(eArchTypeCOFF, cpu, sub);
+ break;
+ case llvm::Triple::GOFF:
+ case llvm::Triple::SPIRV:
+ case llvm::Triple::Wasm:
+ case llvm::Triple::XCOFF:
+ case llvm::Triple::DXContainer:
+ LLDB_LOGF(log, "error: not supported target architecture");
+ return false;
+ case llvm::Triple::UnknownObjectFormat:
+ LLDB_LOGF(log, "error: failed to determine target architecture");
+ return false;
+ }
+
+ if (pointer_byte_size) {
+ assert(pointer_byte_size == m_process_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid) {
+ assert(byte_order == m_process_arch.GetByteOrder());
+ }
+ m_process_arch.GetTriple().setVendorName(llvm::StringRef(vendor_name));
+ m_process_arch.GetTriple().setOSName(llvm::StringRef(os_name));
+ m_process_arch.GetTriple().setEnvironmentName(llvm::StringRef(environment));
+ }
+ return true;
+ }
+ } else {
+ m_qProcessInfo_is_valid = eLazyBoolNo;
+ }
+
+ return false;
+}
+
+uint32_t GDBRemoteCommunicationClient::FindProcesses(
+ const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos) {
+ process_infos.clear();
+
+ if (m_supports_qfProcessInfo) {
+ StreamString packet;
+ packet.PutCString("qfProcessInfo");
+ if (!match_info.MatchAllProcesses()) {
+ packet.PutChar(':');
+ const char *name = match_info.GetProcessInfo().GetName();
+ bool has_name_match = false;
+ if (name && name[0]) {
+ has_name_match = true;
+ NameMatch name_match_type = match_info.GetNameMatchType();
+ switch (name_match_type) {
+ case NameMatch::Ignore:
+ has_name_match = false;
+ break;
+
+ case NameMatch::Equals:
+ packet.PutCString("name_match:equals;");
+ break;
+
+ case NameMatch::Contains:
+ packet.PutCString("name_match:contains;");
+ break;
+
+ case NameMatch::StartsWith:
+ packet.PutCString("name_match:starts_with;");
+ break;
+
+ case NameMatch::EndsWith:
+ packet.PutCString("name_match:ends_with;");
+ break;
+
+ case NameMatch::RegularExpression:
+ packet.PutCString("name_match:regex;");
+ break;
+ }
+ if (has_name_match) {
+ packet.PutCString("name:");
+ packet.PutBytesAsRawHex8(name, ::strlen(name));
+ packet.PutChar(';');
+ }
+ }
+
+ if (match_info.GetProcessInfo().ProcessIDIsValid())
+ packet.Printf("pid:%" PRIu64 ";",
+ match_info.GetProcessInfo().GetProcessID());
+ if (match_info.GetProcessInfo().ParentProcessIDIsValid())
+ packet.Printf("parent_pid:%" PRIu64 ";",
+ match_info.GetProcessInfo().GetParentProcessID());
+ if (match_info.GetProcessInfo().UserIDIsValid())
+ packet.Printf("uid:%u;", match_info.GetProcessInfo().GetUserID());
+ if (match_info.GetProcessInfo().GroupIDIsValid())
+ packet.Printf("gid:%u;", match_info.GetProcessInfo().GetGroupID());
+ if (match_info.GetProcessInfo().EffectiveUserIDIsValid())
+ packet.Printf("euid:%u;",
+ match_info.GetProcessInfo().GetEffectiveUserID());
+ if (match_info.GetProcessInfo().EffectiveGroupIDIsValid())
+ packet.Printf("egid:%u;",
+ match_info.GetProcessInfo().GetEffectiveGroupID());
+ packet.Printf("all_users:%u;", match_info.GetMatchAllUsers() ? 1 : 0);
+ if (match_info.GetProcessInfo().GetArchitecture().IsValid()) {
+ const ArchSpec &match_arch =
+ match_info.GetProcessInfo().GetArchitecture();
+ const llvm::Triple &triple = match_arch.GetTriple();
+ packet.PutCString("triple:");
+ packet.PutCString(triple.getTriple());
+ packet.PutChar(';');
+ }
+ }
+ StringExtractorGDBRemote response;
+ // Increase timeout as the first qfProcessInfo packet takes a long time on
+ // Android. The value of 1min was arrived at empirically.
+ ScopedTimeout timeout(*this, minutes(1));
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success) {
+ do {
+ ProcessInstanceInfo process_info;
+ if (!DecodeProcessInfoResponse(response, process_info))
+ break;
+ process_infos.push_back(process_info);
+ response = StringExtractorGDBRemote();
+ } while (SendPacketAndWaitForResponse("qsProcessInfo", response) ==
+ PacketResult::Success);
+ } else {
+ m_supports_qfProcessInfo = false;
+ return 0;
+ }
+ }
+ return process_infos.size();
+}
+
+bool GDBRemoteCommunicationClient::GetUserName(uint32_t uid,
+ std::string &name) {
+ if (m_supports_qUserName) {
+ char packet[32];
+ const int packet_len =
+ ::snprintf(packet, sizeof(packet), "qUserName:%i", uid);
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, response) ==
+ PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ // Make sure we parsed the right number of characters. The response is
+ // the hex encoded user name and should make up the entire packet. If
+ // there are any non-hex ASCII bytes, the length won't match below..
+ if (response.GetHexByteString(name) * 2 ==
+ response.GetStringRef().size())
+ return true;
+ }
+ } else {
+ m_supports_qUserName = false;
+ return false;
+ }
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationClient::GetGroupName(uint32_t gid,
+ std::string &name) {
+ if (m_supports_qGroupName) {
+ char packet[32];
+ const int packet_len =
+ ::snprintf(packet, sizeof(packet), "qGroupName:%i", gid);
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, response) ==
+ PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ // Make sure we parsed the right number of characters. The response is
+ // the hex encoded group name and should make up the entire packet. If
+ // there are any non-hex ASCII bytes, the length won't match below..
+ if (response.GetHexByteString(name) * 2 ==
+ response.GetStringRef().size())
+ return true;
+ }
+ } else {
+ m_supports_qGroupName = false;
+ return false;
+ }
+ }
+ return false;
+}
+
+static void MakeSpeedTestPacket(StreamString &packet, uint32_t send_size,
+ uint32_t recv_size) {
+ packet.Clear();
+ packet.Printf("qSpeedTest:response_size:%i;data:", recv_size);
+ uint32_t bytes_left = send_size;
+ while (bytes_left > 0) {
+ if (bytes_left >= 26) {
+ packet.PutCString("abcdefghijklmnopqrstuvwxyz");
+ bytes_left -= 26;
+ } else {
+ packet.Printf("%*.*s;", bytes_left, bytes_left,
+ "abcdefghijklmnopqrstuvwxyz");
+ bytes_left = 0;
+ }
+ }
+}
+
+duration<float>
+calculate_standard_deviation(const std::vector<duration<float>> &v) {
+ if (v.size() == 0)
+ return duration<float>::zero();
+ using Dur = duration<float>;
+ Dur sum = std::accumulate(std::begin(v), std::end(v), Dur());
+ Dur mean = sum / v.size();
+ float accum = 0;
+ for (auto d : v) {
+ float delta = (d - mean).count();
+ accum += delta * delta;
+ };
+
+ return Dur(sqrtf(accum / (v.size() - 1)));
+}
+
+void GDBRemoteCommunicationClient::TestPacketSpeed(const uint32_t num_packets,
+ uint32_t max_send,
+ uint32_t max_recv,
+ uint64_t recv_amount,
+ bool json, Stream &strm) {
+
+ if (SendSpeedTestPacket(0, 0)) {
+ StreamString packet;
+ if (json)
+ strm.Printf("{ \"packet_speeds\" : {\n \"num_packets\" : %u,\n "
+ "\"results\" : [",
+ num_packets);
+ else
+ strm.Printf("Testing sending %u packets of various sizes:\n",
+ num_packets);
+ strm.Flush();
+
+ uint32_t result_idx = 0;
+ uint32_t send_size;
+ std::vector<duration<float>> packet_times;
+
+ for (send_size = 0; send_size <= max_send;
+ send_size ? send_size *= 2 : send_size = 4) {
+ for (uint32_t recv_size = 0; recv_size <= max_recv;
+ recv_size ? recv_size *= 2 : recv_size = 4) {
+ MakeSpeedTestPacket(packet, send_size, recv_size);
+
+ packet_times.clear();
+ // Test how long it takes to send 'num_packets' packets
+ const auto start_time = steady_clock::now();
+ for (uint32_t i = 0; i < num_packets; ++i) {
+ const auto packet_start_time = steady_clock::now();
+ StringExtractorGDBRemote response;
+ SendPacketAndWaitForResponse(packet.GetString(), response);
+ const auto packet_end_time = steady_clock::now();
+ packet_times.push_back(packet_end_time - packet_start_time);
+ }
+ const auto end_time = steady_clock::now();
+ const auto total_time = end_time - start_time;
+
+ float packets_per_second =
+ ((float)num_packets) / duration<float>(total_time).count();
+ auto average_per_packet = num_packets > 0 ? total_time / num_packets
+ : duration<float>::zero();
+ const duration<float> standard_deviation =
+ calculate_standard_deviation(packet_times);
+ if (json) {
+ strm.Format("{0}\n {{\"send_size\" : {1,6}, \"recv_size\" : "
+ "{2,6}, \"total_time_nsec\" : {3,12:ns-}, "
+ "\"standard_deviation_nsec\" : {4,9:ns-f0}}",
+ result_idx > 0 ? "," : "", send_size, recv_size,
+ total_time, standard_deviation);
+ ++result_idx;
+ } else {
+ strm.Format("qSpeedTest(send={0,7}, recv={1,7}) in {2:s+f9} for "
+ "{3,9:f2} packets/s ({4,10:ms+f6} per packet) with "
+ "standard deviation of {5,10:ms+f6}\n",
+ send_size, recv_size, duration<float>(total_time),
+ packets_per_second, duration<float>(average_per_packet),
+ standard_deviation);
+ }
+ strm.Flush();
+ }
+ }
+
+ const float k_recv_amount_mb = (float)recv_amount / (1024.0f * 1024.0f);
+ if (json)
+ strm.Printf("\n ]\n },\n \"download_speed\" : {\n \"byte_size\" "
+ ": %" PRIu64 ",\n \"results\" : [",
+ recv_amount);
+ else
+ strm.Printf("Testing receiving %2.1fMB of data using varying receive "
+ "packet sizes:\n",
+ k_recv_amount_mb);
+ strm.Flush();
+ send_size = 0;
+ result_idx = 0;
+ for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2) {
+ MakeSpeedTestPacket(packet, send_size, recv_size);
+
+ // If we have a receive size, test how long it takes to receive 4MB of
+ // data
+ if (recv_size > 0) {
+ const auto start_time = steady_clock::now();
+ uint32_t bytes_read = 0;
+ uint32_t packet_count = 0;
+ while (bytes_read < recv_amount) {
+ StringExtractorGDBRemote response;
+ SendPacketAndWaitForResponse(packet.GetString(), response);
+ bytes_read += recv_size;
+ ++packet_count;
+ }
+ const auto end_time = steady_clock::now();
+ const auto total_time = end_time - start_time;
+ float mb_second = ((float)recv_amount) /
+ duration<float>(total_time).count() /
+ (1024.0 * 1024.0);
+ float packets_per_second =
+ ((float)packet_count) / duration<float>(total_time).count();
+ const auto average_per_packet = packet_count > 0
+ ? total_time / packet_count
+ : duration<float>::zero();
+
+ if (json) {
+ strm.Format("{0}\n {{\"send_size\" : {1,6}, \"recv_size\" : "
+ "{2,6}, \"total_time_nsec\" : {3,12:ns-}}",
+ result_idx > 0 ? "," : "", send_size, recv_size,
+ total_time);
+ ++result_idx;
+ } else {
+ strm.Format("qSpeedTest(send={0,7}, recv={1,7}) {2,6} packets needed "
+ "to receive {3:f1}MB in {4:s+f9} for {5} MB/sec for "
+ "{6,9:f2} packets/sec ({7,10:ms+f6} per packet)\n",
+ send_size, recv_size, packet_count, k_recv_amount_mb,
+ duration<float>(total_time), mb_second,
+ packets_per_second, duration<float>(average_per_packet));
+ }
+ strm.Flush();
+ }
+ }
+ if (json)
+ strm.Printf("\n ]\n }\n}\n");
+ else
+ strm.EOL();
+ }
+}
+
+bool GDBRemoteCommunicationClient::SendSpeedTestPacket(uint32_t send_size,
+ uint32_t recv_size) {
+ StreamString packet;
+ packet.Printf("qSpeedTest:response_size:%i;data:", recv_size);
+ uint32_t bytes_left = send_size;
+ while (bytes_left > 0) {
+ if (bytes_left >= 26) {
+ packet.PutCString("abcdefghijklmnopqrstuvwxyz");
+ bytes_left -= 26;
+ } else {
+ packet.Printf("%*.*s;", bytes_left, bytes_left,
+ "abcdefghijklmnopqrstuvwxyz");
+ bytes_left = 0;
+ }
+ }
+
+ StringExtractorGDBRemote response;
+ return SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success;
+}
+
+bool GDBRemoteCommunicationClient::LaunchGDBServer(
+ const char *remote_accept_hostname, lldb::pid_t &pid, uint16_t &port,
+ std::string &socket_name) {
+ pid = LLDB_INVALID_PROCESS_ID;
+ port = 0;
+ socket_name.clear();
+
+ StringExtractorGDBRemote response;
+ StreamString stream;
+ stream.PutCString("qLaunchGDBServer;");
+ std::string hostname;
+ if (remote_accept_hostname && remote_accept_hostname[0])
+ hostname = remote_accept_hostname;
+ else {
+ if (HostInfo::GetHostname(hostname)) {
+ // Make the GDB server we launch only accept connections from this host
+ stream.Printf("host:%s;", hostname.c_str());
+ } else {
+ // Make the GDB server we launch accept connections from any host since
+ // we can't figure out the hostname
+ stream.Printf("host:*;");
+ }
+ }
+ // give the process a few seconds to startup
+ ScopedTimeout timeout(*this, seconds(10));
+
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.IsErrorResponse())
+ return false;
+
+ llvm::StringRef name;
+ llvm::StringRef value;
+ while (response.GetNameColonValue(name, value)) {
+ if (name == "port")
+ value.getAsInteger(0, port);
+ else if (name == "pid")
+ value.getAsInteger(0, pid);
+ else if (name.compare("socket_name") == 0) {
+ StringExtractor extractor(value);
+ extractor.GetHexByteString(socket_name);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+size_t GDBRemoteCommunicationClient::QueryGDBServer(
+ std::vector<std::pair<uint16_t, std::string>> &connection_urls) {
+ connection_urls.clear();
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qQueryGDBServer", response) !=
+ PacketResult::Success)
+ return 0;
+
+ StructuredData::ObjectSP data =
+ StructuredData::ParseJSON(response.GetStringRef());
+ if (!data)
+ return 0;
+
+ StructuredData::Array *array = data->GetAsArray();
+ if (!array)
+ return 0;
+
+ for (size_t i = 0, count = array->GetSize(); i < count; ++i) {
+ std::optional<StructuredData::Dictionary *> maybe_element =
+ array->GetItemAtIndexAsDictionary(i);
+ if (!maybe_element)
+ continue;
+
+ StructuredData::Dictionary *element = *maybe_element;
+ uint16_t port = 0;
+ if (StructuredData::ObjectSP port_osp =
+ element->GetValueForKey(llvm::StringRef("port")))
+ port = port_osp->GetUnsignedIntegerValue(0);
+
+ std::string socket_name;
+ if (StructuredData::ObjectSP socket_name_osp =
+ element->GetValueForKey(llvm::StringRef("socket_name")))
+ socket_name = std::string(socket_name_osp->GetStringValue());
+
+ if (port != 0 || !socket_name.empty())
+ connection_urls.emplace_back(port, socket_name);
+ }
+ return connection_urls.size();
+}
+
+bool GDBRemoteCommunicationClient::KillSpawnedProcess(lldb::pid_t pid) {
+ StreamString stream;
+ stream.Printf("qKillSpawnedProcess:%" PRId64, pid);
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ return true;
+ }
+ return false;
+}
+
+std::optional<PidTid> GDBRemoteCommunicationClient::SendSetCurrentThreadPacket(
+ uint64_t tid, uint64_t pid, char op) {
+ lldb_private::StreamString packet;
+ packet.PutChar('H');
+ packet.PutChar(op);
+
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ packet.Printf("p%" PRIx64 ".", pid);
+
+ if (tid == UINT64_MAX)
+ packet.PutCString("-1");
+ else
+ packet.Printf("%" PRIx64, tid);
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse())
+ return {{pid, tid}};
+
+ /*
+ * Connected bare-iron target (like YAMON gdb-stub) may not have support for
+ * Hg packet.
+ * The reply from '?' packet could be as simple as 'S05'. There is no packet
+ * which can
+ * give us pid and/or tid. Assume pid=tid=1 in such cases.
+ */
+ if (response.IsUnsupportedResponse() && IsConnected())
+ return {{1, 1}};
+ }
+ return std::nullopt;
+}
+
+bool GDBRemoteCommunicationClient::SetCurrentThread(uint64_t tid,
+ uint64_t pid) {
+ if (m_curr_tid == tid &&
+ (m_curr_pid == pid || LLDB_INVALID_PROCESS_ID == pid))
+ return true;
+
+ std::optional<PidTid> ret = SendSetCurrentThreadPacket(tid, pid, 'g');
+ if (ret) {
+ if (ret->pid != LLDB_INVALID_PROCESS_ID)
+ m_curr_pid = ret->pid;
+ m_curr_tid = ret->tid;
+ }
+ return ret.has_value();
+}
+
+bool GDBRemoteCommunicationClient::SetCurrentThreadForRun(uint64_t tid,
+ uint64_t pid) {
+ if (m_curr_tid_run == tid &&
+ (m_curr_pid_run == pid || LLDB_INVALID_PROCESS_ID == pid))
+ return true;
+
+ std::optional<PidTid> ret = SendSetCurrentThreadPacket(tid, pid, 'c');
+ if (ret) {
+ if (ret->pid != LLDB_INVALID_PROCESS_ID)
+ m_curr_pid_run = ret->pid;
+ m_curr_tid_run = ret->tid;
+ }
+ return ret.has_value();
+}
+
+bool GDBRemoteCommunicationClient::GetStopReply(
+ StringExtractorGDBRemote &response) {
+ if (SendPacketAndWaitForResponse("?", response) == PacketResult::Success)
+ return response.IsNormalResponse();
+ return false;
+}
+
+bool GDBRemoteCommunicationClient::GetThreadStopInfo(
+ lldb::tid_t tid, StringExtractorGDBRemote &response) {
+ if (m_supports_qThreadStopInfo) {
+ char packet[256];
+ int packet_len =
+ ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid);
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ if (SendPacketAndWaitForResponse(packet, response) ==
+ PacketResult::Success) {
+ if (response.IsUnsupportedResponse())
+ m_supports_qThreadStopInfo = false;
+ else if (response.IsNormalResponse())
+ return true;
+ else
+ return false;
+ } else {
+ m_supports_qThreadStopInfo = false;
+ }
+ }
+ return false;
+}
+
+uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket(
+ GDBStoppointType type, bool insert, addr_t addr, uint32_t length,
+ std::chrono::seconds timeout) {
+ Log *log = GetLog(LLDBLog::Breakpoints);
+ LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64,
+ __FUNCTION__, insert ? "add" : "remove", addr);
+
+ // Check if the stub is known not to support this breakpoint type
+ if (!SupportsGDBStoppointPacket(type))
+ return UINT8_MAX;
+ // Construct the breakpoint packet
+ char packet[64];
+ const int packet_len =
+ ::snprintf(packet, sizeof(packet), "%c%i,%" PRIx64 ",%x",
+ insert ? 'Z' : 'z', type, addr, length);
+ // Check we haven't overwritten the end of the packet buffer
+ assert(packet_len + 1 < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ // Make sure the response is either "OK", "EXX" where XX are two hex digits,
+ // or "" (unsupported)
+ response.SetResponseValidatorToOKErrorNotSupported();
+ // Try to send the breakpoint packet, and check that it was correctly sent
+ if (SendPacketAndWaitForResponse(packet, response, timeout) ==
+ PacketResult::Success) {
+ // Receive and OK packet when the breakpoint successfully placed
+ if (response.IsOKResponse())
+ return 0;
+
+ // Status while setting breakpoint, send back specific error
+ if (response.IsErrorResponse())
+ return response.GetError();
+
+ // Empty packet informs us that breakpoint is not supported
+ if (response.IsUnsupportedResponse()) {
+ // Disable this breakpoint type since it is unsupported
+ switch (type) {
+ case eBreakpointSoftware:
+ m_supports_z0 = false;
+ break;
+ case eBreakpointHardware:
+ m_supports_z1 = false;
+ break;
+ case eWatchpointWrite:
+ m_supports_z2 = false;
+ break;
+ case eWatchpointRead:
+ m_supports_z3 = false;
+ break;
+ case eWatchpointReadWrite:
+ m_supports_z4 = false;
+ break;
+ case eStoppointInvalid:
+ return UINT8_MAX;
+ }
+ }
+ }
+ // Signal generic failure
+ return UINT8_MAX;
+}
+
+std::vector<std::pair<lldb::pid_t, lldb::tid_t>>
+GDBRemoteCommunicationClient::GetCurrentProcessAndThreadIDs(
+ bool &sequence_mutex_unavailable) {
+ std::vector<std::pair<lldb::pid_t, lldb::tid_t>> ids;
+
+ Lock lock(*this);
+ if (lock) {
+ sequence_mutex_unavailable = false;
+ StringExtractorGDBRemote response;
+
+ PacketResult packet_result;
+ for (packet_result =
+ SendPacketAndWaitForResponseNoLock("qfThreadInfo", response);
+ packet_result == PacketResult::Success && response.IsNormalResponse();
+ packet_result =
+ SendPacketAndWaitForResponseNoLock("qsThreadInfo", response)) {
+ char ch = response.GetChar();
+ if (ch == 'l')
+ break;
+ if (ch == 'm') {
+ do {
+ auto pid_tid = response.GetPidTid(LLDB_INVALID_PROCESS_ID);
+ // If we get an invalid response, break out of the loop.
+ // If there are valid tids, they have been added to ids.
+ // If there are no valid tids, we'll fall through to the
+ // bare-iron target handling below.
+ if (!pid_tid)
+ break;
+
+ ids.push_back(*pid_tid);
+ ch = response.GetChar(); // Skip the command separator
+ } while (ch == ','); // Make sure we got a comma separator
+ }
+ }
+
+ /*
+ * Connected bare-iron target (like YAMON gdb-stub) may not have support for
+ * qProcessInfo, qC and qfThreadInfo packets. The reply from '?' packet
+ * could
+ * be as simple as 'S05'. There is no packet which can give us pid and/or
+ * tid.
+ * Assume pid=tid=1 in such cases.
+ */
+ if ((response.IsUnsupportedResponse() || response.IsNormalResponse()) &&
+ ids.size() == 0 && IsConnected()) {
+ ids.emplace_back(1, 1);
+ }
+ } else {
+ Log *log(GetLog(GDBRLog::Process | GDBRLog::Packets));
+ LLDB_LOG(log, "error: failed to get packet sequence mutex, not sending "
+ "packet 'qfThreadInfo'");
+ sequence_mutex_unavailable = true;
+ }
+
+ return ids;
+}
+
+size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs(
+ std::vector<lldb::tid_t> &thread_ids, bool &sequence_mutex_unavailable) {
+ lldb::pid_t pid = GetCurrentProcessID();
+ thread_ids.clear();
+
+ auto ids = GetCurrentProcessAndThreadIDs(sequence_mutex_unavailable);
+ if (ids.empty() || sequence_mutex_unavailable)
+ return 0;
+
+ for (auto id : ids) {
+ // skip threads that do not belong to the current process
+ if (id.first != LLDB_INVALID_PROCESS_ID && id.first != pid)
+ continue;
+ if (id.second != LLDB_INVALID_THREAD_ID &&
+ id.second != StringExtractorGDBRemote::AllThreads)
+ thread_ids.push_back(id.second);
+ }
+
+ return thread_ids.size();
+}
+
+lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() {
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qShlibInfoAddr", response) !=
+ PacketResult::Success ||
+ !response.IsNormalResponse())
+ return LLDB_INVALID_ADDRESS;
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+}
+
+lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand(
+ llvm::StringRef command,
+ const FileSpec &
+ working_dir, // Pass empty FileSpec to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the
+ // process to exit
+ std::string
+ *command_output, // Pass NULL if you don't want the command output
+ const Timeout<std::micro> &timeout) {
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_shell:");
+ stream.PutBytesAsRawHex8(command.data(), command.size());
+ stream.PutChar(',');
+ uint32_t timeout_sec = UINT32_MAX;
+ if (timeout) {
+ // TODO: Use chrono version of std::ceil once c++17 is available.
+ timeout_sec = std::ceil(std::chrono::duration<double>(*timeout).count());
+ }
+ stream.PutHex32(timeout_sec);
+ if (working_dir) {
+ std::string path{working_dir.GetPath(false)};
+ stream.PutChar(',');
+ stream.PutStringAsRawHex8(path);
+ }
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.GetChar() != 'F')
+ return Status("malformed reply");
+ if (response.GetChar() != ',')
+ return Status("malformed reply");
+ uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX);
+ if (exitcode == UINT32_MAX)
+ return Status("unable to run remote process");
+ else if (status_ptr)
+ *status_ptr = exitcode;
+ if (response.GetChar() != ',')
+ return Status("malformed reply");
+ uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX);
+ if (signo_ptr)
+ *signo_ptr = signo;
+ if (response.GetChar() != ',')
+ return Status("malformed reply");
+ std::string output;
+ response.GetEscapedBinaryData(output);
+ if (command_output)
+ command_output->assign(output);
+ return Status();
+ }
+ return Status("unable to send packet");
+}
+
+Status GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec,
+ uint32_t file_permissions) {
+ std::string path{file_spec.GetPath(false)};
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_mkdir:");
+ stream.PutHex32(file_permissions);
+ stream.PutChar(',');
+ stream.PutStringAsRawHex8(path);
+ llvm::StringRef packet = stream.GetString();
+ StringExtractorGDBRemote response;
+
+ if (SendPacketAndWaitForResponse(packet, response) != PacketResult::Success)
+ return Status("failed to send '%s' packet", packet.str().c_str());
+
+ if (response.GetChar() != 'F')
+ return Status("invalid response to '%s' packet", packet.str().c_str());
+
+ return Status(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);
+}
+
+Status
+GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions) {
+ std::string path{file_spec.GetPath(false)};
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_chmod:");
+ stream.PutHex32(file_permissions);
+ stream.PutChar(',');
+ stream.PutStringAsRawHex8(path);
+ llvm::StringRef packet = stream.GetString();
+ StringExtractorGDBRemote response;
+
+ if (SendPacketAndWaitForResponse(packet, response) != PacketResult::Success)
+ return Status("failed to send '%s' packet", stream.GetData());
+
+ if (response.GetChar() != 'F')
+ return Status("invalid response to '%s' packet", stream.GetData());
+
+ return Status(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);
+}
+
+static int gdb_errno_to_system(int err) {
+ switch (err) {
+#define HANDLE_ERRNO(name, value) \
+ case GDB_##name: \
+ return name;
+#include "Plugins/Process/gdb-remote/GDBRemoteErrno.def"
+ default:
+ return -1;
+ }
+}
+
+static uint64_t ParseHostIOPacketResponse(StringExtractorGDBRemote &response,
+ uint64_t fail_result, Status &error) {
+ response.SetFilePos(0);
+ if (response.GetChar() != 'F')
+ return fail_result;
+ int32_t result = response.GetS32(-2, 16);
+ if (result == -2)
+ return fail_result;
+ if (response.GetChar() == ',') {
+ int result_errno = gdb_errno_to_system(response.GetS32(-1, 16));
+ if (result_errno != -1)
+ error.SetError(result_errno, eErrorTypePOSIX);
+ else
+ error.SetError(-1, eErrorTypeGeneric);
+ } else
+ error.Clear();
+ return result;
+}
+lldb::user_id_t
+GDBRemoteCommunicationClient::OpenFile(const lldb_private::FileSpec &file_spec,
+ File::OpenOptions flags, mode_t mode,
+ Status &error) {
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:open:");
+ if (path.empty())
+ return UINT64_MAX;
+ stream.PutStringAsRawHex8(path);
+ stream.PutChar(',');
+ stream.PutHex32(flags);
+ stream.PutChar(',');
+ stream.PutHex32(mode);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ return ParseHostIOPacketResponse(response, UINT64_MAX, error);
+ }
+ return UINT64_MAX;
+}
+
+bool GDBRemoteCommunicationClient::CloseFile(lldb::user_id_t fd,
+ Status &error) {
+ lldb_private::StreamString stream;
+ stream.Printf("vFile:close:%x", (int)fd);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ return ParseHostIOPacketResponse(response, -1, error) == 0;
+ }
+ return false;
+}
+
+std::optional<GDBRemoteFStatData>
+GDBRemoteCommunicationClient::FStat(lldb::user_id_t fd) {
+ lldb_private::StreamString stream;
+ stream.Printf("vFile:fstat:%" PRIx64, fd);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.GetChar() != 'F')
+ return std::nullopt;
+ int64_t size = response.GetS64(-1, 16);
+ if (size > 0 && response.GetChar() == ';') {
+ std::string buffer;
+ if (response.GetEscapedBinaryData(buffer)) {
+ GDBRemoteFStatData out;
+ if (buffer.size() != sizeof(out))
+ return std::nullopt;
+ memcpy(&out, buffer.data(), sizeof(out));
+ return out;
+ }
+ }
+ }
+ return std::nullopt;
+}
+
+std::optional<GDBRemoteFStatData>
+GDBRemoteCommunicationClient::Stat(const lldb_private::FileSpec &file_spec) {
+ Status error;
+ lldb::user_id_t fd = OpenFile(file_spec, File::eOpenOptionReadOnly, 0, error);
+ if (fd == UINT64_MAX)
+ return std::nullopt;
+ std::optional<GDBRemoteFStatData> st = FStat(fd);
+ CloseFile(fd, error);
+ return st;
+}
+
+// Extension of host I/O packets to get the file size.
+lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize(
+ const lldb_private::FileSpec &file_spec) {
+ if (m_supports_vFileSize) {
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:size:");
+ stream.PutStringAsRawHex8(path);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) !=
+ PacketResult::Success)
+ return UINT64_MAX;
+
+ if (!response.IsUnsupportedResponse()) {
+ if (response.GetChar() != 'F')
+ return UINT64_MAX;
+ uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX);
+ return retcode;
+ }
+ m_supports_vFileSize = false;
+ }
+
+ // Fallback to fstat.
+ std::optional<GDBRemoteFStatData> st = Stat(file_spec);
+ return st ? st->gdb_st_size : UINT64_MAX;
+}
+
+void GDBRemoteCommunicationClient::AutoCompleteDiskFileOrDirectory(
+ CompletionRequest &request, bool only_dir) {
+ lldb_private::StreamString stream;
+ stream.PutCString("qPathComplete:");
+ stream.PutHex32(only_dir ? 1 : 0);
+ stream.PutChar(',');
+ stream.PutStringAsRawHex8(request.GetCursorArgumentPrefix());
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ StreamString strm;
+ char ch = response.GetChar();
+ if (ch != 'M')
+ return;
+ while (response.Peek()) {
+ strm.Clear();
+ while ((ch = response.GetHexU8(0, false)) != '\0')
+ strm.PutChar(ch);
+ request.AddCompletion(strm.GetString());
+ if (response.GetChar() != ',')
+ break;
+ }
+ }
+}
+
+Status
+GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions) {
+ if (m_supports_vFileMode) {
+ std::string path{file_spec.GetPath(false)};
+ Status error;
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:mode:");
+ stream.PutStringAsRawHex8(path);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) !=
+ PacketResult::Success) {
+ error.SetErrorStringWithFormat("failed to send '%s' packet",
+ stream.GetData());
+ return error;
+ }
+ if (!response.IsUnsupportedResponse()) {
+ if (response.GetChar() != 'F') {
+ error.SetErrorStringWithFormat("invalid response to '%s' packet",
+ stream.GetData());
+ } else {
+ const uint32_t mode = response.GetS32(-1, 16);
+ if (static_cast<int32_t>(mode) == -1) {
+ if (response.GetChar() == ',') {
+ int response_errno = gdb_errno_to_system(response.GetS32(-1, 16));
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ else
+ error.SetErrorToGenericError();
+ } else
+ error.SetErrorToGenericError();
+ } else {
+ file_permissions = mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+ }
+ return error;
+ } else { // response.IsUnsupportedResponse()
+ m_supports_vFileMode = false;
+ }
+ }
+
+ // Fallback to fstat.
+ if (std::optional<GDBRemoteFStatData> st = Stat(file_spec)) {
+ file_permissions = st->gdb_st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ return Status();
+ }
+ return Status("fstat failed");
+}
+
+uint64_t GDBRemoteCommunicationClient::ReadFile(lldb::user_id_t fd,
+ uint64_t offset, void *dst,
+ uint64_t dst_len,
+ Status &error) {
+ lldb_private::StreamString stream;
+ stream.Printf("vFile:pread:%x,%" PRIx64 ",%" PRIx64, (int)fd, dst_len,
+ offset);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.GetChar() != 'F')
+ return 0;
+ int64_t retcode = response.GetS64(-1, 16);
+ if (retcode == -1) {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',') {
+ int response_errno = gdb_errno_to_system(response.GetS32(-1, 16));
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ return -1;
+ }
+ const char next = (response.Peek() ? *response.Peek() : 0);
+ if (next == ',')
+ return 0;
+ if (next == ';') {
+ response.GetChar(); // skip the semicolon
+ std::string buffer;
+ if (response.GetEscapedBinaryData(buffer)) {
+ const uint64_t data_to_write =
+ std::min<uint64_t>(dst_len, buffer.size());
+ if (data_to_write > 0)
+ memcpy(dst, &buffer[0], data_to_write);
+ return data_to_write;
+ }
+ }
+ }
+ return 0;
+}
+
+uint64_t GDBRemoteCommunicationClient::WriteFile(lldb::user_id_t fd,
+ uint64_t offset,
+ const void *src,
+ uint64_t src_len,
+ Status &error) {
+ lldb_private::StreamGDBRemote stream;
+ stream.Printf("vFile:pwrite:%x,%" PRIx64 ",", (int)fd, offset);
+ stream.PutEscapedBytes(src, src_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.GetChar() != 'F') {
+ error.SetErrorStringWithFormat("write file failed");
+ return 0;
+ }
+ int64_t bytes_written = response.GetS64(-1, 16);
+ if (bytes_written == -1) {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',') {
+ int response_errno = gdb_errno_to_system(response.GetS32(-1, 16));
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ return -1;
+ }
+ return bytes_written;
+ } else {
+ error.SetErrorString("failed to send vFile:pwrite packet");
+ }
+ return 0;
+}
+
+Status GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src,
+ const FileSpec &dst) {
+ std::string src_path{src.GetPath(false)}, dst_path{dst.GetPath(false)};
+ Status error;
+ lldb_private::StreamGDBRemote stream;
+ stream.PutCString("vFile:symlink:");
+ // the unix symlink() command reverses its parameters where the dst if first,
+ // so we follow suit here
+ stream.PutStringAsRawHex8(dst_path);
+ stream.PutChar(',');
+ stream.PutStringAsRawHex8(src_path);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.GetChar() == 'F') {
+ uint32_t result = response.GetHexMaxU32(false, UINT32_MAX);
+ if (result != 0) {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',') {
+ int response_errno = gdb_errno_to_system(response.GetS32(-1, 16));
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ }
+ } else {
+ // Should have returned with 'F<result>[,<errno>]'
+ error.SetErrorStringWithFormat("symlink failed");
+ }
+ } else {
+ error.SetErrorString("failed to send vFile:symlink packet");
+ }
+ return error;
+}
+
+Status GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) {
+ std::string path{file_spec.GetPath(false)};
+ Status error;
+ lldb_private::StreamGDBRemote stream;
+ stream.PutCString("vFile:unlink:");
+ // the unix symlink() command reverses its parameters where the dst if first,
+ // so we follow suit here
+ stream.PutStringAsRawHex8(path);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.GetChar() == 'F') {
+ uint32_t result = response.GetHexMaxU32(false, UINT32_MAX);
+ if (result != 0) {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',') {
+ int response_errno = gdb_errno_to_system(response.GetS32(-1, 16));
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ }
+ } else {
+ // Should have returned with 'F<result>[,<errno>]'
+ error.SetErrorStringWithFormat("unlink failed");
+ }
+ } else {
+ error.SetErrorString("failed to send vFile:unlink packet");
+ }
+ return error;
+}
+
+// Extension of host I/O packets to get whether a file exists.
+bool GDBRemoteCommunicationClient::GetFileExists(
+ const lldb_private::FileSpec &file_spec) {
+ if (m_supports_vFileExists) {
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:exists:");
+ stream.PutStringAsRawHex8(path);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) !=
+ PacketResult::Success)
+ return false;
+ if (!response.IsUnsupportedResponse()) {
+ if (response.GetChar() != 'F')
+ return false;
+ if (response.GetChar() != ',')
+ return false;
+ bool retcode = (response.GetChar() != '0');
+ return retcode;
+ } else
+ m_supports_vFileExists = false;
+ }
+
+ // Fallback to open.
+ Status error;
+ lldb::user_id_t fd = OpenFile(file_spec, File::eOpenOptionReadOnly, 0, error);
+ if (fd == UINT64_MAX)
+ return false;
+ CloseFile(fd, error);
+ return true;
+}
+
+llvm::ErrorOr<llvm::MD5::MD5Result> GDBRemoteCommunicationClient::CalculateMD5(
+ const lldb_private::FileSpec &file_spec) {
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:MD5:");
+ stream.PutStringAsRawHex8(path);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.GetChar() != 'F')
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ if (response.GetChar() != ',')
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ if (response.Peek() && *response.Peek() == 'x')
+ return std::make_error_code(std::errc::no_such_file_or_directory);
+
+ // GDBRemoteCommunicationServerCommon::Handle_vFile_MD5 concatenates low and
+ // high hex strings. We can't use response.GetHexMaxU64 because that can't
+ // handle the concatenated hex string. What would happen is parsing the low
+ // would consume the whole response packet which would give incorrect
+ // results. Instead, we get the byte string for each low and high hex
+ // separately, and parse them.
+ //
+ // An alternate way to handle this is to change the server to put a
+ // delimiter between the low/high parts, and change the client to parse the
+ // delimiter. However, we choose not to do this so existing lldb-servers
+ // don't have to be patched
+
+ // The checksum is 128 bits encoded as hex
+ // This means low/high are halves of 64 bits each, in otherwords, 8 bytes.
+ // Each byte takes 2 hex characters in the response.
+ const size_t MD5_HALF_LENGTH = sizeof(uint64_t) * 2;
+
+ // Get low part
+ auto part =
+ response.GetStringRef().substr(response.GetFilePos(), MD5_HALF_LENGTH);
+ if (part.size() != MD5_HALF_LENGTH)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ response.SetFilePos(response.GetFilePos() + part.size());
+
+ uint64_t low;
+ if (part.getAsInteger(/*radix=*/16, low))
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ // Get high part
+ part =
+ response.GetStringRef().substr(response.GetFilePos(), MD5_HALF_LENGTH);
+ if (part.size() != MD5_HALF_LENGTH)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ response.SetFilePos(response.GetFilePos() + part.size());
+
+ uint64_t high;
+ if (part.getAsInteger(/*radix=*/16, high))
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ llvm::MD5::MD5Result result;
+ llvm::support::endian::write<uint64_t, llvm::endianness::little>(
+ result.data(), low);
+ llvm::support::endian::write<uint64_t, llvm::endianness::little>(
+ result.data() + 8, high);
+
+ return result;
+ }
+ return std::make_error_code(std::errc::operation_canceled);
+}
+
+bool GDBRemoteCommunicationClient::AvoidGPackets(ProcessGDBRemote *process) {
+ // Some targets have issues with g/G packets and we need to avoid using them
+ if (m_avoid_g_packets == eLazyBoolCalculate) {
+ if (process) {
+ m_avoid_g_packets = eLazyBoolNo;
+ const ArchSpec &arch = process->GetTarget().GetArchitecture();
+ if (arch.IsValid() &&
+ arch.GetTriple().getVendor() == llvm::Triple::Apple &&
+ arch.GetTriple().getOS() == llvm::Triple::IOS &&
+ (arch.GetTriple().getArch() == llvm::Triple::aarch64 ||
+ arch.GetTriple().getArch() == llvm::Triple::aarch64_32)) {
+ m_avoid_g_packets = eLazyBoolYes;
+ uint32_t gdb_server_version = GetGDBServerProgramVersion();
+ if (gdb_server_version != 0) {
+ const char *gdb_server_name = GetGDBServerProgramName();
+ if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) {
+ if (gdb_server_version >= 310)
+ m_avoid_g_packets = eLazyBoolNo;
+ }
+ }
+ }
+ }
+ }
+ return m_avoid_g_packets == eLazyBoolYes;
+}
+
+DataBufferSP GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid,
+ uint32_t reg) {
+ StreamString payload;
+ payload.Printf("p%x", reg);
+ StringExtractorGDBRemote response;
+ if (SendThreadSpecificPacketAndWaitForResponse(
+ tid, std::move(payload), response) != PacketResult::Success ||
+ !response.IsNormalResponse())
+ return nullptr;
+
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(response.GetStringRef().size() / 2, 0));
+ response.GetHexBytes(buffer_sp->GetData(), '\xcc');
+ return buffer_sp;
+}
+
+DataBufferSP GDBRemoteCommunicationClient::ReadAllRegisters(lldb::tid_t tid) {
+ StreamString payload;
+ payload.PutChar('g');
+ StringExtractorGDBRemote response;
+ if (SendThreadSpecificPacketAndWaitForResponse(
+ tid, std::move(payload), response) != PacketResult::Success ||
+ !response.IsNormalResponse())
+ return nullptr;
+
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(response.GetStringRef().size() / 2, 0));
+ response.GetHexBytes(buffer_sp->GetData(), '\xcc');
+ return buffer_sp;
+}
+
+bool GDBRemoteCommunicationClient::WriteRegister(lldb::tid_t tid,
+ uint32_t reg_num,
+ llvm::ArrayRef<uint8_t> data) {
+ StreamString payload;
+ payload.Printf("P%x=", reg_num);
+ payload.PutBytesAsRawHex8(data.data(), data.size(),
+ endian::InlHostByteOrder(),
+ endian::InlHostByteOrder());
+ StringExtractorGDBRemote response;
+ return SendThreadSpecificPacketAndWaitForResponse(
+ tid, std::move(payload), response) == PacketResult::Success &&
+ response.IsOKResponse();
+}
+
+bool GDBRemoteCommunicationClient::WriteAllRegisters(
+ lldb::tid_t tid, llvm::ArrayRef<uint8_t> data) {
+ StreamString payload;
+ payload.PutChar('G');
+ payload.PutBytesAsRawHex8(data.data(), data.size(),
+ endian::InlHostByteOrder(),
+ endian::InlHostByteOrder());
+ StringExtractorGDBRemote response;
+ return SendThreadSpecificPacketAndWaitForResponse(
+ tid, std::move(payload), response) == PacketResult::Success &&
+ response.IsOKResponse();
+}
+
+bool GDBRemoteCommunicationClient::SaveRegisterState(lldb::tid_t tid,
+ uint32_t &save_id) {
+ save_id = 0; // Set to invalid save ID
+ if (m_supports_QSaveRegisterState == eLazyBoolNo)
+ return false;
+
+ m_supports_QSaveRegisterState = eLazyBoolYes;
+ StreamString payload;
+ payload.PutCString("QSaveRegisterState");
+ StringExtractorGDBRemote response;
+ if (SendThreadSpecificPacketAndWaitForResponse(
+ tid, std::move(payload), response) != PacketResult::Success)
+ return false;
+
+ if (response.IsUnsupportedResponse())
+ m_supports_QSaveRegisterState = eLazyBoolNo;
+
+ const uint32_t response_save_id = response.GetU32(0);
+ if (response_save_id == 0)
+ return false;
+
+ save_id = response_save_id;
+ return true;
+}
+
+bool GDBRemoteCommunicationClient::RestoreRegisterState(lldb::tid_t tid,
+ uint32_t save_id) {
+ // We use the "m_supports_QSaveRegisterState" variable here because the
+ // QSaveRegisterState and QRestoreRegisterState packets must both be
+ // supported in order to be useful
+ if (m_supports_QSaveRegisterState == eLazyBoolNo)
+ return false;
+
+ StreamString payload;
+ payload.Printf("QRestoreRegisterState:%u", save_id);
+ StringExtractorGDBRemote response;
+ if (SendThreadSpecificPacketAndWaitForResponse(
+ tid, std::move(payload), response) != PacketResult::Success)
+ return false;
+
+ if (response.IsOKResponse())
+ return true;
+
+ if (response.IsUnsupportedResponse())
+ m_supports_QSaveRegisterState = eLazyBoolNo;
+ return false;
+}
+
+bool GDBRemoteCommunicationClient::SyncThreadState(lldb::tid_t tid) {
+ if (!GetSyncThreadStateSupported())
+ return false;
+
+ StreamString packet;
+ StringExtractorGDBRemote response;
+ packet.Printf("QSyncThreadState:%4.4" PRIx64 ";", tid);
+ return SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ GDBRemoteCommunication::PacketResult::Success &&
+ response.IsOKResponse();
+}
+
+llvm::Expected<TraceSupportedResponse>
+GDBRemoteCommunicationClient::SendTraceSupported(std::chrono::seconds timeout) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jLLDBTraceSupported");
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ timeout) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsErrorResponse())
+ return response.GetStatus().ToError();
+ if (response.IsUnsupportedResponse())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "jLLDBTraceSupported is unsupported");
+
+ return llvm::json::parse<TraceSupportedResponse>(response.Peek(),
+ "TraceSupportedResponse");
+ }
+ LLDB_LOG(log, "failed to send packet: jLLDBTraceSupported");
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "failed to send packet: jLLDBTraceSupported");
+}
+
+llvm::Error
+GDBRemoteCommunicationClient::SendTraceStop(const TraceStopRequest &request,
+ std::chrono::seconds timeout) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jLLDBTraceStop:");
+
+ std::string json_string;
+ llvm::raw_string_ostream os(json_string);
+ os << toJSON(request);
+ os.flush();
+
+ escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ timeout) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsErrorResponse())
+ return response.GetStatus().ToError();
+ if (response.IsUnsupportedResponse())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "jLLDBTraceStop is unsupported");
+ if (response.IsOKResponse())
+ return llvm::Error::success();
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Invalid jLLDBTraceStart response");
+ }
+ LLDB_LOG(log, "failed to send packet: jLLDBTraceStop");
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "failed to send packet: jLLDBTraceStop '%s'",
+ escaped_packet.GetData());
+}
+
+llvm::Error
+GDBRemoteCommunicationClient::SendTraceStart(const llvm::json::Value &params,
+ std::chrono::seconds timeout) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jLLDBTraceStart:");
+
+ std::string json_string;
+ llvm::raw_string_ostream os(json_string);
+ os << params;
+ os.flush();
+
+ escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ timeout) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsErrorResponse())
+ return response.GetStatus().ToError();
+ if (response.IsUnsupportedResponse())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "jLLDBTraceStart is unsupported");
+ if (response.IsOKResponse())
+ return llvm::Error::success();
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Invalid jLLDBTraceStart response");
+ }
+ LLDB_LOG(log, "failed to send packet: jLLDBTraceStart");
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "failed to send packet: jLLDBTraceStart '%s'",
+ escaped_packet.GetData());
+}
+
+llvm::Expected<std::string>
+GDBRemoteCommunicationClient::SendTraceGetState(llvm::StringRef type,
+ std::chrono::seconds timeout) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jLLDBTraceGetState:");
+
+ std::string json_string;
+ llvm::raw_string_ostream os(json_string);
+ os << toJSON(TraceGetStateRequest{type.str()});
+ os.flush();
+
+ escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ timeout) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsErrorResponse())
+ return response.GetStatus().ToError();
+ if (response.IsUnsupportedResponse())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "jLLDBTraceGetState is unsupported");
+ return std::string(response.Peek());
+ }
+
+ LLDB_LOG(log, "failed to send packet: jLLDBTraceGetState");
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "failed to send packet: jLLDBTraceGetState '%s'",
+ escaped_packet.GetData());
+}
+
+llvm::Expected<std::vector<uint8_t>>
+GDBRemoteCommunicationClient::SendTraceGetBinaryData(
+ const TraceGetBinaryDataRequest &request, std::chrono::seconds timeout) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jLLDBTraceGetBinaryData:");
+
+ std::string json_string;
+ llvm::raw_string_ostream os(json_string);
+ os << toJSON(request);
+ os.flush();
+
+ escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ timeout) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsErrorResponse())
+ return response.GetStatus().ToError();
+ std::string data;
+ response.GetEscapedBinaryData(data);
+ return std::vector<uint8_t>(data.begin(), data.end());
+ }
+ LLDB_LOG(log, "failed to send packet: jLLDBTraceGetBinaryData");
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "failed to send packet: jLLDBTraceGetBinaryData '%s'",
+ escaped_packet.GetData());
+}
+
+std::optional<QOffsets> GDBRemoteCommunicationClient::GetQOffsets() {
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qOffsets", response) !=
+ PacketResult::Success)
+ return std::nullopt;
+ if (!response.IsNormalResponse())
+ return std::nullopt;
+
+ QOffsets result;
+ llvm::StringRef ref = response.GetStringRef();
+ const auto &GetOffset = [&] {
+ addr_t offset;
+ if (ref.consumeInteger(16, offset))
+ return false;
+ result.offsets.push_back(offset);
+ return true;
+ };
+
+ if (ref.consume_front("Text=")) {
+ result.segments = false;
+ if (!GetOffset())
+ return std::nullopt;
+ if (!ref.consume_front(";Data=") || !GetOffset())
+ return std::nullopt;
+ if (ref.empty())
+ return result;
+ if (ref.consume_front(";Bss=") && GetOffset() && ref.empty())
+ return result;
+ } else if (ref.consume_front("TextSeg=")) {
+ result.segments = true;
+ if (!GetOffset())
+ return std::nullopt;
+ if (ref.empty())
+ return result;
+ if (ref.consume_front(";DataSeg=") && GetOffset() && ref.empty())
+ return result;
+ }
+ return std::nullopt;
+}
+
+bool GDBRemoteCommunicationClient::GetModuleInfo(
+ const FileSpec &module_file_spec, const lldb_private::ArchSpec &arch_spec,
+ ModuleSpec &module_spec) {
+ if (!m_supports_qModuleInfo)
+ return false;
+
+ std::string module_path = module_file_spec.GetPath(false);
+ if (module_path.empty())
+ return false;
+
+ StreamString packet;
+ packet.PutCString("qModuleInfo:");
+ packet.PutStringAsRawHex8(module_path);
+ packet.PutCString(";");
+ const auto &triple = arch_spec.GetTriple().getTriple();
+ packet.PutStringAsRawHex8(triple);
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ PacketResult::Success)
+ return false;
+
+ if (response.IsErrorResponse())
+ return false;
+
+ if (response.IsUnsupportedResponse()) {
+ m_supports_qModuleInfo = false;
+ return false;
+ }
+
+ llvm::StringRef name;
+ llvm::StringRef value;
+
+ module_spec.Clear();
+ module_spec.GetFileSpec() = module_file_spec;
+
+ while (response.GetNameColonValue(name, value)) {
+ if (name == "uuid" || name == "md5") {
+ StringExtractor extractor(value);
+ std::string uuid;
+ extractor.GetHexByteString(uuid);
+ module_spec.GetUUID().SetFromStringRef(uuid);
+ } else if (name == "triple") {
+ StringExtractor extractor(value);
+ std::string triple;
+ extractor.GetHexByteString(triple);
+ module_spec.GetArchitecture().SetTriple(triple.c_str());
+ } else if (name == "file_offset") {
+ uint64_t ival = 0;
+ if (!value.getAsInteger(16, ival))
+ module_spec.SetObjectOffset(ival);
+ } else if (name == "file_size") {
+ uint64_t ival = 0;
+ if (!value.getAsInteger(16, ival))
+ module_spec.SetObjectSize(ival);
+ } else if (name == "file_path") {
+ StringExtractor extractor(value);
+ std::string path;
+ extractor.GetHexByteString(path);
+ module_spec.GetFileSpec() = FileSpec(path, arch_spec.GetTriple());
+ }
+ }
+
+ return true;
+}
+
+static std::optional<ModuleSpec>
+ParseModuleSpec(StructuredData::Dictionary *dict) {
+ ModuleSpec result;
+ if (!dict)
+ return std::nullopt;
+
+ llvm::StringRef string;
+ uint64_t integer;
+
+ if (!dict->GetValueForKeyAsString("uuid", string))
+ return std::nullopt;
+ if (!result.GetUUID().SetFromStringRef(string))
+ return std::nullopt;
+
+ if (!dict->GetValueForKeyAsInteger("file_offset", integer))
+ return std::nullopt;
+ result.SetObjectOffset(integer);
+
+ if (!dict->GetValueForKeyAsInteger("file_size", integer))
+ return std::nullopt;
+ result.SetObjectSize(integer);
+
+ if (!dict->GetValueForKeyAsString("triple", string))
+ return std::nullopt;
+ result.GetArchitecture().SetTriple(string);
+
+ if (!dict->GetValueForKeyAsString("file_path", string))
+ return std::nullopt;
+ result.GetFileSpec() = FileSpec(string, result.GetArchitecture().GetTriple());
+
+ return result;
+}
+
+std::optional<std::vector<ModuleSpec>>
+GDBRemoteCommunicationClient::GetModulesInfo(
+ llvm::ArrayRef<FileSpec> module_file_specs, const llvm::Triple &triple) {
+ namespace json = llvm::json;
+
+ if (!m_supports_jModulesInfo)
+ return std::nullopt;
+
+ json::Array module_array;
+ for (const FileSpec &module_file_spec : module_file_specs) {
+ module_array.push_back(
+ json::Object{{"file", module_file_spec.GetPath(false)},
+ {"triple", triple.getTriple()}});
+ }
+ StreamString unescaped_payload;
+ unescaped_payload.PutCString("jModulesInfo:");
+ unescaped_payload.AsRawOstream() << std::move(module_array);
+
+ StreamGDBRemote payload;
+ payload.PutEscapedBytes(unescaped_payload.GetString().data(),
+ unescaped_payload.GetSize());
+
+ // Increase the timeout for jModulesInfo since this packet can take longer.
+ ScopedTimeout timeout(*this, std::chrono::seconds(10));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(payload.GetString(), response) !=
+ PacketResult::Success ||
+ response.IsErrorResponse())
+ return std::nullopt;
+
+ if (response.IsUnsupportedResponse()) {
+ m_supports_jModulesInfo = false;
+ return std::nullopt;
+ }
+
+ StructuredData::ObjectSP response_object_sp =
+ StructuredData::ParseJSON(response.GetStringRef());
+ if (!response_object_sp)
+ return std::nullopt;
+
+ StructuredData::Array *response_array = response_object_sp->GetAsArray();
+ if (!response_array)
+ return std::nullopt;
+
+ std::vector<ModuleSpec> result;
+ for (size_t i = 0; i < response_array->GetSize(); ++i) {
+ if (std::optional<ModuleSpec> module_spec = ParseModuleSpec(
+ response_array->GetItemAtIndex(i)->GetAsDictionary()))
+ result.push_back(*module_spec);
+ }
+
+ return result;
+}
+
+// query the target remote for extended information using the qXfer packet
+//
+// example: object='features', annex='target.xml'
+// return: <xml output> or error
+llvm::Expected<std::string>
+GDBRemoteCommunicationClient::ReadExtFeature(llvm::StringRef object,
+ llvm::StringRef annex) {
+
+ std::string output;
+ llvm::raw_string_ostream output_stream(output);
+ StringExtractorGDBRemote chunk;
+
+ uint64_t size = GetRemoteMaxPacketSize();
+ if (size == 0)
+ size = 0x1000;
+ size = size - 1; // Leave space for the 'm' or 'l' character in the response
+ int offset = 0;
+ bool active = true;
+
+ // loop until all data has been read
+ while (active) {
+
+ // send query extended feature packet
+ std::string packet =
+ ("qXfer:" + object + ":read:" + annex + ":" +
+ llvm::Twine::utohexstr(offset) + "," + llvm::Twine::utohexstr(size))
+ .str();
+
+ GDBRemoteCommunication::PacketResult res =
+ SendPacketAndWaitForResponse(packet, chunk);
+
+ if (res != GDBRemoteCommunication::PacketResult::Success ||
+ chunk.GetStringRef().empty()) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Error sending $qXfer packet");
+ }
+
+ // check packet code
+ switch (chunk.GetStringRef()[0]) {
+ // last chunk
+ case ('l'):
+ active = false;
+ [[fallthrough]];
+
+ // more chunks
+ case ('m'):
+ output_stream << chunk.GetStringRef().drop_front();
+ offset += chunk.GetStringRef().size() - 1;
+ break;
+
+ // unknown chunk
+ default:
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Invalid continuation code from $qXfer packet");
+ }
+ }
+
+ return output_stream.str();
+}
+
+// Notify the target that gdb is prepared to serve symbol lookup requests.
+// packet: "qSymbol::"
+// reply:
+// OK The target does not need to look up any (more) symbols.
+// qSymbol:<sym_name> The target requests the value of symbol sym_name (hex
+// encoded).
+// LLDB may provide the value by sending another qSymbol
+// packet
+// in the form of"qSymbol:<sym_value>:<sym_name>".
+//
+// Three examples:
+//
+// lldb sends: qSymbol::
+// lldb receives: OK
+// Remote gdb stub does not need to know the addresses of any symbols, lldb
+// does not
+// need to ask again in this session.
+//
+// lldb sends: qSymbol::
+// lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473
+// lldb sends: qSymbol::64697370617463685f71756575655f6f666673657473
+// lldb receives: OK
+// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb does
+// not know
+// the address at this time. lldb needs to send qSymbol:: again when it has
+// more
+// solibs loaded.
+//
+// lldb sends: qSymbol::
+// lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473
+// lldb sends: qSymbol:2bc97554:64697370617463685f71756575655f6f666673657473
+// lldb receives: OK
+// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb says
+// that it
+// is at address 0x2bc97554. Remote gdb stub sends 'OK' indicating that it
+// does not
+// need any more symbols. lldb does not need to ask again in this session.
+
+void GDBRemoteCommunicationClient::ServeSymbolLookups(
+ lldb_private::Process *process) {
+ // Set to true once we've resolved a symbol to an address for the remote
+ // stub. If we get an 'OK' response after this, the remote stub doesn't need
+ // any more symbols and we can stop asking.
+ bool symbol_response_provided = false;
+
+ // Is this the initial qSymbol:: packet?
+ bool first_qsymbol_query = true;
+
+ if (m_supports_qSymbol && !m_qSymbol_requests_done) {
+ Lock lock(*this);
+ if (lock) {
+ StreamString packet;
+ packet.PutCString("qSymbol::");
+ StringExtractorGDBRemote response;
+ while (SendPacketAndWaitForResponseNoLock(packet.GetString(), response) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ if (symbol_response_provided || first_qsymbol_query) {
+ m_qSymbol_requests_done = true;
+ }
+
+ // We are done serving symbols requests
+ return;
+ }
+ first_qsymbol_query = false;
+
+ if (response.IsUnsupportedResponse()) {
+ // qSymbol is not supported by the current GDB server we are
+ // connected to
+ m_supports_qSymbol = false;
+ return;
+ } else {
+ llvm::StringRef response_str(response.GetStringRef());
+ if (response_str.starts_with("qSymbol:")) {
+ response.SetFilePos(strlen("qSymbol:"));
+ std::string symbol_name;
+ if (response.GetHexByteString(symbol_name)) {
+ if (symbol_name.empty())
+ return;
+
+ addr_t symbol_load_addr = LLDB_INVALID_ADDRESS;
+ lldb_private::SymbolContextList sc_list;
+ process->GetTarget().GetImages().FindSymbolsWithNameAndType(
+ ConstString(symbol_name), eSymbolTypeAny, sc_list);
+ for (const SymbolContext &sc : sc_list) {
+ if (symbol_load_addr != LLDB_INVALID_ADDRESS)
+ break;
+ if (sc.symbol) {
+ switch (sc.symbol->GetType()) {
+ case eSymbolTypeInvalid:
+ case eSymbolTypeAbsolute:
+ case eSymbolTypeUndefined:
+ case eSymbolTypeSourceFile:
+ case eSymbolTypeHeaderFile:
+ case eSymbolTypeObjectFile:
+ case eSymbolTypeCommonBlock:
+ case eSymbolTypeBlock:
+ case eSymbolTypeLocal:
+ case eSymbolTypeParam:
+ case eSymbolTypeVariable:
+ case eSymbolTypeVariableType:
+ case eSymbolTypeLineEntry:
+ case eSymbolTypeLineHeader:
+ case eSymbolTypeScopeBegin:
+ case eSymbolTypeScopeEnd:
+ case eSymbolTypeAdditional:
+ case eSymbolTypeCompiler:
+ case eSymbolTypeInstrumentation:
+ case eSymbolTypeTrampoline:
+ break;
+
+ case eSymbolTypeCode:
+ case eSymbolTypeResolver:
+ case eSymbolTypeData:
+ case eSymbolTypeRuntime:
+ case eSymbolTypeException:
+ case eSymbolTypeObjCClass:
+ case eSymbolTypeObjCMetaClass:
+ case eSymbolTypeObjCIVar:
+ case eSymbolTypeReExported:
+ symbol_load_addr =
+ sc.symbol->GetLoadAddress(&process->GetTarget());
+ break;
+ }
+ }
+ }
+ // This is the normal path where our symbol lookup was successful
+ // and we want to send a packet with the new symbol value and see
+ // if another lookup needs to be done.
+
+ // Change "packet" to contain the requested symbol value and name
+ packet.Clear();
+ packet.PutCString("qSymbol:");
+ if (symbol_load_addr != LLDB_INVALID_ADDRESS) {
+ packet.Printf("%" PRIx64, symbol_load_addr);
+ symbol_response_provided = true;
+ } else {
+ symbol_response_provided = false;
+ }
+ packet.PutCString(":");
+ packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size());
+ continue; // go back to the while loop and send "packet" and wait
+ // for another response
+ }
+ }
+ }
+ }
+ // If we make it here, the symbol request packet response wasn't valid or
+ // our symbol lookup failed so we must abort
+ return;
+
+ } else if (Log *log = GetLog(GDBRLog::Process | GDBRLog::Packets)) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationClient::%s: Didn't get sequence mutex.",
+ __FUNCTION__);
+ }
+ }
+}
+
+StructuredData::Array *
+GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() {
+ if (!m_supported_async_json_packets_is_valid) {
+ // Query the server for the array of supported asynchronous JSON packets.
+ m_supported_async_json_packets_is_valid = true;
+
+ Log *log = GetLog(GDBRLog::Process);
+
+ // Poll it now.
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qStructuredDataPlugins", response) ==
+ PacketResult::Success) {
+ m_supported_async_json_packets_sp =
+ StructuredData::ParseJSON(response.GetStringRef());
+ if (m_supported_async_json_packets_sp &&
+ !m_supported_async_json_packets_sp->GetAsArray()) {
+ // We were returned something other than a JSON array. This is
+ // invalid. Clear it out.
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationClient::%s(): "
+ "QSupportedAsyncJSONPackets returned invalid "
+ "result: %s",
+ __FUNCTION__, response.GetStringRef().data());
+ m_supported_async_json_packets_sp.reset();
+ }
+ } else {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationClient::%s(): "
+ "QSupportedAsyncJSONPackets unsupported",
+ __FUNCTION__);
+ }
+
+ if (log && m_supported_async_json_packets_sp) {
+ StreamString stream;
+ m_supported_async_json_packets_sp->Dump(stream);
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationClient::%s(): supported async "
+ "JSON packets: %s",
+ __FUNCTION__, stream.GetData());
+ }
+ }
+
+ return m_supported_async_json_packets_sp
+ ? m_supported_async_json_packets_sp->GetAsArray()
+ : nullptr;
+}
+
+Status GDBRemoteCommunicationClient::SendSignalsToIgnore(
+ llvm::ArrayRef<int32_t> signals) {
+ // Format packet:
+ // QPassSignals:<hex_sig1>;<hex_sig2>...;<hex_sigN>
+ auto range = llvm::make_range(signals.begin(), signals.end());
+ std::string packet = formatv("QPassSignals:{0:$[;]@(x-2)}", range).str();
+
+ StringExtractorGDBRemote response;
+ auto send_status = SendPacketAndWaitForResponse(packet, response);
+
+ if (send_status != GDBRemoteCommunication::PacketResult::Success)
+ return Status("Sending QPassSignals packet failed");
+
+ if (response.IsOKResponse()) {
+ return Status();
+ } else {
+ return Status("Unknown error happened during sending QPassSignals packet.");
+ }
+}
+
+Status GDBRemoteCommunicationClient::ConfigureRemoteStructuredData(
+ llvm::StringRef type_name, const StructuredData::ObjectSP &config_sp) {
+ Status error;
+
+ if (type_name.empty()) {
+ error.SetErrorString("invalid type_name argument");
+ return error;
+ }
+
+ // Build command: Configure{type_name}: serialized config data.
+ StreamGDBRemote stream;
+ stream.PutCString("QConfigure");
+ stream.PutCString(type_name);
+ stream.PutChar(':');
+ if (config_sp) {
+ // Gather the plain-text version of the configuration data.
+ StreamString unescaped_stream;
+ config_sp->Dump(unescaped_stream);
+ unescaped_stream.Flush();
+
+ // Add it to the stream in escaped fashion.
+ stream.PutEscapedBytes(unescaped_stream.GetString().data(),
+ unescaped_stream.GetSize());
+ }
+ stream.Flush();
+
+ // Send the packet.
+ StringExtractorGDBRemote response;
+ auto result = SendPacketAndWaitForResponse(stream.GetString(), response);
+ if (result == PacketResult::Success) {
+ // We failed if the config result comes back other than OK.
+ if (response.GetStringRef() == "OK") {
+ // Okay!
+ error.Clear();
+ } else {
+ error.SetErrorStringWithFormatv(
+ "configuring StructuredData feature {0} failed with error {1}",
+ type_name, response.GetStringRef());
+ }
+ } else {
+ // Can we get more data here on the failure?
+ error.SetErrorStringWithFormatv(
+ "configuring StructuredData feature {0} failed when sending packet: "
+ "PacketResult={1}",
+ type_name, (int)result);
+ }
+ return error;
+}
+
+void GDBRemoteCommunicationClient::OnRunPacketSent(bool first) {
+ GDBRemoteClientBase::OnRunPacketSent(first);
+ m_curr_tid = LLDB_INVALID_THREAD_ID;
+}
+
+bool GDBRemoteCommunicationClient::UsesNativeSignals() {
+ if (m_uses_native_signals == eLazyBoolCalculate)
+ GetRemoteQSupported();
+ if (m_uses_native_signals == eLazyBoolYes)
+ return true;
+
+ // If the remote didn't indicate native-signal support explicitly,
+ // check whether it is an old version of lldb-server.
+ return GetThreadSuffixSupported();
+}
+
+llvm::Expected<int> GDBRemoteCommunicationClient::KillProcess(lldb::pid_t pid) {
+ StringExtractorGDBRemote response;
+ GDBRemoteCommunication::ScopedTimeout(*this, seconds(3));
+
+ if (SendPacketAndWaitForResponse("k", response, GetPacketTimeout()) !=
+ PacketResult::Success)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "failed to send k packet");
+
+ char packet_cmd = response.GetChar(0);
+ if (packet_cmd == 'W' || packet_cmd == 'X')
+ return response.GetHexU8();
+
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "unexpected response to k packet: %s",
+ response.GetStringRef().str().c_str());
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
new file mode 100644
index 000000000000..898d176abc34
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -0,0 +1,658 @@
+//===-- GDBRemoteCommunicationClient.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONCLIENT_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONCLIENT_H
+
+#include "GDBRemoteClientBase.h"
+
+#include <chrono>
+#include <map>
+#include <mutex>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "lldb/Host/File.h"
+#include "lldb/Utility/AddressableBits.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/GDBRemote.h"
+#include "lldb/Utility/ProcessInfo.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/TraceGDBRemotePackets.h"
+#include "lldb/Utility/UUID.h"
+#if defined(_WIN32)
+#include "lldb/Host/windows/PosixApi.h"
+#endif
+
+#include "llvm/Support/VersionTuple.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+/// The offsets used by the target when relocating the executable. Decoded from
+/// qOffsets packet response.
+struct QOffsets {
+ /// If true, the offsets field describes segments. Otherwise, it describes
+ /// sections.
+ bool segments;
+
+ /// The individual offsets. Section offsets have two or three members.
+ /// Segment offsets have either one of two.
+ std::vector<uint64_t> offsets;
+};
+inline bool operator==(const QOffsets &a, const QOffsets &b) {
+ return a.segments == b.segments && a.offsets == b.offsets;
+}
+llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const QOffsets &offsets);
+
+// A trivial struct used to return a pair of PID and TID.
+struct PidTid {
+ uint64_t pid;
+ uint64_t tid;
+};
+
+class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
+public:
+ GDBRemoteCommunicationClient();
+
+ ~GDBRemoteCommunicationClient() override;
+
+ // After connecting, send the handshake to the server to make sure
+ // we are communicating with it.
+ bool HandshakeWithServer(Status *error_ptr);
+
+ bool GetThreadSuffixSupported();
+
+ // This packet is usually sent first and the boolean return value
+ // indicates if the packet was send and any response was received
+ // even in the response is UNIMPLEMENTED. If the packet failed to
+ // get a response, then false is returned. This quickly tells us
+ // if we were able to connect and communicate with the remote GDB
+ // server
+ bool QueryNoAckModeSupported();
+
+ void GetListThreadsInStopReplySupported();
+
+ lldb::pid_t GetCurrentProcessID(bool allow_lazy = true);
+
+ bool LaunchGDBServer(const char *remote_accept_hostname, lldb::pid_t &pid,
+ uint16_t &port, std::string &socket_name);
+
+ size_t QueryGDBServer(
+ std::vector<std::pair<uint16_t, std::string>> &connection_urls);
+
+ bool KillSpawnedProcess(lldb::pid_t pid);
+
+ /// Launch the process using the provided arguments.
+ ///
+ /// \param[in] args
+ /// A list of program arguments. The first entry is the program being run.
+ llvm::Error LaunchProcess(const Args &args);
+
+ /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the
+ /// environment that will get used when launching an application
+ /// in conjunction with the 'A' packet. This function can be called
+ /// multiple times in a row in order to pass on the desired
+ /// environment that the inferior should be launched with.
+ ///
+ /// \param[in] name_equal_value
+ /// A NULL terminated C string that contains a single environment
+ /// in the format "NAME=VALUE".
+ ///
+ /// \return
+ /// Zero if the response was "OK", a positive value if the
+ /// the response was "Exx" where xx are two hex digits, or
+ /// -1 if the call is unsupported or any other unexpected
+ /// response was received.
+ int SendEnvironmentPacket(char const *name_equal_value);
+ int SendEnvironment(const Environment &env);
+
+ int SendLaunchArchPacket(const char *arch);
+
+ int SendLaunchEventDataPacket(const char *data,
+ bool *was_supported = nullptr);
+
+ /// Sends a GDB remote protocol 'I' packet that delivers stdin
+ /// data to the remote process.
+ ///
+ /// \param[in] data
+ /// A pointer to stdin data.
+ ///
+ /// \param[in] data_len
+ /// The number of bytes available at \a data.
+ ///
+ /// \return
+ /// Zero if the attach was successful, or an error indicating
+ /// an error code.
+ int SendStdinNotification(const char *data, size_t data_len);
+
+ /// Sets the path to use for stdin/out/err for a process
+ /// that will be launched with the 'A' packet.
+ ///
+ /// \param[in] file_spec
+ /// The path to use for stdin/out/err
+ ///
+ /// \return
+ /// Zero if the for success, or an error code for failure.
+ int SetSTDIN(const FileSpec &file_spec);
+ int SetSTDOUT(const FileSpec &file_spec);
+ int SetSTDERR(const FileSpec &file_spec);
+
+ /// Sets the disable ASLR flag to \a enable for a process that will
+ /// be launched with the 'A' packet.
+ ///
+ /// \param[in] enable
+ /// A boolean value indicating whether to disable ASLR or not.
+ ///
+ /// \return
+ /// Zero if the for success, or an error code for failure.
+ int SetDisableASLR(bool enable);
+
+ /// Sets the DetachOnError flag to \a enable for the process controlled by the
+ /// stub.
+ ///
+ /// \param[in] enable
+ /// A boolean value indicating whether to detach on error or not.
+ ///
+ /// \return
+ /// Zero if the for success, or an error code for failure.
+ int SetDetachOnError(bool enable);
+
+ /// Sets the working directory to \a path for a process that will
+ /// be launched with the 'A' packet for non platform based
+ /// connections. If this packet is sent to a GDB server that
+ /// implements the platform, it will change the current working
+ /// directory for the platform process.
+ ///
+ /// \param[in] working_dir
+ /// The path to a directory to use when launching our process
+ ///
+ /// \return
+ /// Zero if the for success, or an error code for failure.
+ int SetWorkingDir(const FileSpec &working_dir);
+
+ /// Gets the current working directory of a remote platform GDB
+ /// server.
+ ///
+ /// \param[out] working_dir
+ /// The current working directory on the remote platform.
+ ///
+ /// \return
+ /// Boolean for success
+ bool GetWorkingDir(FileSpec &working_dir);
+
+ lldb::addr_t AllocateMemory(size_t size, uint32_t permissions);
+
+ bool DeallocateMemory(lldb::addr_t addr);
+
+ Status Detach(bool keep_stopped, lldb::pid_t pid = LLDB_INVALID_PROCESS_ID);
+
+ Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info);
+
+ std::optional<uint32_t> GetWatchpointSlotCount();
+
+ std::optional<bool> GetWatchpointReportedAfter();
+
+ WatchpointHardwareFeature GetSupportedWatchpointTypes();
+
+ const ArchSpec &GetHostArchitecture();
+
+ std::chrono::seconds GetHostDefaultPacketTimeout();
+
+ const ArchSpec &GetProcessArchitecture();
+
+ bool GetProcessStandaloneBinary(UUID &uuid, lldb::addr_t &value,
+ bool &value_is_offset);
+
+ std::vector<lldb::addr_t> GetProcessStandaloneBinaries();
+
+ void GetRemoteQSupported();
+
+ bool GetVContSupported(char flavor);
+
+ bool GetpPacketSupported(lldb::tid_t tid);
+
+ bool GetxPacketSupported();
+
+ bool GetVAttachOrWaitSupported();
+
+ bool GetSyncThreadStateSupported();
+
+ void ResetDiscoverableSettings(bool did_exec);
+
+ bool GetHostInfo(bool force = false);
+
+ bool GetDefaultThreadId(lldb::tid_t &tid);
+
+ llvm::VersionTuple GetOSVersion();
+
+ llvm::VersionTuple GetMacCatalystVersion();
+
+ std::optional<std::string> GetOSBuildString();
+
+ std::optional<std::string> GetOSKernelDescription();
+
+ ArchSpec GetSystemArchitecture();
+
+ lldb_private::AddressableBits GetAddressableBits();
+
+ bool GetHostname(std::string &s);
+
+ lldb::addr_t GetShlibInfoAddr();
+
+ bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info);
+
+ uint32_t FindProcesses(const ProcessInstanceInfoMatch &process_match_info,
+ ProcessInstanceInfoList &process_infos);
+
+ bool GetUserName(uint32_t uid, std::string &name);
+
+ bool GetGroupName(uint32_t gid, std::string &name);
+
+ bool HasFullVContSupport() { return GetVContSupported('A'); }
+
+ bool HasAnyVContSupport() { return GetVContSupported('a'); }
+
+ bool GetStopReply(StringExtractorGDBRemote &response);
+
+ bool GetThreadStopInfo(lldb::tid_t tid, StringExtractorGDBRemote &response);
+
+ bool SupportsGDBStoppointPacket(GDBStoppointType type) {
+ switch (type) {
+ case eBreakpointSoftware:
+ return m_supports_z0;
+ case eBreakpointHardware:
+ return m_supports_z1;
+ case eWatchpointWrite:
+ return m_supports_z2;
+ case eWatchpointRead:
+ return m_supports_z3;
+ case eWatchpointReadWrite:
+ return m_supports_z4;
+ default:
+ return false;
+ }
+ }
+
+ uint8_t SendGDBStoppointTypePacket(
+ GDBStoppointType type, // Type of breakpoint or watchpoint
+ bool insert, // Insert or remove?
+ lldb::addr_t addr, // Address of breakpoint or watchpoint
+ uint32_t length, // Byte Size of breakpoint or watchpoint
+ std::chrono::seconds interrupt_timeout); // Time to wait for an interrupt
+
+ void TestPacketSpeed(const uint32_t num_packets, uint32_t max_send,
+ uint32_t max_recv, uint64_t recv_amount, bool json,
+ Stream &strm);
+
+ // This packet is for testing the speed of the interface only. Both
+ // the client and server need to support it, but this allows us to
+ // measure the packet speed without any other work being done on the
+ // other end and avoids any of that work affecting the packet send
+ // and response times.
+ bool SendSpeedTestPacket(uint32_t send_size, uint32_t recv_size);
+
+ std::optional<PidTid> SendSetCurrentThreadPacket(uint64_t tid, uint64_t pid,
+ char op);
+
+ bool SetCurrentThread(uint64_t tid,
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID);
+
+ bool SetCurrentThreadForRun(uint64_t tid,
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID);
+
+ bool GetQXferAuxvReadSupported();
+
+ void EnableErrorStringInPacket();
+
+ bool GetQXferLibrariesReadSupported();
+
+ bool GetQXferLibrariesSVR4ReadSupported();
+
+ uint64_t GetRemoteMaxPacketSize();
+
+ bool GetEchoSupported();
+
+ bool GetQPassSignalsSupported();
+
+ bool GetAugmentedLibrariesSVR4ReadSupported();
+
+ bool GetQXferFeaturesReadSupported();
+
+ bool GetQXferMemoryMapReadSupported();
+
+ bool GetQXferSigInfoReadSupported();
+
+ bool GetMultiprocessSupported();
+
+ LazyBool SupportsAllocDeallocMemory() // const
+ {
+ // Uncomment this to have lldb pretend the debug server doesn't respond to
+ // alloc/dealloc memory packets.
+ // m_supports_alloc_dealloc_memory = lldb_private::eLazyBoolNo;
+ return m_supports_alloc_dealloc_memory;
+ }
+
+ std::vector<std::pair<lldb::pid_t, lldb::tid_t>>
+ GetCurrentProcessAndThreadIDs(bool &sequence_mutex_unavailable);
+
+ size_t GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids,
+ bool &sequence_mutex_unavailable);
+
+ lldb::user_id_t OpenFile(const FileSpec &file_spec, File::OpenOptions flags,
+ mode_t mode, Status &error);
+
+ bool CloseFile(lldb::user_id_t fd, Status &error);
+
+ std::optional<GDBRemoteFStatData> FStat(lldb::user_id_t fd);
+
+ // NB: this is just a convenience wrapper over open() + fstat(). It does not
+ // work if the file cannot be opened.
+ std::optional<GDBRemoteFStatData> Stat(const FileSpec &file_spec);
+
+ lldb::user_id_t GetFileSize(const FileSpec &file_spec);
+
+ void AutoCompleteDiskFileOrDirectory(CompletionRequest &request,
+ bool only_dir);
+
+ Status GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions);
+
+ Status SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions);
+
+ uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
+ uint64_t dst_len, Status &error);
+
+ uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src,
+ uint64_t src_len, Status &error);
+
+ Status CreateSymlink(const FileSpec &src, const FileSpec &dst);
+
+ Status Unlink(const FileSpec &file_spec);
+
+ Status MakeDirectory(const FileSpec &file_spec, uint32_t mode);
+
+ bool GetFileExists(const FileSpec &file_spec);
+
+ Status RunShellCommand(
+ llvm::StringRef command,
+ const FileSpec &working_dir, // Pass empty FileSpec to use the current
+ // working directory
+ int *status_ptr, // Pass nullptr if you don't want the process exit status
+ int *signo_ptr, // Pass nullptr if you don't want the signal that caused
+ // the process to exit
+ std::string
+ *command_output, // Pass nullptr if you don't want the command output
+ const Timeout<std::micro> &timeout);
+
+ llvm::ErrorOr<llvm::MD5::MD5Result> CalculateMD5(const FileSpec &file_spec);
+
+ lldb::DataBufferSP ReadRegister(
+ lldb::tid_t tid,
+ uint32_t
+ reg_num); // Must be the eRegisterKindProcessPlugin register number
+
+ lldb::DataBufferSP ReadAllRegisters(lldb::tid_t tid);
+
+ bool
+ WriteRegister(lldb::tid_t tid,
+ uint32_t reg_num, // eRegisterKindProcessPlugin register number
+ llvm::ArrayRef<uint8_t> data);
+
+ bool WriteAllRegisters(lldb::tid_t tid, llvm::ArrayRef<uint8_t> data);
+
+ bool SaveRegisterState(lldb::tid_t tid, uint32_t &save_id);
+
+ bool RestoreRegisterState(lldb::tid_t tid, uint32_t save_id);
+
+ bool SyncThreadState(lldb::tid_t tid);
+
+ const char *GetGDBServerProgramName();
+
+ uint32_t GetGDBServerProgramVersion();
+
+ bool AvoidGPackets(ProcessGDBRemote *process);
+
+ StructuredData::ObjectSP GetThreadsInfo();
+
+ bool GetThreadExtendedInfoSupported();
+
+ bool GetLoadedDynamicLibrariesInfosSupported();
+
+ bool GetSharedCacheInfoSupported();
+
+ bool GetDynamicLoaderProcessStateSupported();
+
+ bool GetMemoryTaggingSupported();
+
+ bool UsesNativeSignals();
+
+ lldb::DataBufferSP ReadMemoryTags(lldb::addr_t addr, size_t len,
+ int32_t type);
+
+ Status WriteMemoryTags(lldb::addr_t addr, size_t len, int32_t type,
+ const std::vector<uint8_t> &tags);
+
+ /// Use qOffsets to query the offset used when relocating the target
+ /// executable. If successful, the returned structure will contain at least
+ /// one value in the offsets field.
+ std::optional<QOffsets> GetQOffsets();
+
+ bool GetModuleInfo(const FileSpec &module_file_spec,
+ const ArchSpec &arch_spec, ModuleSpec &module_spec);
+
+ std::optional<std::vector<ModuleSpec>>
+ GetModulesInfo(llvm::ArrayRef<FileSpec> module_file_specs,
+ const llvm::Triple &triple);
+
+ llvm::Expected<std::string> ReadExtFeature(llvm::StringRef object,
+ llvm::StringRef annex);
+
+ void ServeSymbolLookups(lldb_private::Process *process);
+
+ // Sends QPassSignals packet to the server with given signals to ignore.
+ Status SendSignalsToIgnore(llvm::ArrayRef<int32_t> signals);
+
+ /// Return the feature set supported by the gdb-remote server.
+ ///
+ /// This method returns the remote side's response to the qSupported
+ /// packet. The response is the complete string payload returned
+ /// to the client.
+ ///
+ /// \return
+ /// The string returned by the server to the qSupported query.
+ const std::string &GetServerSupportedFeatures() const {
+ return m_qSupported_response;
+ }
+
+ /// Return the array of async JSON packet types supported by the remote.
+ ///
+ /// This method returns the remote side's array of supported JSON
+ /// packet types as a list of type names. Each of the results are
+ /// expected to have an Enable{type_name} command to enable and configure
+ /// the related feature. Each type_name for an enabled feature will
+ /// possibly send async-style packets that contain a payload of a
+ /// binhex-encoded JSON dictionary. The dictionary will have a
+ /// string field named 'type', that contains the type_name of the
+ /// supported packet type.
+ ///
+ /// There is a Plugin category called structured-data plugins.
+ /// A plugin indicates whether it knows how to handle a type_name.
+ /// If so, it can be used to process the async JSON packet.
+ ///
+ /// \return
+ /// The string returned by the server to the qSupported query.
+ lldb_private::StructuredData::Array *GetSupportedStructuredDataPlugins();
+
+ /// Configure a StructuredData feature on the remote end.
+ ///
+ /// \see \b Process::ConfigureStructuredData(...) for details.
+ Status
+ ConfigureRemoteStructuredData(llvm::StringRef type_name,
+ const StructuredData::ObjectSP &config_sp);
+
+ llvm::Expected<TraceSupportedResponse>
+ SendTraceSupported(std::chrono::seconds interrupt_timeout);
+
+ llvm::Error SendTraceStart(const llvm::json::Value &request,
+ std::chrono::seconds interrupt_timeout);
+
+ llvm::Error SendTraceStop(const TraceStopRequest &request,
+ std::chrono::seconds interrupt_timeout);
+
+ llvm::Expected<std::string>
+ SendTraceGetState(llvm::StringRef type,
+ std::chrono::seconds interrupt_timeout);
+
+ llvm::Expected<std::vector<uint8_t>>
+ SendTraceGetBinaryData(const TraceGetBinaryDataRequest &request,
+ std::chrono::seconds interrupt_timeout);
+
+ bool GetSaveCoreSupported() const;
+
+ llvm::Expected<int> KillProcess(lldb::pid_t pid);
+
+protected:
+ LazyBool m_supports_not_sending_acks = eLazyBoolCalculate;
+ LazyBool m_supports_thread_suffix = eLazyBoolCalculate;
+ LazyBool m_supports_threads_in_stop_reply = eLazyBoolCalculate;
+ LazyBool m_supports_vCont_all = eLazyBoolCalculate;
+ LazyBool m_supports_vCont_any = eLazyBoolCalculate;
+ LazyBool m_supports_vCont_c = eLazyBoolCalculate;
+ LazyBool m_supports_vCont_C = eLazyBoolCalculate;
+ LazyBool m_supports_vCont_s = eLazyBoolCalculate;
+ LazyBool m_supports_vCont_S = eLazyBoolCalculate;
+ LazyBool m_qHostInfo_is_valid = eLazyBoolCalculate;
+ LazyBool m_curr_pid_is_valid = eLazyBoolCalculate;
+ LazyBool m_qProcessInfo_is_valid = eLazyBoolCalculate;
+ LazyBool m_qGDBServerVersion_is_valid = eLazyBoolCalculate;
+ LazyBool m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
+ LazyBool m_supports_memory_region_info = eLazyBoolCalculate;
+ LazyBool m_supports_watchpoint_support_info = eLazyBoolCalculate;
+ LazyBool m_supports_detach_stay_stopped = eLazyBoolCalculate;
+ LazyBool m_watchpoints_trigger_after_instruction = eLazyBoolCalculate;
+ LazyBool m_attach_or_wait_reply = eLazyBoolCalculate;
+ LazyBool m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
+ LazyBool m_supports_p = eLazyBoolCalculate;
+ LazyBool m_supports_x = eLazyBoolCalculate;
+ LazyBool m_avoid_g_packets = eLazyBoolCalculate;
+ LazyBool m_supports_QSaveRegisterState = eLazyBoolCalculate;
+ LazyBool m_supports_qXfer_auxv_read = eLazyBoolCalculate;
+ LazyBool m_supports_qXfer_libraries_read = eLazyBoolCalculate;
+ LazyBool m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;
+ LazyBool m_supports_qXfer_features_read = eLazyBoolCalculate;
+ LazyBool m_supports_qXfer_memory_map_read = eLazyBoolCalculate;
+ LazyBool m_supports_qXfer_siginfo_read = eLazyBoolCalculate;
+ LazyBool m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;
+ LazyBool m_supports_jThreadExtendedInfo = eLazyBoolCalculate;
+ LazyBool m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolCalculate;
+ LazyBool m_supports_jGetSharedCacheInfo = eLazyBoolCalculate;
+ LazyBool m_supports_jGetDyldProcessState = eLazyBoolCalculate;
+ LazyBool m_supports_QPassSignals = eLazyBoolCalculate;
+ LazyBool m_supports_error_string_reply = eLazyBoolCalculate;
+ LazyBool m_supports_multiprocess = eLazyBoolCalculate;
+ LazyBool m_supports_memory_tagging = eLazyBoolCalculate;
+ LazyBool m_supports_qSaveCore = eLazyBoolCalculate;
+ LazyBool m_uses_native_signals = eLazyBoolCalculate;
+
+ bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1,
+ m_supports_qUserName : 1, m_supports_qGroupName : 1,
+ m_supports_qThreadStopInfo : 1, m_supports_z0 : 1, m_supports_z1 : 1,
+ m_supports_z2 : 1, m_supports_z3 : 1, m_supports_z4 : 1,
+ m_supports_QEnvironment : 1, m_supports_QEnvironmentHexEncoded : 1,
+ m_supports_qSymbol : 1, m_qSymbol_requests_done : 1,
+ m_supports_qModuleInfo : 1, m_supports_jThreadsInfo : 1,
+ m_supports_jModulesInfo : 1, m_supports_vFileSize : 1,
+ m_supports_vFileMode : 1, m_supports_vFileExists : 1,
+ m_supports_vRun : 1;
+
+ /// Current gdb remote protocol process identifier for all other operations
+ lldb::pid_t m_curr_pid = LLDB_INVALID_PROCESS_ID;
+ /// Current gdb remote protocol process identifier for continue, step, etc
+ lldb::pid_t m_curr_pid_run = LLDB_INVALID_PROCESS_ID;
+ /// Current gdb remote protocol thread identifier for all other operations
+ lldb::tid_t m_curr_tid = LLDB_INVALID_THREAD_ID;
+ /// Current gdb remote protocol thread identifier for continue, step, etc
+ lldb::tid_t m_curr_tid_run = LLDB_INVALID_THREAD_ID;
+
+ uint32_t m_num_supported_hardware_watchpoints = 0;
+ WatchpointHardwareFeature m_watchpoint_types =
+ eWatchpointHardwareFeatureUnknown;
+ uint32_t m_low_mem_addressing_bits = 0;
+ uint32_t m_high_mem_addressing_bits = 0;
+
+ ArchSpec m_host_arch;
+ std::string m_host_distribution_id;
+ ArchSpec m_process_arch;
+ UUID m_process_standalone_uuid;
+ lldb::addr_t m_process_standalone_value = LLDB_INVALID_ADDRESS;
+ bool m_process_standalone_value_is_offset = false;
+ std::vector<lldb::addr_t> m_binary_addresses;
+ llvm::VersionTuple m_os_version;
+ llvm::VersionTuple m_maccatalyst_version;
+ std::string m_os_build;
+ std::string m_os_kernel;
+ std::string m_hostname;
+ std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if
+ // qGDBServerVersion is not supported
+ uint32_t m_gdb_server_version =
+ UINT32_MAX; // from reply to qGDBServerVersion, zero if
+ // qGDBServerVersion is not supported
+ std::chrono::seconds m_default_packet_timeout;
+ int m_target_vm_page_size = 0; // target system VM page size; 0 unspecified
+ uint64_t m_max_packet_size = 0; // as returned by qSupported
+ std::string m_qSupported_response; // the complete response to qSupported
+
+ bool m_supported_async_json_packets_is_valid = false;
+ lldb_private::StructuredData::ObjectSP m_supported_async_json_packets_sp;
+
+ std::vector<MemoryRegionInfo> m_qXfer_memory_map;
+ bool m_qXfer_memory_map_loaded = false;
+
+ bool GetCurrentProcessInfo(bool allow_lazy_pid = true);
+
+ bool GetGDBServerVersion();
+
+ // Given the list of compression types that the remote debug stub can support,
+ // possibly enable compression if we find an encoding we can handle.
+ void MaybeEnableCompression(
+ llvm::ArrayRef<llvm::StringRef> supported_compressions);
+
+ bool DecodeProcessInfoResponse(StringExtractorGDBRemote &response,
+ ProcessInstanceInfo &process_info);
+
+ void OnRunPacketSent(bool first) override;
+
+ PacketResult SendThreadSpecificPacketAndWaitForResponse(
+ lldb::tid_t tid, StreamString &&payload,
+ StringExtractorGDBRemote &response);
+
+ Status SendGetTraceDataPacket(StreamGDBRemote &packet, lldb::user_id_t uid,
+ lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset);
+
+ Status LoadQXferMemoryMap();
+
+ Status GetQXferMemoryMapRegionInfo(lldb::addr_t addr,
+ MemoryRegionInfo &region);
+
+ LazyBool GetThreadPacketSupported(lldb::tid_t tid, llvm::StringRef packetStr);
+
+private:
+ GDBRemoteCommunicationClient(const GDBRemoteCommunicationClient &) = delete;
+ const GDBRemoteCommunicationClient &
+ operator=(const GDBRemoteCommunicationClient &) = delete;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONCLIENT_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp
new file mode 100644
index 000000000000..5d4a537befeb
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp
@@ -0,0 +1,95 @@
+//===-- GDBRemoteCommunicationHistory.cpp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteCommunicationHistory.h"
+
+// Other libraries and framework includes
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+GDBRemoteCommunicationHistory::GDBRemoteCommunicationHistory(uint32_t size)
+ : m_packets() {
+ if (size)
+ m_packets.resize(size);
+}
+
+GDBRemoteCommunicationHistory::~GDBRemoteCommunicationHistory() = default;
+
+void GDBRemoteCommunicationHistory::AddPacket(char packet_char,
+ GDBRemotePacket::Type type,
+ uint32_t bytes_transmitted) {
+ const size_t size = m_packets.size();
+ if (size == 0)
+ return;
+
+ const uint32_t idx = GetNextIndex();
+ m_packets[idx].packet.data.assign(1, packet_char);
+ m_packets[idx].type = type;
+ m_packets[idx].bytes_transmitted = bytes_transmitted;
+ m_packets[idx].packet_idx = m_total_packet_count;
+ m_packets[idx].tid = llvm::get_threadid();
+}
+
+void GDBRemoteCommunicationHistory::AddPacket(const std::string &src,
+ uint32_t src_len,
+ GDBRemotePacket::Type type,
+ uint32_t bytes_transmitted) {
+ const size_t size = m_packets.size();
+ if (size == 0)
+ return;
+
+ const uint32_t idx = GetNextIndex();
+ m_packets[idx].packet.data.assign(src, 0, src_len);
+ m_packets[idx].type = type;
+ m_packets[idx].bytes_transmitted = bytes_transmitted;
+ m_packets[idx].packet_idx = m_total_packet_count;
+ m_packets[idx].tid = llvm::get_threadid();
+}
+
+void GDBRemoteCommunicationHistory::Dump(Stream &strm) const {
+ const uint32_t size = GetNumPacketsInHistory();
+ const uint32_t first_idx = GetFirstSavedPacketIndex();
+ const uint32_t stop_idx = m_curr_idx + size;
+ for (uint32_t i = first_idx; i < stop_idx; ++i) {
+ const uint32_t idx = NormalizeIndex(i);
+ const GDBRemotePacket &entry = m_packets[idx];
+ if (entry.type == GDBRemotePacket::ePacketTypeInvalid ||
+ entry.packet.data.empty())
+ break;
+ strm.Printf("history[%u] ", entry.packet_idx);
+ entry.Dump(strm);
+ }
+}
+
+void GDBRemoteCommunicationHistory::Dump(Log *log) const {
+ if (!log || m_dumped_to_log)
+ return;
+
+ m_dumped_to_log = true;
+ const uint32_t size = GetNumPacketsInHistory();
+ const uint32_t first_idx = GetFirstSavedPacketIndex();
+ const uint32_t stop_idx = m_curr_idx + size;
+ for (uint32_t i = first_idx; i < stop_idx; ++i) {
+ const uint32_t idx = NormalizeIndex(i);
+ const GDBRemotePacket &entry = m_packets[idx];
+ if (entry.type == GDBRemotePacket::ePacketTypeInvalid ||
+ entry.packet.data.empty())
+ break;
+ LLDB_LOGF(log, "history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s",
+ entry.packet_idx, entry.tid, entry.bytes_transmitted,
+ (entry.type == GDBRemotePacket::ePacketTypeSend) ? "send"
+ : "read",
+ entry.packet.data.c_str());
+ }
+}
+
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h
new file mode 100644
index 000000000000..2fbc621a90e7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h
@@ -0,0 +1,76 @@
+//===-- GDBRemoteCommunicationHistory.h--------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONHISTORY_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONHISTORY_H
+
+#include <string>
+#include <vector>
+
+#include "lldb/Utility/GDBRemote.h"
+#include "lldb/lldb-public.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+/// The history keeps a circular buffer of GDB remote packets. The history is
+/// used for logging and replaying GDB remote packets.
+class GDBRemoteCommunicationHistory {
+public:
+ GDBRemoteCommunicationHistory(uint32_t size = 0);
+
+ ~GDBRemoteCommunicationHistory();
+
+ // For single char packets for ack, nack and /x03
+ void AddPacket(char packet_char, GDBRemotePacket::Type type,
+ uint32_t bytes_transmitted);
+
+ void AddPacket(const std::string &src, uint32_t src_len,
+ GDBRemotePacket::Type type, uint32_t bytes_transmitted);
+
+ void Dump(Stream &strm) const;
+ void Dump(Log *log) const;
+ bool DidDumpToLog() const { return m_dumped_to_log; }
+
+private:
+ uint32_t GetFirstSavedPacketIndex() const {
+ if (m_total_packet_count < m_packets.size())
+ return 0;
+ else
+ return m_curr_idx + 1;
+ }
+
+ uint32_t GetNumPacketsInHistory() const {
+ if (m_total_packet_count < m_packets.size())
+ return m_total_packet_count;
+ else
+ return (uint32_t)m_packets.size();
+ }
+
+ uint32_t GetNextIndex() {
+ ++m_total_packet_count;
+ const uint32_t idx = m_curr_idx;
+ m_curr_idx = NormalizeIndex(idx + 1);
+ return idx;
+ }
+
+ uint32_t NormalizeIndex(uint32_t i) const {
+ return m_packets.empty() ? 0 : i % m_packets.size();
+ }
+
+ std::vector<GDBRemotePacket> m_packets;
+ uint32_t m_curr_idx = 0;
+ uint32_t m_total_packet_count = 0;
+ mutable bool m_dumped_to_log = false;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONHISTORY_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
new file mode 100644
index 000000000000..e7a292f858a8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -0,0 +1,168 @@
+//===-- GDBRemoteCommunicationServer.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+
+#include "lldb/Host/Config.h"
+
+#include "GDBRemoteCommunicationServer.h"
+
+#include "ProcessGDBRemoteLog.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StringExtractorGDBRemote.h"
+#include "lldb/Utility/UnimplementedError.h"
+#include "llvm/Support/JSON.h"
+#include <cstring>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace llvm;
+
+GDBRemoteCommunicationServer::GDBRemoteCommunicationServer()
+ : GDBRemoteCommunication(), m_exit_now(false) {
+ RegisterPacketHandler(
+ StringExtractorGDBRemote::eServerPacketType_QEnableErrorStrings,
+ [this](StringExtractorGDBRemote packet, Status &error, bool &interrupt,
+ bool &quit) { return this->Handle_QErrorStringEnable(packet); });
+}
+
+GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() = default;
+
+void GDBRemoteCommunicationServer::RegisterPacketHandler(
+ StringExtractorGDBRemote::ServerPacketType packet_type,
+ PacketHandler handler) {
+ m_packet_handlers[packet_type] = std::move(handler);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::GetPacketAndSendResponse(
+ Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) {
+ StringExtractorGDBRemote packet;
+
+ PacketResult packet_result = ReadPacket(packet, timeout, false);
+ if (packet_result == PacketResult::Success) {
+ const StringExtractorGDBRemote::ServerPacketType packet_type =
+ packet.GetServerPacketType();
+ switch (packet_type) {
+ case StringExtractorGDBRemote::eServerPacketType_nack:
+ case StringExtractorGDBRemote::eServerPacketType_ack:
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_invalid:
+ error.SetErrorString("invalid packet");
+ quit = true;
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_unimplemented:
+ packet_result = SendUnimplementedResponse(packet.GetStringRef().data());
+ break;
+
+ default:
+ auto handler_it = m_packet_handlers.find(packet_type);
+ if (handler_it == m_packet_handlers.end())
+ packet_result = SendUnimplementedResponse(packet.GetStringRef().data());
+ else
+ packet_result = handler_it->second(packet, error, interrupt, quit);
+ break;
+ }
+ } else {
+ if (!IsConnected()) {
+ error.SetErrorString("lost connection");
+ quit = true;
+ } else {
+ error.SetErrorString("timeout");
+ }
+ }
+
+ // Check if anything occurred that would force us to want to exit.
+ if (m_exit_now)
+ quit = true;
+
+ return packet_result;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendUnimplementedResponse(const char *) {
+ // TODO: Log the packet we aren't handling...
+ return SendPacketNoLock("");
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendErrorResponse(uint8_t err) {
+ char packet[16];
+ int packet_len = ::snprintf(packet, sizeof(packet), "E%2.2x", err);
+ assert(packet_len < (int)sizeof(packet));
+ return SendPacketNoLock(llvm::StringRef(packet, packet_len));
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendErrorResponse(const Status &error) {
+ if (m_send_error_strings) {
+ lldb_private::StreamString packet;
+ packet.Printf("E%2.2x;", static_cast<uint8_t>(error.GetError()));
+ packet.PutStringAsRawHex8(error.AsCString());
+ return SendPacketNoLock(packet.GetString());
+ } else
+ return SendErrorResponse(error.GetError());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendErrorResponse(llvm::Error error) {
+ assert(error);
+ std::unique_ptr<llvm::ErrorInfoBase> EIB;
+ std::unique_ptr<UnimplementedError> UE;
+ llvm::handleAllErrors(
+ std::move(error),
+ [&](std::unique_ptr<UnimplementedError> E) { UE = std::move(E); },
+ [&](std::unique_ptr<llvm::ErrorInfoBase> E) { EIB = std::move(E); });
+
+ if (EIB)
+ return SendErrorResponse(Status(llvm::Error(std::move(EIB))));
+ return SendUnimplementedResponse("");
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QErrorStringEnable(
+ StringExtractorGDBRemote &packet) {
+ m_send_error_strings = true;
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendIllFormedResponse(
+ const StringExtractorGDBRemote &failed_packet, const char *message) {
+ Log *log = GetLog(GDBRLog::Packets);
+ LLDB_LOGF(log, "GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)",
+ __FUNCTION__, failed_packet.GetStringRef().data(),
+ message ? message : "");
+ return SendErrorResponse(0x03);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendOKResponse() {
+ return SendPacketNoLock("OK");
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendJSONResponse(const json::Value &value) {
+ std::string json_string;
+ raw_string_ostream os(json_string);
+ os << value;
+ os.flush();
+ StreamGDBRemote escaped_response;
+ escaped_response.PutEscapedBytes(json_string.c_str(), json_string.size());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendJSONResponse(Expected<json::Value> value) {
+ if (!value)
+ return SendErrorResponse(value.takeError());
+ return SendJSONResponse(*value);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
new file mode 100644
index 000000000000..ccbcd0ac5bf5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -0,0 +1,86 @@
+//===-- GDBRemoteCommunicationServer.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVER_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVER_H
+
+#include <functional>
+#include <map>
+
+#include "GDBRemoteCommunication.h"
+#include "lldb/lldb-private-forward.h"
+
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+
+class StringExtractorGDBRemote;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunicationServer : public GDBRemoteCommunication {
+public:
+ using PacketHandler =
+ std::function<PacketResult(StringExtractorGDBRemote &packet,
+ Status &error, bool &interrupt, bool &quit)>;
+
+ GDBRemoteCommunicationServer();
+
+ ~GDBRemoteCommunicationServer() override;
+
+ void
+ RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type,
+ PacketHandler handler);
+
+ PacketResult GetPacketAndSendResponse(Timeout<std::micro> timeout,
+ Status &error, bool &interrupt,
+ bool &quit);
+
+protected:
+ std::map<StringExtractorGDBRemote::ServerPacketType, PacketHandler>
+ m_packet_handlers;
+ bool m_exit_now; // use in asynchronous handling to indicate process should
+ // exit.
+
+ bool m_send_error_strings = false; // If the client enables this then
+ // we will send error strings as well.
+
+ PacketResult Handle_QErrorStringEnable(StringExtractorGDBRemote &packet);
+
+ PacketResult SendErrorResponse(const Status &error);
+
+ PacketResult SendErrorResponse(llvm::Error error);
+
+ PacketResult SendUnimplementedResponse(const char *packet);
+
+ PacketResult SendErrorResponse(uint8_t error);
+
+ PacketResult SendIllFormedResponse(const StringExtractorGDBRemote &packet,
+ const char *error_message);
+
+ PacketResult SendOKResponse();
+
+ /// Serialize and send a JSON object response.
+ PacketResult SendJSONResponse(const llvm::json::Value &value);
+
+ /// Serialize and send a JSON object response, or respond with an error if the
+ /// input object is an \a llvm::Error.
+ PacketResult SendJSONResponse(llvm::Expected<llvm::json::Value> value);
+
+private:
+ GDBRemoteCommunicationServer(const GDBRemoteCommunicationServer &) = delete;
+ const GDBRemoteCommunicationServer &
+ operator=(const GDBRemoteCommunicationServer &) = delete;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
new file mode 100644
index 000000000000..f9d37490e16a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -0,0 +1,1388 @@
+//===-- GDBRemoteCommunicationServerCommon.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteCommunicationServerCommon.h"
+
+#include <cerrno>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#include <chrono>
+#include <cstring>
+#include <optional>
+
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileAction.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/SafeMachO.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/GDBRemote.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StructuredData.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/TargetParser/Triple.h"
+
+#include "ProcessGDBRemoteLog.h"
+#include "lldb/Utility/StringExtractorGDBRemote.h"
+
+#ifdef __ANDROID__
+#include "lldb/Host/android/HostInfoAndroid.h"
+#include "lldb/Host/common/ZipFileResolver.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private;
+
+#ifdef __ANDROID__
+const static uint32_t g_default_packet_timeout_sec = 20; // seconds
+#else
+const static uint32_t g_default_packet_timeout_sec = 0; // not specified
+#endif
+
+// GDBRemoteCommunicationServerCommon constructor
+GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon()
+ : GDBRemoteCommunicationServer(), m_process_launch_info(),
+ m_process_launch_error(), m_proc_infos(), m_proc_infos_index(0) {
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A,
+ &GDBRemoteCommunicationServerCommon::Handle_A);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QEnvironment,
+ &GDBRemoteCommunicationServerCommon::Handle_QEnvironment);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QEnvironmentHexEncoded,
+ &GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qfProcessInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qGroupName,
+ &GDBRemoteCommunicationServerCommon::Handle_qGroupName);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qHostInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qHostInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QLaunchArch,
+ &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess,
+ &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qEcho,
+ &GDBRemoteCommunicationServerCommon::Handle_qEcho);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qModuleInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jModulesInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_jModulesInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod,
+ &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir,
+ &GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qPlatform_shell,
+ &GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID,
+ &GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QSetSTDERR,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QSetSTDIN,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qSpeedTest,
+ &GDBRemoteCommunicationServerCommon::Handle_qSpeedTest);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qsProcessInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode,
+ &GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qSupported,
+ &GDBRemoteCommunicationServerCommon::Handle_qSupported);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qUserName,
+ &GDBRemoteCommunicationServerCommon::Handle_qUserName);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_close,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Close);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_exists,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Exists);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_md5,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_MD5);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_mode,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Mode);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_open,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Open);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_pread,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_pRead);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_pwrite,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_size,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Size);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_fstat,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_FStat);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_stat,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Stat);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_symlink,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_symlink);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_unlink,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_unlink);
+}
+
+// Destructor
+GDBRemoteCommunicationServerCommon::~GDBRemoteCommunicationServerCommon() =
+ default;
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qHostInfo(
+ StringExtractorGDBRemote &packet) {
+ StreamString response;
+
+ // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
+
+ ArchSpec host_arch(HostInfo::GetArchitecture());
+ const llvm::Triple &host_triple = host_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutStringAsRawHex8(host_triple.getTriple());
+ response.Printf(";ptrsize:%u;", host_arch.GetAddressByteSize());
+
+ llvm::StringRef distribution_id = HostInfo::GetDistributionId();
+ if (!distribution_id.empty()) {
+ response.PutCString("distribution_id:");
+ response.PutStringAsRawHex8(distribution_id);
+ response.PutCString(";");
+ }
+
+#if defined(__APPLE__)
+ // For parity with debugserver, we'll include the vendor key.
+ response.PutCString("vendor:apple;");
+
+ // Send out MachO info.
+ uint32_t cpu = host_arch.GetMachOCPUType();
+ uint32_t sub = host_arch.GetMachOCPUSubType();
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ response.Printf("cputype:%u;", cpu);
+ if (sub != LLDB_INVALID_CPUTYPE)
+ response.Printf("cpusubtype:%u;", sub);
+
+ if (cpu == llvm::MachO::CPU_TYPE_ARM || cpu == llvm::MachO::CPU_TYPE_ARM64) {
+// Indicate the OS type.
+#if defined(TARGET_OS_TV) && TARGET_OS_TV == 1
+ response.PutCString("ostype:tvos;");
+#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
+ response.PutCString("ostype:watchos;");
+#elif defined(TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE == 1
+ response.PutCString("ostype:bridgeos;");
+#else
+ response.PutCString("ostype:ios;");
+#endif
+
+ // On arm, we use "synchronous" watchpoints which means the exception is
+ // delivered before the instruction executes.
+ response.PutCString("watchpoint_exceptions_received:before;");
+ } else {
+ response.PutCString("ostype:macosx;");
+ response.Printf("watchpoint_exceptions_received:after;");
+ }
+
+#else
+ if (host_arch.GetMachine() == llvm::Triple::aarch64 ||
+ host_arch.GetMachine() == llvm::Triple::aarch64_32 ||
+ host_arch.GetMachine() == llvm::Triple::aarch64_be ||
+ host_arch.GetMachine() == llvm::Triple::arm ||
+ host_arch.GetMachine() == llvm::Triple::armeb || host_arch.IsMIPS())
+ response.Printf("watchpoint_exceptions_received:before;");
+ else
+ response.Printf("watchpoint_exceptions_received:after;");
+#endif
+
+ switch (endian::InlHostByteOrder()) {
+ case eByteOrderBig:
+ response.PutCString("endian:big;");
+ break;
+ case eByteOrderLittle:
+ response.PutCString("endian:little;");
+ break;
+ case eByteOrderPDP:
+ response.PutCString("endian:pdp;");
+ break;
+ default:
+ response.PutCString("endian:unknown;");
+ break;
+ }
+
+ llvm::VersionTuple version = HostInfo::GetOSVersion();
+ if (!version.empty()) {
+ response.Format("os_version:{0}", version.getAsString());
+ response.PutChar(';');
+ }
+
+#if defined(__APPLE__)
+ llvm::VersionTuple maccatalyst_version = HostInfo::GetMacCatalystVersion();
+ if (!maccatalyst_version.empty()) {
+ response.Format("maccatalyst_version:{0}",
+ maccatalyst_version.getAsString());
+ response.PutChar(';');
+ }
+#endif
+
+ if (std::optional<std::string> s = HostInfo::GetOSBuildString()) {
+ response.PutCString("os_build:");
+ response.PutStringAsRawHex8(*s);
+ response.PutChar(';');
+ }
+ if (std::optional<std::string> s = HostInfo::GetOSKernelDescription()) {
+ response.PutCString("os_kernel:");
+ response.PutStringAsRawHex8(*s);
+ response.PutChar(';');
+ }
+
+ std::string s;
+#if defined(__APPLE__)
+
+#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ // For iOS devices, we are connected through a USB Mux so we never pretend to
+ // actually have a hostname as far as the remote lldb that is connecting to
+ // this lldb-platform is concerned
+ response.PutCString("hostname:");
+ response.PutStringAsRawHex8("127.0.0.1");
+ response.PutChar(';');
+#else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ if (HostInfo::GetHostname(s)) {
+ response.PutCString("hostname:");
+ response.PutStringAsRawHex8(s);
+ response.PutChar(';');
+ }
+#endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+
+#else // #if defined(__APPLE__)
+ if (HostInfo::GetHostname(s)) {
+ response.PutCString("hostname:");
+ response.PutStringAsRawHex8(s);
+ response.PutChar(';');
+ }
+#endif // #if defined(__APPLE__)
+ // coverity[unsigned_compare]
+ if (g_default_packet_timeout_sec > 0)
+ response.Printf("default_packet_timeout:%u;", g_default_packet_timeout_sec);
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID(
+ StringExtractorGDBRemote &packet) {
+ // Packet format: "qProcessInfoPID:%i" where %i is the pid
+ packet.SetFilePos(::strlen("qProcessInfoPID:"));
+ lldb::pid_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID);
+ if (pid != LLDB_INVALID_PROCESS_ID) {
+ ProcessInstanceInfo proc_info;
+ if (Host::GetProcessInfo(pid, proc_info)) {
+ StreamString response;
+ CreateProcessInfoResponse(proc_info, response);
+ return SendPacketNoLock(response.GetString());
+ }
+ }
+ return SendErrorResponse(1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo(
+ StringExtractorGDBRemote &packet) {
+ m_proc_infos_index = 0;
+ m_proc_infos.clear();
+
+ ProcessInstanceInfoMatch match_info;
+ packet.SetFilePos(::strlen("qfProcessInfo"));
+ if (packet.GetChar() == ':') {
+ llvm::StringRef key;
+ llvm::StringRef value;
+ while (packet.GetNameColonValue(key, value)) {
+ bool success = true;
+ if (key == "name") {
+ StringExtractor extractor(value);
+ std::string file;
+ extractor.GetHexByteString(file);
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(
+ file, FileSpec::Style::native);
+ } else if (key == "name_match") {
+ NameMatch name_match = llvm::StringSwitch<NameMatch>(value)
+ .Case("equals", NameMatch::Equals)
+ .Case("starts_with", NameMatch::StartsWith)
+ .Case("ends_with", NameMatch::EndsWith)
+ .Case("contains", NameMatch::Contains)
+ .Case("regex", NameMatch::RegularExpression)
+ .Default(NameMatch::Ignore);
+ match_info.SetNameMatchType(name_match);
+ if (name_match == NameMatch::Ignore)
+ return SendErrorResponse(2);
+ } else if (key == "pid") {
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ if (value.getAsInteger(0, pid))
+ return SendErrorResponse(2);
+ match_info.GetProcessInfo().SetProcessID(pid);
+ } else if (key == "parent_pid") {
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ if (value.getAsInteger(0, pid))
+ return SendErrorResponse(2);
+ match_info.GetProcessInfo().SetParentProcessID(pid);
+ } else if (key == "uid") {
+ uint32_t uid = UINT32_MAX;
+ if (value.getAsInteger(0, uid))
+ return SendErrorResponse(2);
+ match_info.GetProcessInfo().SetUserID(uid);
+ } else if (key == "gid") {
+ uint32_t gid = UINT32_MAX;
+ if (value.getAsInteger(0, gid))
+ return SendErrorResponse(2);
+ match_info.GetProcessInfo().SetGroupID(gid);
+ } else if (key == "euid") {
+ uint32_t uid = UINT32_MAX;
+ if (value.getAsInteger(0, uid))
+ return SendErrorResponse(2);
+ match_info.GetProcessInfo().SetEffectiveUserID(uid);
+ } else if (key == "egid") {
+ uint32_t gid = UINT32_MAX;
+ if (value.getAsInteger(0, gid))
+ return SendErrorResponse(2);
+ match_info.GetProcessInfo().SetEffectiveGroupID(gid);
+ } else if (key == "all_users") {
+ match_info.SetMatchAllUsers(
+ OptionArgParser::ToBoolean(value, false, &success));
+ } else if (key == "triple") {
+ match_info.GetProcessInfo().GetArchitecture() =
+ HostInfo::GetAugmentedArchSpec(value);
+ } else {
+ success = false;
+ }
+
+ if (!success)
+ return SendErrorResponse(2);
+ }
+ }
+
+ if (Host::FindProcesses(match_info, m_proc_infos)) {
+ // We found something, return the first item by calling the get subsequent
+ // process info packet handler...
+ return Handle_qsProcessInfo(packet);
+ }
+ return SendErrorResponse(3);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo(
+ StringExtractorGDBRemote &packet) {
+ if (m_proc_infos_index < m_proc_infos.size()) {
+ StreamString response;
+ CreateProcessInfoResponse(m_proc_infos[m_proc_infos_index], response);
+ ++m_proc_infos_index;
+ return SendPacketNoLock(response.GetString());
+ }
+ return SendErrorResponse(4);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qUserName(
+ StringExtractorGDBRemote &packet) {
+#if LLDB_ENABLE_POSIX
+ Log *log = GetLog(LLDBLog::Process);
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__);
+
+ // Packet format: "qUserName:%i" where %i is the uid
+ packet.SetFilePos(::strlen("qUserName:"));
+ uint32_t uid = packet.GetU32(UINT32_MAX);
+ if (uid != UINT32_MAX) {
+ if (std::optional<llvm::StringRef> name =
+ HostInfo::GetUserIDResolver().GetUserName(uid)) {
+ StreamString response;
+ response.PutStringAsRawHex8(*name);
+ return SendPacketNoLock(response.GetString());
+ }
+ }
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerCommon::%s end", __FUNCTION__);
+#endif
+ return SendErrorResponse(5);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qGroupName(
+ StringExtractorGDBRemote &packet) {
+#if LLDB_ENABLE_POSIX
+ // Packet format: "qGroupName:%i" where %i is the gid
+ packet.SetFilePos(::strlen("qGroupName:"));
+ uint32_t gid = packet.GetU32(UINT32_MAX);
+ if (gid != UINT32_MAX) {
+ if (std::optional<llvm::StringRef> name =
+ HostInfo::GetUserIDResolver().GetGroupName(gid)) {
+ StreamString response;
+ response.PutStringAsRawHex8(*name);
+ return SendPacketNoLock(response.GetString());
+ }
+ }
+#endif
+ return SendErrorResponse(6);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qSpeedTest(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("qSpeedTest:"));
+
+ llvm::StringRef key;
+ llvm::StringRef value;
+ bool success = packet.GetNameColonValue(key, value);
+ if (success && key == "response_size") {
+ uint32_t response_size = 0;
+ if (!value.getAsInteger(0, response_size)) {
+ if (response_size == 0)
+ return SendOKResponse();
+ StreamString response;
+ uint32_t bytes_left = response_size;
+ response.PutCString("data:");
+ while (bytes_left > 0) {
+ if (bytes_left >= 26) {
+ response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left -= 26;
+ } else {
+ response.Printf("%*.*s;", bytes_left, bytes_left,
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left = 0;
+ }
+ }
+ return SendPacketNoLock(response.GetString());
+ }
+ }
+ return SendErrorResponse(7);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Open(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("vFile:open:"));
+ std::string path;
+ packet.GetHexByteStringTerminatedBy(path, ',');
+ if (!path.empty()) {
+ if (packet.GetChar() == ',') {
+ auto flags = File::OpenOptions(packet.GetHexMaxU32(false, 0));
+ if (packet.GetChar() == ',') {
+ mode_t mode = packet.GetHexMaxU32(false, 0600);
+ FileSpec path_spec(path);
+ FileSystem::Instance().Resolve(path_spec);
+ // Do not close fd.
+ auto file = FileSystem::Instance().Open(path_spec, flags, mode, false);
+
+ StreamString response;
+ response.PutChar('F');
+
+ int descriptor = File::kInvalidDescriptor;
+ if (file) {
+ descriptor = file.get()->GetDescriptor();
+ response.Printf("%x", descriptor);
+ } else {
+ response.PutCString("-1");
+ std::error_code code = errorToErrorCode(file.takeError());
+ if (code.category() == std::system_category()) {
+ response.Printf(",%x", code.value());
+ }
+ }
+
+ return SendPacketNoLock(response.GetString());
+ }
+ }
+ }
+ return SendErrorResponse(18);
+}
+
+static GDBErrno system_errno_to_gdb(int err) {
+ switch (err) {
+#define HANDLE_ERRNO(name, value) \
+ case name: \
+ return GDB_##name;
+#include "Plugins/Process/gdb-remote/GDBRemoteErrno.def"
+ default:
+ return GDB_EUNKNOWN;
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Close(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("vFile:close:"));
+ int fd = packet.GetS32(-1, 16);
+ int err = -1;
+ int save_errno = 0;
+ if (fd >= 0) {
+ NativeFile file(fd, File::OpenOptions(0), true);
+ Status error = file.Close();
+ err = 0;
+ save_errno = error.GetError();
+ } else {
+ save_errno = EINVAL;
+ }
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%x", err);
+ if (save_errno)
+ response.Printf(",%x", system_errno_to_gdb(save_errno));
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_pRead(
+ StringExtractorGDBRemote &packet) {
+ StreamGDBRemote response;
+ packet.SetFilePos(::strlen("vFile:pread:"));
+ int fd = packet.GetS32(-1, 16);
+ if (packet.GetChar() == ',') {
+ size_t count = packet.GetHexMaxU64(false, SIZE_MAX);
+ if (packet.GetChar() == ',') {
+ off_t offset = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (count == SIZE_MAX) {
+ response.Printf("F-1:%x", EINVAL);
+ return SendPacketNoLock(response.GetString());
+ }
+
+ std::string buffer(count, 0);
+ NativeFile file(fd, File::eOpenOptionReadOnly, false);
+ Status error = file.Read(static_cast<void *>(&buffer[0]), count, offset);
+ const int save_errno = error.GetError();
+ response.PutChar('F');
+ if (error.Success()) {
+ response.Printf("%zx", count);
+ response.PutChar(';');
+ response.PutEscapedBytes(&buffer[0], count);
+ } else {
+ response.PutCString("-1");
+ if (save_errno)
+ response.Printf(",%x", system_errno_to_gdb(save_errno));
+ }
+ return SendPacketNoLock(response.GetString());
+ }
+ }
+ return SendErrorResponse(21);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("vFile:pwrite:"));
+
+ StreamGDBRemote response;
+ response.PutChar('F');
+
+ int fd = packet.GetS32(-1, 16);
+ if (packet.GetChar() == ',') {
+ off_t offset = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() == ',') {
+ std::string buffer;
+ if (packet.GetEscapedBinaryData(buffer)) {
+ NativeFile file(fd, File::eOpenOptionWriteOnly, false);
+ size_t count = buffer.size();
+ Status error =
+ file.Write(static_cast<const void *>(&buffer[0]), count, offset);
+ const int save_errno = error.GetError();
+ if (error.Success())
+ response.Printf("%zx", count);
+ else {
+ response.PutCString("-1");
+ if (save_errno)
+ response.Printf(",%x", system_errno_to_gdb(save_errno));
+ }
+ } else {
+ response.Printf("-1,%x", EINVAL);
+ }
+ return SendPacketNoLock(response.GetString());
+ }
+ }
+ return SendErrorResponse(27);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Size(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("vFile:size:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty()) {
+ uint64_t Size;
+ if (llvm::sys::fs::file_size(path, Size))
+ return SendErrorResponse(5);
+ StreamString response;
+ response.PutChar('F');
+ response.PutHex64(Size);
+ if (Size == UINT64_MAX) {
+ response.PutChar(',');
+ response.PutHex64(Size); // TODO: replace with Host::GetSyswideErrorCode()
+ }
+ return SendPacketNoLock(response.GetString());
+ }
+ return SendErrorResponse(22);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Mode(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("vFile:mode:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty()) {
+ FileSpec file_spec(path);
+ FileSystem::Instance().Resolve(file_spec);
+ std::error_code ec;
+ const uint32_t mode = FileSystem::Instance().GetPermissions(file_spec, ec);
+ StreamString response;
+ if (mode != llvm::sys::fs::perms_not_known)
+ response.Printf("F%x", mode);
+ else
+ response.Printf("F-1,%x", (int)Status(ec).GetError());
+ return SendPacketNoLock(response.GetString());
+ }
+ return SendErrorResponse(23);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Exists(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("vFile:exists:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty()) {
+ bool retcode = llvm::sys::fs::exists(path);
+ StreamString response;
+ response.PutChar('F');
+ response.PutChar(',');
+ if (retcode)
+ response.PutChar('1');
+ else
+ response.PutChar('0');
+ return SendPacketNoLock(response.GetString());
+ }
+ return SendErrorResponse(24);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_symlink(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("vFile:symlink:"));
+ std::string dst, src;
+ packet.GetHexByteStringTerminatedBy(dst, ',');
+ packet.GetChar(); // Skip ',' char
+ packet.GetHexByteString(src);
+
+ FileSpec src_spec(src);
+ FileSystem::Instance().Resolve(src_spec);
+ Status error = FileSystem::Instance().Symlink(src_spec, FileSpec(dst));
+
+ StreamString response;
+ response.Printf("F%x,%x", error.GetError(), error.GetError());
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_unlink(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("vFile:unlink:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ Status error(llvm::sys::fs::remove(path));
+ StreamString response;
+ response.Printf("F%x,%x", error.GetError(), error.GetError());
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("qPlatform_shell:"));
+ std::string path;
+ std::string working_dir;
+ packet.GetHexByteStringTerminatedBy(path, ',');
+ if (!path.empty()) {
+ if (packet.GetChar() == ',') {
+ // FIXME: add timeout to qPlatform_shell packet
+ // uint32_t timeout = packet.GetHexMaxU32(false, 32);
+ if (packet.GetChar() == ',')
+ packet.GetHexByteString(working_dir);
+ int status, signo;
+ std::string output;
+ FileSpec working_spec(working_dir);
+ FileSystem::Instance().Resolve(working_spec);
+ Status err =
+ Host::RunShellCommand(path.c_str(), working_spec, &status, &signo,
+ &output, std::chrono::seconds(10));
+ StreamGDBRemote response;
+ if (err.Fail()) {
+ response.PutCString("F,");
+ response.PutHex32(UINT32_MAX);
+ } else {
+ response.PutCString("F,");
+ response.PutHex32(status);
+ response.PutChar(',');
+ response.PutHex32(signo);
+ response.PutChar(',');
+ response.PutEscapedBytes(output.c_str(), output.size());
+ }
+ return SendPacketNoLock(response.GetString());
+ }
+ }
+ return SendErrorResponse(24);
+}
+
+template <typename T, typename U>
+static void fill_clamp(T &dest, U src, typename T::value_type fallback) {
+ static_assert(std::is_unsigned<typename T::value_type>::value,
+ "Destination type must be unsigned.");
+ using UU = std::make_unsigned_t<U>;
+ constexpr auto T_max = std::numeric_limits<typename T::value_type>::max();
+ dest = src >= 0 && static_cast<UU>(src) <= T_max ? src : fallback;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_FStat(
+ StringExtractorGDBRemote &packet) {
+ StreamGDBRemote response;
+ packet.SetFilePos(::strlen("vFile:fstat:"));
+ int fd = packet.GetS32(-1, 16);
+
+ struct stat file_stats;
+ if (::fstat(fd, &file_stats) == -1) {
+ const int save_errno = errno;
+ response.Printf("F-1,%x", system_errno_to_gdb(save_errno));
+ return SendPacketNoLock(response.GetString());
+ }
+
+ GDBRemoteFStatData data;
+ fill_clamp(data.gdb_st_dev, file_stats.st_dev, 0);
+ fill_clamp(data.gdb_st_ino, file_stats.st_ino, 0);
+ data.gdb_st_mode = file_stats.st_mode;
+ fill_clamp(data.gdb_st_nlink, file_stats.st_nlink, UINT32_MAX);
+ fill_clamp(data.gdb_st_uid, file_stats.st_uid, 0);
+ fill_clamp(data.gdb_st_gid, file_stats.st_gid, 0);
+ fill_clamp(data.gdb_st_rdev, file_stats.st_rdev, 0);
+ data.gdb_st_size = file_stats.st_size;
+#if !defined(_WIN32)
+ data.gdb_st_blksize = file_stats.st_blksize;
+ data.gdb_st_blocks = file_stats.st_blocks;
+#else
+ data.gdb_st_blksize = 0;
+ data.gdb_st_blocks = 0;
+#endif
+ fill_clamp(data.gdb_st_atime, file_stats.st_atime, 0);
+ fill_clamp(data.gdb_st_mtime, file_stats.st_mtime, 0);
+ fill_clamp(data.gdb_st_ctime, file_stats.st_ctime, 0);
+
+ response.Printf("F%zx;", sizeof(data));
+ response.PutEscapedBytes(&data, sizeof(data));
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Stat(
+ StringExtractorGDBRemote &packet) {
+ return SendUnimplementedResponse(
+ "GDBRemoteCommunicationServerCommon::Handle_vFile_Stat() unimplemented");
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_MD5(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("vFile:MD5:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty()) {
+ StreamGDBRemote response;
+ auto Result = llvm::sys::fs::md5_contents(path);
+ if (!Result) {
+ response.PutCString("F,");
+ response.PutCString("x");
+ } else {
+ response.PutCString("F,");
+ response.PutHex64(Result->low());
+ response.PutHex64(Result->high());
+ }
+ return SendPacketNoLock(response.GetString());
+ }
+ return SendErrorResponse(25);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("qPlatform_mkdir:"));
+ mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() == ',') {
+ std::string path;
+ packet.GetHexByteString(path);
+ Status error(llvm::sys::fs::create_directory(path, mode));
+
+ StreamGDBRemote response;
+ response.Printf("F%x", error.GetError());
+
+ return SendPacketNoLock(response.GetString());
+ }
+ return SendErrorResponse(20);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("qPlatform_chmod:"));
+
+ auto perms =
+ static_cast<llvm::sys::fs::perms>(packet.GetHexMaxU32(false, UINT32_MAX));
+ if (packet.GetChar() == ',') {
+ std::string path;
+ packet.GetHexByteString(path);
+ Status error(llvm::sys::fs::setPermissions(path, perms));
+
+ StreamGDBRemote response;
+ response.Printf("F%x", error.GetError());
+
+ return SendPacketNoLock(response.GetString());
+ }
+ return SendErrorResponse(19);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qSupported(
+ StringExtractorGDBRemote &packet) {
+ // Parse client-indicated features.
+ llvm::SmallVector<llvm::StringRef, 4> client_features;
+ packet.GetStringRef().split(client_features, ';');
+ return SendPacketNoLock(llvm::join(HandleFeatures(client_features), ";"));
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("QSetDetachOnError:"));
+ if (packet.GetU32(0))
+ m_process_launch_info.GetFlags().Set(eLaunchFlagDetachOnError);
+ else
+ m_process_launch_info.GetFlags().Clear(eLaunchFlagDetachOnError);
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode(
+ StringExtractorGDBRemote &packet) {
+ // Send response first before changing m_send_acks to we ack this packet
+ PacketResult packet_result = SendOKResponse();
+ m_send_acks = false;
+ return packet_result;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("QSetSTDIN:"));
+ FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDIN_FILENO, FileSpec(path), read, write)) {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse();
+ }
+ return SendErrorResponse(15);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("QSetSTDOUT:"));
+ FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDOUT_FILENO, FileSpec(path), read, write)) {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse();
+ }
+ return SendErrorResponse(16);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("QSetSTDERR:"));
+ FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDERR_FILENO, FileSpec(path), read, write)) {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse();
+ }
+ return SendErrorResponse(17);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess(
+ StringExtractorGDBRemote &packet) {
+ if (m_process_launch_error.Success())
+ return SendOKResponse();
+ StreamString response;
+ response.PutChar('E');
+ response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QEnvironment(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("QEnvironment:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0) {
+ m_process_launch_info.GetEnvironment().insert(packet.Peek());
+ return SendOKResponse();
+ }
+ return SendErrorResponse(12);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("QEnvironmentHexEncoded:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0) {
+ std::string str;
+ packet.GetHexByteString(str);
+ m_process_launch_info.GetEnvironment().insert(str);
+ return SendOKResponse();
+ }
+ return SendErrorResponse(12);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QLaunchArch(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("QLaunchArch:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0) {
+ const char *arch_triple = packet.Peek();
+ m_process_launch_info.SetArchitecture(
+ HostInfo::GetAugmentedArchSpec(arch_triple));
+ return SendOKResponse();
+ }
+ return SendErrorResponse(13);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) {
+ // The 'A' packet is the most over designed packet ever here with redundant
+ // argument indexes, redundant argument lengths and needed hex encoded
+ // argument string values. Really all that is needed is a comma separated hex
+ // encoded argument value list, but we will stay true to the documented
+ // version of the 'A' packet here...
+
+ Log *log = GetLog(LLDBLog::Process);
+ int actual_arg_index = 0;
+
+ packet.SetFilePos(1); // Skip the 'A'
+ bool success = true;
+ while (success && packet.GetBytesLeft() > 0) {
+ // Decode the decimal argument string length. This length is the number of
+ // hex nibbles in the argument string value.
+ const uint32_t arg_len = packet.GetU32(UINT32_MAX);
+ if (arg_len == UINT32_MAX)
+ success = false;
+ else {
+ // Make sure the argument hex string length is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else {
+ // Decode the argument index. We ignore this really because who would
+ // really send down the arguments in a random order???
+ const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
+ if (arg_idx == UINT32_MAX)
+ success = false;
+ else {
+ // Make sure the argument index is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else {
+ // Decode the argument string value from hex bytes back into a UTF8
+ // string and make sure the length matches the one supplied in the
+ // packet
+ std::string arg;
+ if (packet.GetHexByteStringFixedLength(arg, arg_len) !=
+ (arg_len / 2))
+ success = false;
+ else {
+ // If there are any bytes left
+ if (packet.GetBytesLeft()) {
+ if (packet.GetChar() != ',')
+ success = false;
+ }
+
+ if (success) {
+ if (arg_idx == 0)
+ m_process_launch_info.GetExecutableFile().SetFile(
+ arg, FileSpec::Style::native);
+ m_process_launch_info.GetArguments().AppendArgument(arg);
+ LLDB_LOGF(log, "LLGSPacketHandler::%s added arg %d: \"%s\"",
+ __FUNCTION__, actual_arg_index, arg.c_str());
+ ++actual_arg_index;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success) {
+ m_process_launch_error = LaunchProcess();
+ if (m_process_launch_error.Success())
+ return SendOKResponse();
+ LLDB_LOG(log, "failed to launch exe: {0}", m_process_launch_error);
+ }
+ return SendErrorResponse(8);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qEcho(
+ StringExtractorGDBRemote &packet) {
+ // Just echo back the exact same packet for qEcho...
+ return SendPacketNoLock(packet.GetStringRef());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qModuleInfo(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("qModuleInfo:"));
+
+ std::string module_path;
+ packet.GetHexByteStringTerminatedBy(module_path, ';');
+ if (module_path.empty())
+ return SendErrorResponse(1);
+
+ if (packet.GetChar() != ';')
+ return SendErrorResponse(2);
+
+ std::string triple;
+ packet.GetHexByteString(triple);
+
+ ModuleSpec matched_module_spec = GetModuleInfo(module_path, triple);
+ if (!matched_module_spec.GetFileSpec())
+ return SendErrorResponse(3);
+
+ const auto file_offset = matched_module_spec.GetObjectOffset();
+ const auto file_size = matched_module_spec.GetObjectSize();
+ const auto uuid_str = matched_module_spec.GetUUID().GetAsString("");
+
+ StreamGDBRemote response;
+
+ if (uuid_str.empty()) {
+ auto Result = llvm::sys::fs::md5_contents(
+ matched_module_spec.GetFileSpec().GetPath());
+ if (!Result)
+ return SendErrorResponse(5);
+ response.PutCString("md5:");
+ response.PutStringAsRawHex8(Result->digest());
+ } else {
+ response.PutCString("uuid:");
+ response.PutStringAsRawHex8(uuid_str);
+ }
+ response.PutChar(';');
+
+ const auto &module_arch = matched_module_spec.GetArchitecture();
+ response.PutCString("triple:");
+ response.PutStringAsRawHex8(module_arch.GetTriple().getTriple());
+ response.PutChar(';');
+
+ response.PutCString("file_path:");
+ response.PutStringAsRawHex8(
+ matched_module_spec.GetFileSpec().GetPath().c_str());
+ response.PutChar(';');
+ response.PutCString("file_offset:");
+ response.PutHex64(file_offset);
+ response.PutChar(';');
+ response.PutCString("file_size:");
+ response.PutHex64(file_size);
+ response.PutChar(';');
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_jModulesInfo(
+ StringExtractorGDBRemote &packet) {
+ namespace json = llvm::json;
+
+ packet.SetFilePos(::strlen("jModulesInfo:"));
+
+ StructuredData::ObjectSP object_sp = StructuredData::ParseJSON(packet.Peek());
+ if (!object_sp)
+ return SendErrorResponse(1);
+
+ StructuredData::Array *packet_array = object_sp->GetAsArray();
+ if (!packet_array)
+ return SendErrorResponse(2);
+
+ json::Array response_array;
+ for (size_t i = 0; i < packet_array->GetSize(); ++i) {
+ StructuredData::Dictionary *query =
+ packet_array->GetItemAtIndex(i)->GetAsDictionary();
+ if (!query)
+ continue;
+ llvm::StringRef file, triple;
+ if (!query->GetValueForKeyAsString("file", file) ||
+ !query->GetValueForKeyAsString("triple", triple))
+ continue;
+
+ ModuleSpec matched_module_spec = GetModuleInfo(file, triple);
+ if (!matched_module_spec.GetFileSpec())
+ continue;
+
+ const auto file_offset = matched_module_spec.GetObjectOffset();
+ const auto file_size = matched_module_spec.GetObjectSize();
+ const auto uuid_str = matched_module_spec.GetUUID().GetAsString("");
+ if (uuid_str.empty())
+ continue;
+ const auto triple_str =
+ matched_module_spec.GetArchitecture().GetTriple().getTriple();
+ const auto file_path = matched_module_spec.GetFileSpec().GetPath();
+
+ json::Object response{{"uuid", uuid_str},
+ {"triple", triple_str},
+ {"file_path", file_path},
+ {"file_offset", static_cast<int64_t>(file_offset)},
+ {"file_size", static_cast<int64_t>(file_size)}};
+ response_array.push_back(std::move(response));
+ }
+
+ StreamString response;
+ response.AsRawOstream() << std::move(response_array);
+ StreamGDBRemote escaped_response;
+ escaped_response.PutEscapedBytes(response.GetString().data(),
+ response.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+void GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse(
+ const ProcessInstanceInfo &proc_info, StreamString &response) {
+ response.Printf(
+ "pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
+ proc_info.GetProcessID(), proc_info.GetParentProcessID(),
+ proc_info.GetUserID(), proc_info.GetGroupID(),
+ proc_info.GetEffectiveUserID(), proc_info.GetEffectiveGroupID());
+ response.PutCString("name:");
+ response.PutStringAsRawHex8(proc_info.GetExecutableFile().GetPath().c_str());
+
+ response.PutChar(';');
+ response.PutCString("args:");
+ response.PutStringAsRawHex8(proc_info.GetArg0());
+ for (auto &arg : proc_info.GetArguments()) {
+ response.PutChar('-');
+ response.PutStringAsRawHex8(arg.ref());
+ }
+
+ response.PutChar(';');
+ const ArchSpec &proc_arch = proc_info.GetArchitecture();
+ if (proc_arch.IsValid()) {
+ const llvm::Triple &proc_triple = proc_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutStringAsRawHex8(proc_triple.getTriple());
+ response.PutChar(';');
+ }
+}
+
+void GDBRemoteCommunicationServerCommon::
+ CreateProcessInfoResponse_DebugServerStyle(
+ const ProcessInstanceInfo &proc_info, StreamString &response) {
+ response.Printf("pid:%" PRIx64 ";parent-pid:%" PRIx64
+ ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;",
+ proc_info.GetProcessID(), proc_info.GetParentProcessID(),
+ proc_info.GetUserID(), proc_info.GetGroupID(),
+ proc_info.GetEffectiveUserID(),
+ proc_info.GetEffectiveGroupID());
+
+ const ArchSpec &proc_arch = proc_info.GetArchitecture();
+ if (proc_arch.IsValid()) {
+ const llvm::Triple &proc_triple = proc_arch.GetTriple();
+#if defined(__APPLE__)
+ // We'll send cputype/cpusubtype.
+ const uint32_t cpu_type = proc_arch.GetMachOCPUType();
+ if (cpu_type != 0)
+ response.Printf("cputype:%" PRIx32 ";", cpu_type);
+
+ const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType();
+ if (cpu_subtype != 0)
+ response.Printf("cpusubtype:%" PRIx32 ";", cpu_subtype);
+
+ const std::string vendor = proc_triple.getVendorName().str();
+ if (!vendor.empty())
+ response.Printf("vendor:%s;", vendor.c_str());
+#else
+ // We'll send the triple.
+ response.PutCString("triple:");
+ response.PutStringAsRawHex8(proc_triple.getTriple());
+ response.PutChar(';');
+#endif
+ std::string ostype = std::string(proc_triple.getOSName());
+ // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64.
+ if (proc_triple.getVendor() == llvm::Triple::Apple) {
+ switch (proc_triple.getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
+ ostype = "ios";
+ break;
+ default:
+ // No change.
+ break;
+ }
+ }
+ response.Printf("ostype:%s;", ostype.c_str());
+
+ switch (proc_arch.GetByteOrder()) {
+ case lldb::eByteOrderLittle:
+ response.PutCString("endian:little;");
+ break;
+ case lldb::eByteOrderBig:
+ response.PutCString("endian:big;");
+ break;
+ case lldb::eByteOrderPDP:
+ response.PutCString("endian:pdp;");
+ break;
+ default:
+ // Nothing.
+ break;
+ }
+ // In case of MIPS64, pointer size is depend on ELF ABI For N32 the pointer
+ // size is 4 and for N64 it is 8
+ std::string abi = proc_arch.GetTargetABI();
+ if (!abi.empty())
+ response.Printf("elf_abi:%s;", abi.c_str());
+ response.Printf("ptrsize:%d;", proc_arch.GetAddressByteSize());
+ }
+}
+
+FileSpec GDBRemoteCommunicationServerCommon::FindModuleFile(
+ const std::string &module_path, const ArchSpec &arch) {
+#ifdef __ANDROID__
+ return HostInfoAndroid::ResolveLibraryPath(module_path, arch);
+#else
+ FileSpec file_spec(module_path);
+ FileSystem::Instance().Resolve(file_spec);
+ return file_spec;
+#endif
+}
+
+ModuleSpec
+GDBRemoteCommunicationServerCommon::GetModuleInfo(llvm::StringRef module_path,
+ llvm::StringRef triple) {
+ ArchSpec arch(triple);
+
+ FileSpec req_module_path_spec(module_path);
+ FileSystem::Instance().Resolve(req_module_path_spec);
+
+ const FileSpec module_path_spec =
+ FindModuleFile(req_module_path_spec.GetPath(), arch);
+
+ lldb::offset_t file_offset = 0;
+ lldb::offset_t file_size = 0;
+#ifdef __ANDROID__
+ // In Android API level 23 and above, dynamic loader is able to load .so file
+ // directly from zip file. In that case, module_path will be
+ // "zip_path!/so_path". Resolve the zip file path, .so file offset and size.
+ ZipFileResolver::FileKind file_kind = ZipFileResolver::eFileKindInvalid;
+ std::string file_path;
+ if (!ZipFileResolver::ResolveSharedLibraryPath(
+ module_path_spec, file_kind, file_path, file_offset, file_size)) {
+ return ModuleSpec();
+ }
+ lldbassert(file_kind != ZipFileResolver::eFileKindInvalid);
+ // For zip .so file, this file_path will contain only the actual zip file
+ // path for the object file processing. Otherwise it is the same as
+ // module_path.
+ const FileSpec actual_module_path_spec(file_path);
+#else
+ // It is just module_path_spec reference for other platforms.
+ const FileSpec &actual_module_path_spec = module_path_spec;
+#endif
+
+ const ModuleSpec module_spec(actual_module_path_spec, arch);
+
+ ModuleSpecList module_specs;
+ if (!ObjectFile::GetModuleSpecifications(actual_module_path_spec, file_offset,
+ file_size, module_specs))
+ return ModuleSpec();
+
+ ModuleSpec matched_module_spec;
+ if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
+ return ModuleSpec();
+
+#ifdef __ANDROID__
+ if (file_kind == ZipFileResolver::eFileKindZip) {
+ // For zip .so file, matched_module_spec contains only the actual zip file
+ // path for the object file processing. Overwrite the matched_module_spec
+ // file spec with the original module_path_spec to pass "zip_path!/so_path"
+ // through to PlatformAndroid::DownloadModuleSlice.
+ *matched_module_spec.GetFileSpecPtr() = module_path_spec;
+ }
+#endif
+
+ return matched_module_spec;
+}
+
+std::vector<std::string> GDBRemoteCommunicationServerCommon::HandleFeatures(
+ const llvm::ArrayRef<llvm::StringRef> client_features) {
+ // 128KBytes is a reasonable max packet size--debugger can always use less.
+ constexpr uint32_t max_packet_size = 128 * 1024;
+
+ // Features common to platform server and llgs.
+ return {
+ llvm::formatv("PacketSize={0}", max_packet_size),
+ "QStartNoAckMode+",
+ "qEcho+",
+ "native-signals+",
+ };
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
new file mode 100644
index 000000000000..b4f1eb3e61c4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
@@ -0,0 +1,154 @@
+//===-- GDBRemoteCommunicationServerCommon.h --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERCOMMON_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERCOMMON_H
+
+#include <string>
+
+#include "lldb/Host/ProcessLaunchInfo.h"
+#include "lldb/lldb-private-forward.h"
+
+#include "GDBRemoteCommunicationServer.h"
+
+class StringExtractorGDBRemote;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunicationServerCommon : public GDBRemoteCommunicationServer {
+public:
+ GDBRemoteCommunicationServerCommon();
+
+ ~GDBRemoteCommunicationServerCommon() override;
+
+protected:
+ ProcessLaunchInfo m_process_launch_info;
+ Status m_process_launch_error;
+ ProcessInstanceInfoList m_proc_infos;
+ uint32_t m_proc_infos_index;
+
+ PacketResult Handle_A(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qHostInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qProcessInfoPID(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qfProcessInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qsProcessInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qUserName(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qGroupName(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qSpeedTest(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_Open(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_Close(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_pRead(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_pWrite(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_Size(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_Mode(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_Exists(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_symlink(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_unlink(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_FStat(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_Stat(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vFile_MD5(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qEcho(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qModuleInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jModulesInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qPlatform_shell(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qPlatform_mkdir(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qPlatform_chmod(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qSupported(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QSetDetachOnError(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QStartNoAckMode(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QSetSTDIN(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QSetSTDOUT(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QSetSTDERR(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qLaunchSuccess(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QEnvironment(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QEnvironmentHexEncoded(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QLaunchArch(StringExtractorGDBRemote &packet);
+
+ static void CreateProcessInfoResponse(const ProcessInstanceInfo &proc_info,
+ StreamString &response);
+
+ static void CreateProcessInfoResponse_DebugServerStyle(
+ const ProcessInstanceInfo &proc_info, StreamString &response);
+
+ template <typename T>
+ void RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::ServerPacketType packet_type,
+ PacketResult (T::*handler)(StringExtractorGDBRemote &packet)) {
+ RegisterPacketHandler(packet_type,
+ [this, handler](StringExtractorGDBRemote packet,
+ Status &error, bool &interrupt,
+ bool &quit) {
+ return (static_cast<T *>(this)->*handler)(packet);
+ });
+ }
+
+ /// Launch a process with the current launch settings.
+ ///
+ /// This method supports running an lldb-gdbserver or similar
+ /// server in a situation where the startup code has been provided
+ /// with all the information for a child process to be launched.
+ ///
+ /// \return
+ /// An Status object indicating the success or failure of the
+ /// launch.
+ virtual Status LaunchProcess() = 0;
+
+ virtual FileSpec FindModuleFile(const std::string &module_path,
+ const ArchSpec &arch);
+
+ // Process client_features (qSupported) and return an array of server features
+ // to be returned in response.
+ virtual std::vector<std::string>
+ HandleFeatures(llvm::ArrayRef<llvm::StringRef> client_features);
+
+private:
+ ModuleSpec GetModuleInfo(llvm::StringRef module_path, llvm::StringRef triple);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERCOMMON_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
new file mode 100644
index 000000000000..08d5f5039d51
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -0,0 +1,4321 @@
+//===-- GDBRemoteCommunicationServerLLGS.cpp ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+
+#include "lldb/Host/Config.h"
+
+#include <chrono>
+#include <cstring>
+#include <limits>
+#include <optional>
+#include <thread>
+
+#include "GDBRemoteCommunicationServerLLGS.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Debug.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileAction.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/GDBRemote.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UnimplementedError.h"
+#include "lldb/Utility/UriParser.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/TargetParser/Triple.h"
+
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "lldb/Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace llvm;
+
+// GDBRemote Errors
+
+namespace {
+enum GDBRemoteServerError {
+ // Set to the first unused error number in literal form below
+ eErrorFirst = 29,
+ eErrorNoProcess = eErrorFirst,
+ eErrorResume,
+ eErrorExitStatus
+};
+}
+
+// GDBRemoteCommunicationServerLLGS constructor
+GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS(
+ MainLoop &mainloop, NativeProcessProtocol::Manager &process_manager)
+ : GDBRemoteCommunicationServerCommon(), m_mainloop(mainloop),
+ m_process_manager(process_manager), m_current_process(nullptr),
+ m_continue_process(nullptr), m_stdio_communication() {
+ RegisterPacketHandlers();
+}
+
+void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_C,
+ &GDBRemoteCommunicationServerLLGS::Handle_C);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_c,
+ &GDBRemoteCommunicationServerLLGS::Handle_c);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_D,
+ &GDBRemoteCommunicationServerLLGS::Handle_D);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_H,
+ &GDBRemoteCommunicationServerLLGS::Handle_H);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_I,
+ &GDBRemoteCommunicationServerLLGS::Handle_I);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_interrupt,
+ &GDBRemoteCommunicationServerLLGS::Handle_interrupt);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_m,
+ &GDBRemoteCommunicationServerLLGS::Handle_memory_read);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M,
+ &GDBRemoteCommunicationServerLLGS::Handle_M);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__M,
+ &GDBRemoteCommunicationServerLLGS::Handle__M);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__m,
+ &GDBRemoteCommunicationServerLLGS::Handle__m);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p,
+ &GDBRemoteCommunicationServerLLGS::Handle_p);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P,
+ &GDBRemoteCommunicationServerLLGS::Handle_P);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC,
+ &GDBRemoteCommunicationServerLLGS::Handle_qC);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_T,
+ &GDBRemoteCommunicationServerLLGS::Handle_T);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qfThreadInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress,
+ &GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
+ &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported,
+ &GDBRemoteCommunicationServerLLGS::Handle_QThreadSuffixSupported);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply,
+ &GDBRemoteCommunicationServerLLGS::Handle_QListThreadsInStopReply);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported,
+ &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qRegisterInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState,
+ &GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState,
+ &GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR,
+ &GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
+ &GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qsThreadInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jThreadsInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qXfer,
+ &GDBRemoteCommunicationServerLLGS::Handle_qXfer);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s,
+ &GDBRemoteCommunicationServerLLGS::Handle_s);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_stop_reason,
+ &GDBRemoteCommunicationServerLLGS::Handle_stop_reason); // ?
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vAttach,
+ &GDBRemoteCommunicationServerLLGS::Handle_vAttach);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vAttachWait,
+ &GDBRemoteCommunicationServerLLGS::Handle_vAttachWait);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qVAttachOrWaitSupported,
+ &GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vAttachOrWait,
+ &GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vCont,
+ &GDBRemoteCommunicationServerLLGS::Handle_vCont);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vCont_actions,
+ &GDBRemoteCommunicationServerLLGS::Handle_vCont_actions);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vRun,
+ &GDBRemoteCommunicationServerLLGS::Handle_vRun);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_x,
+ &GDBRemoteCommunicationServerLLGS::Handle_memory_read);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_Z,
+ &GDBRemoteCommunicationServerLLGS::Handle_Z);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z,
+ &GDBRemoteCommunicationServerLLGS::Handle_z);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QPassSignals,
+ &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
+
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupported,
+ &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jLLDBTraceStart,
+ &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStart);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jLLDBTraceStop,
+ &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStop);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetState,
+ &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetState);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetBinaryData,
+ &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData);
+
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g,
+ &GDBRemoteCommunicationServerLLGS::Handle_g);
+
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qMemTags,
+ &GDBRemoteCommunicationServerLLGS::Handle_qMemTags);
+
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QMemTags,
+ &GDBRemoteCommunicationServerLLGS::Handle_QMemTags);
+
+ RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,
+ [this](StringExtractorGDBRemote packet, Status &error,
+ bool &interrupt, bool &quit) {
+ quit = true;
+ return this->Handle_k(packet);
+ });
+
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vKill,
+ &GDBRemoteCommunicationServerLLGS::Handle_vKill);
+
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qLLDBSaveCore,
+ &GDBRemoteCommunicationServerLLGS::Handle_qSaveCore);
+
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QNonStop,
+ &GDBRemoteCommunicationServerLLGS::Handle_QNonStop);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vStdio,
+ &GDBRemoteCommunicationServerLLGS::Handle_vStdio);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vStopped,
+ &GDBRemoteCommunicationServerLLGS::Handle_vStopped);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vCtrlC,
+ &GDBRemoteCommunicationServerLLGS::Handle_vCtrlC);
+}
+
+void GDBRemoteCommunicationServerLLGS::SetLaunchInfo(const ProcessLaunchInfo &info) {
+ m_process_launch_info = info;
+}
+
+Status GDBRemoteCommunicationServerLLGS::LaunchProcess() {
+ Log *log = GetLog(LLDBLog::Process);
+
+ if (!m_process_launch_info.GetArguments().GetArgumentCount())
+ return Status("%s: no process command line specified to launch",
+ __FUNCTION__);
+
+ const bool should_forward_stdio =
+ m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr ||
+ m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr ||
+ m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr;
+ m_process_launch_info.SetLaunchInSeparateProcessGroup(true);
+ m_process_launch_info.GetFlags().Set(eLaunchFlagDebug);
+
+ if (should_forward_stdio) {
+ // Temporarily relax the following for Windows until we can take advantage
+ // of the recently added pty support. This doesn't really affect the use of
+ // lldb-server on Windows.
+#if !defined(_WIN32)
+ if (llvm::Error Err = m_process_launch_info.SetUpPtyRedirection())
+ return Status(std::move(Err));
+#endif
+ }
+
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex);
+ assert(m_debugged_processes.empty() && "lldb-server creating debugged "
+ "process but one already exists");
+ auto process_or = m_process_manager.Launch(m_process_launch_info, *this);
+ if (!process_or)
+ return Status(process_or.takeError());
+ m_continue_process = m_current_process = process_or->get();
+ m_debugged_processes.emplace(
+ m_current_process->GetID(),
+ DebuggedProcess{std::move(*process_or), DebuggedProcess::Flag{}});
+ }
+
+ SetEnabledExtensions(*m_current_process);
+
+ // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as
+ // needed. llgs local-process debugging may specify PTY paths, which will
+ // make these file actions non-null process launch -i/e/o will also make
+ // these file actions non-null nullptr means that the traffic is expected to
+ // flow over gdb-remote protocol
+ if (should_forward_stdio) {
+ // nullptr means it's not redirected to file or pty (in case of LLGS local)
+ // at least one of stdio will be transferred pty<->gdb-remote we need to
+ // give the pty primary handle to this object to read and/or write
+ LLDB_LOG(log,
+ "pid = {0}: setting up stdout/stderr redirection via $O "
+ "gdb-remote commands",
+ m_current_process->GetID());
+
+ // Setup stdout/stderr mapping from inferior to $O
+ auto terminal_fd = m_current_process->GetTerminalFileDescriptor();
+ if (terminal_fd >= 0) {
+ LLDB_LOGF(log,
+ "ProcessGDBRemoteCommunicationServerLLGS::%s setting "
+ "inferior STDIO fd to %d",
+ __FUNCTION__, terminal_fd);
+ Status status = SetSTDIOFileDescriptor(terminal_fd);
+ if (status.Fail())
+ return status;
+ } else {
+ LLDB_LOGF(log,
+ "ProcessGDBRemoteCommunicationServerLLGS::%s ignoring "
+ "inferior STDIO since terminal fd reported as %d",
+ __FUNCTION__, terminal_fd);
+ }
+ } else {
+ LLDB_LOG(log,
+ "pid = {0} skipping stdout/stderr redirection via $O: inferior "
+ "will communicate over client-provided file descriptors",
+ m_current_process->GetID());
+ }
+
+ printf("Launched '%s' as process %" PRIu64 "...\n",
+ m_process_launch_info.GetArguments().GetArgumentAtIndex(0),
+ m_current_process->GetID());
+
+ return Status();
+}
+
+Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
+ Log *log = GetLog(LLDBLog::Process);
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64,
+ __FUNCTION__, pid);
+
+ // Before we try to attach, make sure we aren't already monitoring something
+ // else.
+ if (!m_debugged_processes.empty())
+ return Status("cannot attach to process %" PRIu64
+ " when another process with pid %" PRIu64
+ " is being debugged.",
+ pid, m_current_process->GetID());
+
+ // Try to attach.
+ auto process_or = m_process_manager.Attach(pid, *this);
+ if (!process_or) {
+ Status status(process_or.takeError());
+ llvm::errs() << llvm::formatv("failed to attach to process {0}: {1}\n", pid,
+ status);
+ return status;
+ }
+ m_continue_process = m_current_process = process_or->get();
+ m_debugged_processes.emplace(
+ m_current_process->GetID(),
+ DebuggedProcess{std::move(*process_or), DebuggedProcess::Flag{}});
+ SetEnabledExtensions(*m_current_process);
+
+ // Setup stdout/stderr mapping from inferior.
+ auto terminal_fd = m_current_process->GetTerminalFileDescriptor();
+ if (terminal_fd >= 0) {
+ LLDB_LOGF(log,
+ "ProcessGDBRemoteCommunicationServerLLGS::%s setting "
+ "inferior STDIO fd to %d",
+ __FUNCTION__, terminal_fd);
+ Status status = SetSTDIOFileDescriptor(terminal_fd);
+ if (status.Fail())
+ return status;
+ } else {
+ LLDB_LOGF(log,
+ "ProcessGDBRemoteCommunicationServerLLGS::%s ignoring "
+ "inferior STDIO since terminal fd reported as %d",
+ __FUNCTION__, terminal_fd);
+ }
+
+ printf("Attached to process %" PRIu64 "...\n", pid);
+ return Status();
+}
+
+Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess(
+ llvm::StringRef process_name, bool include_existing) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ std::chrono::milliseconds polling_interval = std::chrono::milliseconds(1);
+
+ // Create the matcher used to search the process list.
+ ProcessInstanceInfoList exclusion_list;
+ ProcessInstanceInfoMatch match_info;
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(
+ process_name, llvm::sys::path::Style::native);
+ match_info.SetNameMatchType(NameMatch::Equals);
+
+ if (include_existing) {
+ LLDB_LOG(log, "including existing processes in search");
+ } else {
+ // Create the excluded process list before polling begins.
+ Host::FindProcesses(match_info, exclusion_list);
+ LLDB_LOG(log, "placed '{0}' processes in the exclusion list.",
+ exclusion_list.size());
+ }
+
+ LLDB_LOG(log, "waiting for '{0}' to appear", process_name);
+
+ auto is_in_exclusion_list =
+ [&exclusion_list](const ProcessInstanceInfo &info) {
+ for (auto &excluded : exclusion_list) {
+ if (excluded.GetProcessID() == info.GetProcessID())
+ return true;
+ }
+ return false;
+ };
+
+ ProcessInstanceInfoList loop_process_list;
+ while (true) {
+ loop_process_list.clear();
+ if (Host::FindProcesses(match_info, loop_process_list)) {
+ // Remove all the elements that are in the exclusion list.
+ llvm::erase_if(loop_process_list, is_in_exclusion_list);
+
+ // One match! We found the desired process.
+ if (loop_process_list.size() == 1) {
+ auto matching_process_pid = loop_process_list[0].GetProcessID();
+ LLDB_LOG(log, "found pid {0}", matching_process_pid);
+ return AttachToProcess(matching_process_pid);
+ }
+
+ // Multiple matches! Return an error reporting the PIDs we found.
+ if (loop_process_list.size() > 1) {
+ StreamString error_stream;
+ error_stream.Format(
+ "Multiple executables with name: '{0}' found. Pids: ",
+ process_name);
+ for (size_t i = 0; i < loop_process_list.size() - 1; ++i) {
+ error_stream.Format("{0}, ", loop_process_list[i].GetProcessID());
+ }
+ error_stream.Format("{0}.", loop_process_list.back().GetProcessID());
+
+ Status error;
+ error.SetErrorString(error_stream.GetString());
+ return error;
+ }
+ }
+ // No matches, we have not found the process. Sleep until next poll.
+ LLDB_LOG(log, "sleep {0} seconds", polling_interval);
+ std::this_thread::sleep_for(polling_interval);
+ }
+}
+
+void GDBRemoteCommunicationServerLLGS::InitializeDelegate(
+ NativeProcessProtocol *process) {
+ assert(process && "process cannot be NULL");
+ Log *log = GetLog(LLDBLog::Process);
+ if (log) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s called with "
+ "NativeProcessProtocol pid %" PRIu64 ", current state: %s",
+ __FUNCTION__, process->GetID(),
+ StateAsCString(process->GetState()));
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendWResponse(
+ NativeProcessProtocol *process) {
+ assert(process && "process cannot be NULL");
+ Log *log = GetLog(LLDBLog::Process);
+
+ // send W notification
+ auto wait_status = process->GetExitStatus();
+ if (!wait_status) {
+ LLDB_LOG(log, "pid = {0}, failed to retrieve process exit status",
+ process->GetID());
+
+ StreamGDBRemote response;
+ response.PutChar('E');
+ response.PutHex8(GDBRemoteServerError::eErrorExitStatus);
+ return SendPacketNoLock(response.GetString());
+ }
+
+ LLDB_LOG(log, "pid = {0}, returning exit type {1}", process->GetID(),
+ *wait_status);
+
+ // If the process was killed through vKill, return "OK".
+ if (bool(m_debugged_processes.at(process->GetID()).flags &
+ DebuggedProcess::Flag::vkilled))
+ return SendOKResponse();
+
+ StreamGDBRemote response;
+ response.Format("{0:g}", *wait_status);
+ if (bool(m_extensions_supported &
+ NativeProcessProtocol::Extension::multiprocess))
+ response.Format(";process:{0:x-}", process->GetID());
+ if (m_non_stop)
+ return SendNotificationPacketNoLock("Stop", m_stop_notification_queue,
+ response.GetString());
+ return SendPacketNoLock(response.GetString());
+}
+
+static void AppendHexValue(StreamString &response, const uint8_t *buf,
+ uint32_t buf_size, bool swap) {
+ int64_t i;
+ if (swap) {
+ for (i = buf_size - 1; i >= 0; i--)
+ response.PutHex8(buf[i]);
+ } else {
+ for (i = 0; i < buf_size; i++)
+ response.PutHex8(buf[i]);
+ }
+}
+
+static llvm::StringRef GetEncodingNameOrEmpty(const RegisterInfo &reg_info) {
+ switch (reg_info.encoding) {
+ case eEncodingUint:
+ return "uint";
+ case eEncodingSint:
+ return "sint";
+ case eEncodingIEEE754:
+ return "ieee754";
+ case eEncodingVector:
+ return "vector";
+ default:
+ return "";
+ }
+}
+
+static llvm::StringRef GetFormatNameOrEmpty(const RegisterInfo &reg_info) {
+ switch (reg_info.format) {
+ case eFormatBinary:
+ return "binary";
+ case eFormatDecimal:
+ return "decimal";
+ case eFormatHex:
+ return "hex";
+ case eFormatFloat:
+ return "float";
+ case eFormatVectorOfSInt8:
+ return "vector-sint8";
+ case eFormatVectorOfUInt8:
+ return "vector-uint8";
+ case eFormatVectorOfSInt16:
+ return "vector-sint16";
+ case eFormatVectorOfUInt16:
+ return "vector-uint16";
+ case eFormatVectorOfSInt32:
+ return "vector-sint32";
+ case eFormatVectorOfUInt32:
+ return "vector-uint32";
+ case eFormatVectorOfFloat32:
+ return "vector-float32";
+ case eFormatVectorOfUInt64:
+ return "vector-uint64";
+ case eFormatVectorOfUInt128:
+ return "vector-uint128";
+ default:
+ return "";
+ };
+}
+
+static llvm::StringRef GetKindGenericOrEmpty(const RegisterInfo &reg_info) {
+ switch (reg_info.kinds[RegisterKind::eRegisterKindGeneric]) {
+ case LLDB_REGNUM_GENERIC_PC:
+ return "pc";
+ case LLDB_REGNUM_GENERIC_SP:
+ return "sp";
+ case LLDB_REGNUM_GENERIC_FP:
+ return "fp";
+ case LLDB_REGNUM_GENERIC_RA:
+ return "ra";
+ case LLDB_REGNUM_GENERIC_FLAGS:
+ return "flags";
+ case LLDB_REGNUM_GENERIC_ARG1:
+ return "arg1";
+ case LLDB_REGNUM_GENERIC_ARG2:
+ return "arg2";
+ case LLDB_REGNUM_GENERIC_ARG3:
+ return "arg3";
+ case LLDB_REGNUM_GENERIC_ARG4:
+ return "arg4";
+ case LLDB_REGNUM_GENERIC_ARG5:
+ return "arg5";
+ case LLDB_REGNUM_GENERIC_ARG6:
+ return "arg6";
+ case LLDB_REGNUM_GENERIC_ARG7:
+ return "arg7";
+ case LLDB_REGNUM_GENERIC_ARG8:
+ return "arg8";
+ case LLDB_REGNUM_GENERIC_TP:
+ return "tp";
+ default:
+ return "";
+ }
+}
+
+static void CollectRegNums(const uint32_t *reg_num, StreamString &response,
+ bool usehex) {
+ for (int i = 0; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) {
+ if (i > 0)
+ response.PutChar(',');
+ if (usehex)
+ response.Printf("%" PRIx32, *reg_num);
+ else
+ response.Printf("%" PRIu32, *reg_num);
+ }
+}
+
+static void WriteRegisterValueInHexFixedWidth(
+ StreamString &response, NativeRegisterContext &reg_ctx,
+ const RegisterInfo &reg_info, const RegisterValue *reg_value_p,
+ lldb::ByteOrder byte_order) {
+ RegisterValue reg_value;
+ if (!reg_value_p) {
+ Status error = reg_ctx.ReadRegister(&reg_info, reg_value);
+ if (error.Success())
+ reg_value_p = &reg_value;
+ // else log.
+ }
+
+ if (reg_value_p) {
+ AppendHexValue(response, (const uint8_t *)reg_value_p->GetBytes(),
+ reg_value_p->GetByteSize(),
+ byte_order == lldb::eByteOrderLittle);
+ } else {
+ // Zero-out any unreadable values.
+ if (reg_info.byte_size > 0) {
+ std::vector<uint8_t> zeros(reg_info.byte_size, '\0');
+ AppendHexValue(response, zeros.data(), zeros.size(), false);
+ }
+ }
+}
+
+static std::optional<json::Object>
+GetRegistersAsJSON(NativeThreadProtocol &thread) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ NativeRegisterContext& reg_ctx = thread.GetRegisterContext();
+
+ json::Object register_object;
+
+#ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET
+ const auto expedited_regs =
+ reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full);
+#else
+ const auto expedited_regs =
+ reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Minimal);
+#endif
+ if (expedited_regs.empty())
+ return std::nullopt;
+
+ for (auto &reg_num : expedited_regs) {
+ const RegisterInfo *const reg_info_p =
+ reg_ctx.GetRegisterInfoAtIndex(reg_num);
+ if (reg_info_p == nullptr) {
+ LLDB_LOGF(log,
+ "%s failed to get register info for register index %" PRIu32,
+ __FUNCTION__, reg_num);
+ continue;
+ }
+
+ if (reg_info_p->value_regs != nullptr)
+ continue; // Only expedite registers that are not contained in other
+ // registers.
+
+ RegisterValue reg_value;
+ Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
+ if (error.Fail()) {
+ LLDB_LOGF(log, "%s failed to read register '%s' index %" PRIu32 ": %s",
+ __FUNCTION__,
+ reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
+ reg_num, error.AsCString());
+ continue;
+ }
+
+ StreamString stream;
+ WriteRegisterValueInHexFixedWidth(stream, reg_ctx, *reg_info_p,
+ &reg_value, lldb::eByteOrderBig);
+
+ register_object.try_emplace(llvm::to_string(reg_num),
+ stream.GetString().str());
+ }
+
+ return register_object;
+}
+
+static const char *GetStopReasonString(StopReason stop_reason) {
+ switch (stop_reason) {
+ case eStopReasonTrace:
+ return "trace";
+ case eStopReasonBreakpoint:
+ return "breakpoint";
+ case eStopReasonWatchpoint:
+ return "watchpoint";
+ case eStopReasonSignal:
+ return "signal";
+ case eStopReasonException:
+ return "exception";
+ case eStopReasonExec:
+ return "exec";
+ case eStopReasonProcessorTrace:
+ return "processor trace";
+ case eStopReasonFork:
+ return "fork";
+ case eStopReasonVFork:
+ return "vfork";
+ case eStopReasonVForkDone:
+ return "vforkdone";
+ case eStopReasonInstrumentation:
+ case eStopReasonInvalid:
+ case eStopReasonPlanComplete:
+ case eStopReasonThreadExiting:
+ case eStopReasonNone:
+ break; // ignored
+ }
+ return nullptr;
+}
+
+static llvm::Expected<json::Array>
+GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
+
+ json::Array threads_array;
+
+ // Ensure we can get info on the given thread.
+ for (NativeThreadProtocol &thread : process.Threads()) {
+ lldb::tid_t tid = thread.GetID();
+ // Grab the reason this thread stopped.
+ struct ThreadStopInfo tid_stop_info;
+ std::string description;
+ if (!thread.GetStopReason(tid_stop_info, description))
+ return llvm::make_error<llvm::StringError>(
+ "failed to get stop reason", llvm::inconvertibleErrorCode());
+
+ const int signum = tid_stop_info.signo;
+ if (log) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " tid %" PRIu64
+ " got signal signo = %d, reason = %d, exc_type = %" PRIu64,
+ __FUNCTION__, process.GetID(), tid, signum,
+ tid_stop_info.reason, tid_stop_info.details.exception.type);
+ }
+
+ json::Object thread_obj;
+
+ if (!abridged) {
+ if (std::optional<json::Object> registers = GetRegistersAsJSON(thread))
+ thread_obj.try_emplace("registers", std::move(*registers));
+ }
+
+ thread_obj.try_emplace("tid", static_cast<int64_t>(tid));
+
+ if (signum != 0)
+ thread_obj.try_emplace("signal", signum);
+
+ const std::string thread_name = thread.GetName();
+ if (!thread_name.empty())
+ thread_obj.try_emplace("name", thread_name);
+
+ const char *stop_reason = GetStopReasonString(tid_stop_info.reason);
+ if (stop_reason)
+ thread_obj.try_emplace("reason", stop_reason);
+
+ if (!description.empty())
+ thread_obj.try_emplace("description", description);
+
+ if ((tid_stop_info.reason == eStopReasonException) &&
+ tid_stop_info.details.exception.type) {
+ thread_obj.try_emplace(
+ "metype", static_cast<int64_t>(tid_stop_info.details.exception.type));
+
+ json::Array medata_array;
+ for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count;
+ ++i) {
+ medata_array.push_back(
+ static_cast<int64_t>(tid_stop_info.details.exception.data[i]));
+ }
+ thread_obj.try_emplace("medata", std::move(medata_array));
+ }
+ threads_array.push_back(std::move(thread_obj));
+ }
+ return threads_array;
+}
+
+StreamString
+GDBRemoteCommunicationServerLLGS::PrepareStopReplyPacketForThread(
+ NativeThreadProtocol &thread) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
+
+ NativeProcessProtocol &process = thread.GetProcess();
+
+ LLDB_LOG(log, "preparing packet for pid {0} tid {1}", process.GetID(),
+ thread.GetID());
+
+ // Grab the reason this thread stopped.
+ StreamString response;
+ struct ThreadStopInfo tid_stop_info;
+ std::string description;
+ if (!thread.GetStopReason(tid_stop_info, description))
+ return response;
+
+ // FIXME implement register handling for exec'd inferiors.
+ // if (tid_stop_info.reason == eStopReasonExec) {
+ // const bool force = true;
+ // InitializeRegisters(force);
+ // }
+
+ // Output the T packet with the thread
+ response.PutChar('T');
+ int signum = tid_stop_info.signo;
+ LLDB_LOG(
+ log,
+ "pid {0}, tid {1}, got signal signo = {2}, reason = {3}, exc_type = {4}",
+ process.GetID(), thread.GetID(), signum, int(tid_stop_info.reason),
+ tid_stop_info.details.exception.type);
+
+ // Print the signal number.
+ response.PutHex8(signum & 0xff);
+
+ // Include the (pid and) tid.
+ response.PutCString("thread:");
+ AppendThreadIDToResponse(response, process.GetID(), thread.GetID());
+ response.PutChar(';');
+
+ // Include the thread name if there is one.
+ const std::string thread_name = thread.GetName();
+ if (!thread_name.empty()) {
+ size_t thread_name_len = thread_name.length();
+
+ if (::strcspn(thread_name.c_str(), "$#+-;:") == thread_name_len) {
+ response.PutCString("name:");
+ response.PutCString(thread_name);
+ } else {
+ // The thread name contains special chars, send as hex bytes.
+ response.PutCString("hexname:");
+ response.PutStringAsRawHex8(thread_name);
+ }
+ response.PutChar(';');
+ }
+
+ // If a 'QListThreadsInStopReply' was sent to enable this feature, we will
+ // send all thread IDs back in the "threads" key whose value is a list of hex
+ // thread IDs separated by commas:
+ // "threads:10a,10b,10c;"
+ // This will save the debugger from having to send a pair of qfThreadInfo and
+ // qsThreadInfo packets, but it also might take a lot of room in the stop
+ // reply packet, so it must be enabled only on systems where there are no
+ // limits on packet lengths.
+ if (m_list_threads_in_stop_reply) {
+ response.PutCString("threads:");
+
+ uint32_t thread_num = 0;
+ for (NativeThreadProtocol &listed_thread : process.Threads()) {
+ if (thread_num > 0)
+ response.PutChar(',');
+ response.Printf("%" PRIx64, listed_thread.GetID());
+ ++thread_num;
+ }
+ response.PutChar(';');
+
+ // Include JSON info that describes the stop reason for any threads that
+ // actually have stop reasons. We use the new "jstopinfo" key whose values
+ // is hex ascii JSON that contains the thread IDs thread stop info only for
+ // threads that have stop reasons. Only send this if we have more than one
+ // thread otherwise this packet has all the info it needs.
+ if (thread_num > 1) {
+ const bool threads_with_valid_stop_info_only = true;
+ llvm::Expected<json::Array> threads_info = GetJSONThreadsInfo(
+ *m_current_process, threads_with_valid_stop_info_only);
+ if (threads_info) {
+ response.PutCString("jstopinfo:");
+ StreamString unescaped_response;
+ unescaped_response.AsRawOstream() << std::move(*threads_info);
+ response.PutStringAsRawHex8(unescaped_response.GetData());
+ response.PutChar(';');
+ } else {
+ LLDB_LOG_ERROR(log, threads_info.takeError(),
+ "failed to prepare a jstopinfo field for pid {1}: {0}",
+ process.GetID());
+ }
+ }
+
+ response.PutCString("thread-pcs");
+ char delimiter = ':';
+ for (NativeThreadProtocol &thread : process.Threads()) {
+ NativeRegisterContext &reg_ctx = thread.GetRegisterContext();
+
+ uint32_t reg_to_read = reg_ctx.ConvertRegisterKindToRegisterNumber(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ const RegisterInfo *const reg_info_p =
+ reg_ctx.GetRegisterInfoAtIndex(reg_to_read);
+
+ RegisterValue reg_value;
+ Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
+ if (error.Fail()) {
+ LLDB_LOGF(log, "%s failed to read register '%s' index %" PRIu32 ": %s",
+ __FUNCTION__,
+ reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
+ reg_to_read, error.AsCString());
+ continue;
+ }
+
+ response.PutChar(delimiter);
+ delimiter = ',';
+ WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p,
+ &reg_value, endian::InlHostByteOrder());
+ }
+
+ response.PutChar(';');
+ }
+
+ //
+ // Expedite registers.
+ //
+
+ // Grab the register context.
+ NativeRegisterContext &reg_ctx = thread.GetRegisterContext();
+ const auto expedited_regs =
+ reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full);
+
+ for (auto &reg_num : expedited_regs) {
+ const RegisterInfo *const reg_info_p =
+ reg_ctx.GetRegisterInfoAtIndex(reg_num);
+ // Only expediate registers that are not contained in other registers.
+ if (reg_info_p != nullptr && reg_info_p->value_regs == nullptr) {
+ RegisterValue reg_value;
+ Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
+ if (error.Success()) {
+ response.Printf("%.02x:", reg_num);
+ WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p,
+ &reg_value, lldb::eByteOrderBig);
+ response.PutChar(';');
+ } else {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed to read "
+ "register '%s' index %" PRIu32 ": %s",
+ __FUNCTION__,
+ reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
+ reg_num, error.AsCString());
+ }
+ }
+ }
+
+ const char *reason_str = GetStopReasonString(tid_stop_info.reason);
+ if (reason_str != nullptr) {
+ response.Printf("reason:%s;", reason_str);
+ }
+
+ if (!description.empty()) {
+ // Description may contains special chars, send as hex bytes.
+ response.PutCString("description:");
+ response.PutStringAsRawHex8(description);
+ response.PutChar(';');
+ } else if ((tid_stop_info.reason == eStopReasonException) &&
+ tid_stop_info.details.exception.type) {
+ response.PutCString("metype:");
+ response.PutHex64(tid_stop_info.details.exception.type);
+ response.PutCString(";mecount:");
+ response.PutHex32(tid_stop_info.details.exception.data_count);
+ response.PutChar(';');
+
+ for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) {
+ response.PutCString("medata:");
+ response.PutHex64(tid_stop_info.details.exception.data[i]);
+ response.PutChar(';');
+ }
+ }
+
+ // Include child process PID/TID for forks.
+ if (tid_stop_info.reason == eStopReasonFork ||
+ tid_stop_info.reason == eStopReasonVFork) {
+ assert(bool(m_extensions_supported &
+ NativeProcessProtocol::Extension::multiprocess));
+ if (tid_stop_info.reason == eStopReasonFork)
+ assert(bool(m_extensions_supported &
+ NativeProcessProtocol::Extension::fork));
+ if (tid_stop_info.reason == eStopReasonVFork)
+ assert(bool(m_extensions_supported &
+ NativeProcessProtocol::Extension::vfork));
+ response.Printf("%s:p%" PRIx64 ".%" PRIx64 ";", reason_str,
+ tid_stop_info.details.fork.child_pid,
+ tid_stop_info.details.fork.child_tid);
+ }
+
+ return response;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
+ NativeProcessProtocol &process, lldb::tid_t tid, bool force_synchronous) {
+ // Ensure we can get info on the given thread.
+ NativeThreadProtocol *thread = process.GetThreadByID(tid);
+ if (!thread)
+ return SendErrorResponse(51);
+
+ StreamString response = PrepareStopReplyPacketForThread(*thread);
+ if (response.Empty())
+ return SendErrorResponse(42);
+
+ if (m_non_stop && !force_synchronous) {
+ PacketResult ret = SendNotificationPacketNoLock(
+ "Stop", m_stop_notification_queue, response.GetString());
+ // Queue notification events for the remaining threads.
+ EnqueueStopReplyPackets(tid);
+ return ret;
+ }
+
+ return SendPacketNoLock(response.GetString());
+}
+
+void GDBRemoteCommunicationServerLLGS::EnqueueStopReplyPackets(
+ lldb::tid_t thread_to_skip) {
+ if (!m_non_stop)
+ return;
+
+ for (NativeThreadProtocol &listed_thread : m_current_process->Threads()) {
+ if (listed_thread.GetID() != thread_to_skip) {
+ StreamString stop_reply = PrepareStopReplyPacketForThread(listed_thread);
+ if (!stop_reply.Empty())
+ m_stop_notification_queue.push_back(stop_reply.GetString().str());
+ }
+ }
+}
+
+void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited(
+ NativeProcessProtocol *process) {
+ assert(process && "process cannot be NULL");
+
+ Log *log = GetLog(LLDBLog::Process);
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
+
+ PacketResult result = SendStopReasonForState(
+ *process, StateType::eStateExited, /*force_synchronous=*/false);
+ if (result != PacketResult::Success) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed to send stop "
+ "notification for PID %" PRIu64 ", state: eStateExited",
+ __FUNCTION__, process->GetID());
+ }
+
+ if (m_current_process == process)
+ m_current_process = nullptr;
+ if (m_continue_process == process)
+ m_continue_process = nullptr;
+
+ lldb::pid_t pid = process->GetID();
+ m_mainloop.AddPendingCallback([this, pid](MainLoopBase &loop) {
+ auto find_it = m_debugged_processes.find(pid);
+ assert(find_it != m_debugged_processes.end());
+ bool vkilled = bool(find_it->second.flags & DebuggedProcess::Flag::vkilled);
+ m_debugged_processes.erase(find_it);
+ // Terminate the main loop only if vKill has not been used.
+ // When running in non-stop mode, wait for the vStopped to clear
+ // the notification queue.
+ if (m_debugged_processes.empty() && !m_non_stop && !vkilled) {
+ // Close the pipe to the inferior terminal i/o if we launched it and set
+ // one up.
+ MaybeCloseInferiorTerminalConnection();
+
+ // We are ready to exit the debug monitor.
+ m_exit_now = true;
+ loop.RequestTermination();
+ }
+ });
+}
+
+void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped(
+ NativeProcessProtocol *process) {
+ assert(process && "process cannot be NULL");
+
+ Log *log = GetLog(LLDBLog::Process);
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
+
+ PacketResult result = SendStopReasonForState(
+ *process, StateType::eStateStopped, /*force_synchronous=*/false);
+ if (result != PacketResult::Success) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed to send stop "
+ "notification for PID %" PRIu64 ", state: eStateExited",
+ __FUNCTION__, process->GetID());
+ }
+}
+
+void GDBRemoteCommunicationServerLLGS::ProcessStateChanged(
+ NativeProcessProtocol *process, lldb::StateType state) {
+ assert(process && "process cannot be NULL");
+ Log *log = GetLog(LLDBLog::Process);
+ if (log) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s called with "
+ "NativeProcessProtocol pid %" PRIu64 ", state: %s",
+ __FUNCTION__, process->GetID(), StateAsCString(state));
+ }
+
+ switch (state) {
+ case StateType::eStateRunning:
+ break;
+
+ case StateType::eStateStopped:
+ // Make sure we get all of the pending stdout/stderr from the inferior and
+ // send it to the lldb host before we send the state change notification
+ SendProcessOutput();
+ // Then stop the forwarding, so that any late output (see llvm.org/pr25652)
+ // does not interfere with our protocol.
+ if (!m_non_stop)
+ StopSTDIOForwarding();
+ HandleInferiorState_Stopped(process);
+ break;
+
+ case StateType::eStateExited:
+ // Same as above
+ SendProcessOutput();
+ if (!m_non_stop)
+ StopSTDIOForwarding();
+ HandleInferiorState_Exited(process);
+ break;
+
+ default:
+ if (log) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s didn't handle state "
+ "change for pid %" PRIu64 ", new state: %s",
+ __FUNCTION__, process->GetID(), StateAsCString(state));
+ }
+ break;
+ }
+}
+
+void GDBRemoteCommunicationServerLLGS::DidExec(NativeProcessProtocol *process) {
+ ClearProcessSpecificData();
+}
+
+void GDBRemoteCommunicationServerLLGS::NewSubprocess(
+ NativeProcessProtocol *parent_process,
+ std::unique_ptr<NativeProcessProtocol> child_process) {
+ lldb::pid_t child_pid = child_process->GetID();
+ assert(child_pid != LLDB_INVALID_PROCESS_ID);
+ assert(m_debugged_processes.find(child_pid) == m_debugged_processes.end());
+ m_debugged_processes.emplace(
+ child_pid,
+ DebuggedProcess{std::move(child_process), DebuggedProcess::Flag{}});
+}
+
+void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() {
+ Log *log = GetLog(GDBRLog::Comm);
+
+ bool interrupt = false;
+ bool done = false;
+ Status error;
+ while (true) {
+ const PacketResult result = GetPacketAndSendResponse(
+ std::chrono::microseconds(0), error, interrupt, done);
+ if (result == PacketResult::ErrorReplyTimeout)
+ break; // No more packets in the queue
+
+ if ((result != PacketResult::Success)) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s processing a packet "
+ "failed: %s",
+ __FUNCTION__, error.AsCString());
+ m_mainloop.RequestTermination();
+ break;
+ }
+ }
+}
+
+Status GDBRemoteCommunicationServerLLGS::InitializeConnection(
+ std::unique_ptr<Connection> connection) {
+ IOObjectSP read_object_sp = connection->GetReadObject();
+ GDBRemoteCommunicationServer::SetConnection(std::move(connection));
+
+ Status error;
+ m_network_handle_up = m_mainloop.RegisterReadObject(
+ read_object_sp, [this](MainLoopBase &) { DataAvailableCallback(); },
+ error);
+ return error;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendONotification(const char *buffer,
+ uint32_t len) {
+ if ((buffer == nullptr) || (len == 0)) {
+ // Nothing to send.
+ return PacketResult::Success;
+ }
+
+ StreamString response;
+ response.PutChar('O');
+ response.PutBytesAsRawHex8(buffer, len);
+
+ if (m_non_stop)
+ return SendNotificationPacketNoLock("Stdio", m_stdio_notification_queue,
+ response.GetString());
+ return SendPacketNoLock(response.GetString());
+}
+
+Status GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor(int fd) {
+ Status error;
+
+ // Set up the reading/handling of process I/O
+ std::unique_ptr<ConnectionFileDescriptor> conn_up(
+ new ConnectionFileDescriptor(fd, true));
+ if (!conn_up) {
+ error.SetErrorString("failed to create ConnectionFileDescriptor");
+ return error;
+ }
+
+ m_stdio_communication.SetCloseOnEOF(false);
+ m_stdio_communication.SetConnection(std::move(conn_up));
+ if (!m_stdio_communication.IsConnected()) {
+ error.SetErrorString(
+ "failed to set connection for inferior I/O communication");
+ return error;
+ }
+
+ return Status();
+}
+
+void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() {
+ // Don't forward if not connected (e.g. when attaching).
+ if (!m_stdio_communication.IsConnected())
+ return;
+
+ Status error;
+ assert(!m_stdio_handle_up);
+ m_stdio_handle_up = m_mainloop.RegisterReadObject(
+ m_stdio_communication.GetConnection()->GetReadObject(),
+ [this](MainLoopBase &) { SendProcessOutput(); }, error);
+
+ if (!m_stdio_handle_up) {
+ // Not much we can do about the failure. Log it and continue without
+ // forwarding.
+ if (Log *log = GetLog(LLDBLog::Process))
+ LLDB_LOG(log, "Failed to set up stdio forwarding: {0}", error);
+ }
+}
+
+void GDBRemoteCommunicationServerLLGS::StopSTDIOForwarding() {
+ m_stdio_handle_up.reset();
+}
+
+void GDBRemoteCommunicationServerLLGS::SendProcessOutput() {
+ char buffer[1024];
+ ConnectionStatus status;
+ Status error;
+ while (true) {
+ size_t bytes_read = m_stdio_communication.Read(
+ buffer, sizeof buffer, std::chrono::microseconds(0), status, &error);
+ switch (status) {
+ case eConnectionStatusSuccess:
+ SendONotification(buffer, bytes_read);
+ break;
+ case eConnectionStatusLostConnection:
+ case eConnectionStatusEndOfFile:
+ case eConnectionStatusError:
+ case eConnectionStatusNoConnection:
+ if (Log *log = GetLog(LLDBLog::Process))
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s Stopping stdio "
+ "forwarding as communication returned status %d (error: "
+ "%s)",
+ __FUNCTION__, status, error.AsCString());
+ m_stdio_handle_up.reset();
+ return;
+
+ case eConnectionStatusInterrupted:
+ case eConnectionStatusTimedOut:
+ return;
+ }
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(Status("Process not running."));
+
+ return SendJSONResponse(m_current_process->TraceSupported());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStop(
+ StringExtractorGDBRemote &packet) {
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(Status("Process not running."));
+
+ packet.ConsumeFront("jLLDBTraceStop:");
+ Expected<TraceStopRequest> stop_request =
+ json::parse<TraceStopRequest>(packet.Peek(), "TraceStopRequest");
+ if (!stop_request)
+ return SendErrorResponse(stop_request.takeError());
+
+ if (Error err = m_current_process->TraceStop(*stop_request))
+ return SendErrorResponse(std::move(err));
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStart(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(Status("Process not running."));
+
+ packet.ConsumeFront("jLLDBTraceStart:");
+ Expected<TraceStartRequest> request =
+ json::parse<TraceStartRequest>(packet.Peek(), "TraceStartRequest");
+ if (!request)
+ return SendErrorResponse(request.takeError());
+
+ if (Error err = m_current_process->TraceStart(packet.Peek(), request->type))
+ return SendErrorResponse(std::move(err));
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetState(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(Status("Process not running."));
+
+ packet.ConsumeFront("jLLDBTraceGetState:");
+ Expected<TraceGetStateRequest> request =
+ json::parse<TraceGetStateRequest>(packet.Peek(), "TraceGetStateRequest");
+ if (!request)
+ return SendErrorResponse(request.takeError());
+
+ return SendJSONResponse(m_current_process->TraceGetState(request->type));
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(Status("Process not running."));
+
+ packet.ConsumeFront("jLLDBTraceGetBinaryData:");
+ llvm::Expected<TraceGetBinaryDataRequest> request =
+ llvm::json::parse<TraceGetBinaryDataRequest>(packet.Peek(),
+ "TraceGetBinaryDataRequest");
+ if (!request)
+ return SendErrorResponse(Status(request.takeError()));
+
+ if (Expected<std::vector<uint8_t>> bytes =
+ m_current_process->TraceGetBinaryData(*request)) {
+ StreamGDBRemote response;
+ response.PutEscapedBytes(bytes->data(), bytes->size());
+ return SendPacketNoLock(response.GetString());
+ } else
+ return SendErrorResponse(bytes.takeError());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo(
+ StringExtractorGDBRemote &packet) {
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ lldb::pid_t pid = m_current_process->GetID();
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse(1);
+
+ ProcessInstanceInfo proc_info;
+ if (!Host::GetProcessInfo(pid, proc_info))
+ return SendErrorResponse(1);
+
+ StreamString response;
+ CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qC(StringExtractorGDBRemote &packet) {
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ // Make sure we set the current thread so g and p packets return the data the
+ // gdb will expect.
+ lldb::tid_t tid = m_current_process->GetCurrentThreadID();
+ SetCurrentThreadID(tid);
+
+ NativeThreadProtocol *thread = m_current_process->GetCurrentThread();
+ if (!thread)
+ return SendErrorResponse(69);
+
+ StreamString response;
+ response.PutCString("QC");
+ AppendThreadIDToResponse(response, m_current_process->GetID(),
+ thread->GetID());
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ if (!m_non_stop)
+ StopSTDIOForwarding();
+
+ if (m_debugged_processes.empty()) {
+ LLDB_LOG(log, "No debugged process found.");
+ return PacketResult::Success;
+ }
+
+ for (auto it = m_debugged_processes.begin(); it != m_debugged_processes.end();
+ ++it) {
+ LLDB_LOG(log, "Killing process {0}", it->first);
+ Status error = it->second.process_up->Kill();
+ if (error.Fail())
+ LLDB_LOG(log, "Failed to kill debugged process {0}: {1}", it->first,
+ error);
+ }
+
+ // The response to kill packet is undefined per the spec. LLDB
+ // follows the same rules as for continue packets, i.e. no response
+ // in all-stop mode, and "OK" in non-stop mode; in both cases this
+ // is followed by the actual stop reason.
+ return SendContinueSuccessResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vKill(
+ StringExtractorGDBRemote &packet) {
+ if (!m_non_stop)
+ StopSTDIOForwarding();
+
+ packet.SetFilePos(6); // vKill;
+ uint32_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16);
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendIllFormedResponse(packet,
+ "vKill failed to parse the process id");
+
+ auto it = m_debugged_processes.find(pid);
+ if (it == m_debugged_processes.end())
+ return SendErrorResponse(42);
+
+ Status error = it->second.process_up->Kill();
+ if (error.Fail())
+ return SendErrorResponse(error.ToError());
+
+ // OK response is sent when the process dies.
+ it->second.flags |= DebuggedProcess::Flag::vkilled;
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("QSetDisableASLR:"));
+ if (packet.GetU32(0))
+ m_process_launch_info.GetFlags().Set(eLaunchFlagDisableASLR);
+ else
+ m_process_launch_info.GetFlags().Clear(eLaunchFlagDisableASLR);
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("QSetWorkingDir:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ m_process_launch_info.SetWorkingDirectory(FileSpec(path));
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir(
+ StringExtractorGDBRemote &packet) {
+ FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()};
+ if (working_dir) {
+ StreamString response;
+ response.PutStringAsRawHex8(working_dir.GetPath().c_str());
+ return SendPacketNoLock(response.GetString());
+ }
+
+ return SendErrorResponse(14);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QThreadSuffixSupported(
+ StringExtractorGDBRemote &packet) {
+ m_thread_suffix_supported = true;
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QListThreadsInStopReply(
+ StringExtractorGDBRemote &packet) {
+ m_list_threads_in_stop_reply = true;
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::ResumeProcess(
+ NativeProcessProtocol &process, const ResumeActionList &actions) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
+
+ // In non-stop protocol mode, the process could be running already.
+ // We do not support resuming threads independently, so just error out.
+ if (!process.CanResume()) {
+ LLDB_LOG(log, "process {0} cannot be resumed (state={1})", process.GetID(),
+ process.GetState());
+ return SendErrorResponse(0x37);
+ }
+
+ Status error = process.Resume(actions);
+ if (error.Fail()) {
+ LLDB_LOG(log, "process {0} failed to resume: {1}", process.GetID(), error);
+ return SendErrorResponse(GDBRemoteServerError::eErrorResume);
+ }
+
+ LLDB_LOG(log, "process {0} resumed", process.GetID());
+
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
+
+ // Ensure we have a native process.
+ if (!m_continue_process) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s no debugged process "
+ "shared pointer",
+ __FUNCTION__);
+ return SendErrorResponse(0x36);
+ }
+
+ // Pull out the signal number.
+ packet.SetFilePos(::strlen("C"));
+ if (packet.GetBytesLeft() < 1) {
+ // Shouldn't be using a C without a signal.
+ return SendIllFormedResponse(packet, "C packet specified without signal.");
+ }
+ const uint32_t signo =
+ packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max());
+ if (signo == std::numeric_limits<uint32_t>::max())
+ return SendIllFormedResponse(packet, "failed to parse signal number");
+
+ // Handle optional continue address.
+ if (packet.GetBytesLeft() > 0) {
+ // FIXME add continue at address support for $C{signo}[;{continue-address}].
+ if (*packet.Peek() == ';')
+ return SendUnimplementedResponse(packet.GetStringRef().data());
+ else
+ return SendIllFormedResponse(
+ packet, "unexpected content after $C{signal-number}");
+ }
+
+ // In non-stop protocol mode, the process could be running already.
+ // We do not support resuming threads independently, so just error out.
+ if (!m_continue_process->CanResume()) {
+ LLDB_LOG(log, "process cannot be resumed (state={0})",
+ m_continue_process->GetState());
+ return SendErrorResponse(0x37);
+ }
+
+ ResumeActionList resume_actions(StateType::eStateRunning,
+ LLDB_INVALID_SIGNAL_NUMBER);
+ Status error;
+
+ // We have two branches: what to do if a continue thread is specified (in
+ // which case we target sending the signal to that thread), or when we don't
+ // have a continue thread set (in which case we send a signal to the
+ // process).
+
+ // TODO discuss with Greg Clayton, make sure this makes sense.
+
+ lldb::tid_t signal_tid = GetContinueThreadID();
+ if (signal_tid != LLDB_INVALID_THREAD_ID) {
+ // The resume action for the continue thread (or all threads if a continue
+ // thread is not set).
+ ResumeAction action = {GetContinueThreadID(), StateType::eStateRunning,
+ static_cast<int>(signo)};
+
+ // Add the action for the continue thread (or all threads when the continue
+ // thread isn't present).
+ resume_actions.Append(action);
+ } else {
+ // Send the signal to the process since we weren't targeting a specific
+ // continue thread with the signal.
+ error = m_continue_process->Signal(signo);
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to send signal for process {0}: {1}",
+ m_continue_process->GetID(), error);
+
+ return SendErrorResponse(0x52);
+ }
+ }
+
+ // NB: this checks CanResume() twice but using a single code path for
+ // resuming still seems worth it.
+ PacketResult resume_res = ResumeProcess(*m_continue_process, resume_actions);
+ if (resume_res != PacketResult::Success)
+ return resume_res;
+
+ // Don't send an "OK" packet, except in non-stop mode;
+ // otherwise, the response is the stopped/exited message.
+ return SendContinueSuccessResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
+
+ packet.SetFilePos(packet.GetFilePos() + ::strlen("c"));
+
+ // For now just support all continue.
+ const bool has_continue_address = (packet.GetBytesLeft() > 0);
+ if (has_continue_address) {
+ LLDB_LOG(log, "not implemented for c[address] variant [{0} remains]",
+ packet.Peek());
+ return SendUnimplementedResponse(packet.GetStringRef().data());
+ }
+
+ // Ensure we have a native process.
+ if (!m_continue_process) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s no debugged process "
+ "shared pointer",
+ __FUNCTION__);
+ return SendErrorResponse(0x36);
+ }
+
+ // Build the ResumeActionList
+ ResumeActionList actions(StateType::eStateRunning,
+ LLDB_INVALID_SIGNAL_NUMBER);
+
+ PacketResult resume_res = ResumeProcess(*m_continue_process, actions);
+ if (resume_res != PacketResult::Success)
+ return resume_res;
+
+ return SendContinueSuccessResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vCont_actions(
+ StringExtractorGDBRemote &packet) {
+ StreamString response;
+ response.Printf("vCont;c;C;s;S;t");
+
+ return SendPacketNoLock(response.GetString());
+}
+
+static bool ResumeActionListStopsAllThreads(ResumeActionList &actions) {
+ // We're doing a stop-all if and only if our only action is a "t" for all
+ // threads.
+ if (const ResumeAction *default_action =
+ actions.GetActionForThread(LLDB_INVALID_THREAD_ID, false)) {
+ if (default_action->state == eStateSuspended && actions.GetSize() == 1)
+ return true;
+ }
+
+ return false;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vCont(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s handling vCont packet",
+ __FUNCTION__);
+
+ packet.SetFilePos(::strlen("vCont"));
+
+ if (packet.GetBytesLeft() == 0) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s missing action from "
+ "vCont package",
+ __FUNCTION__);
+ return SendIllFormedResponse(packet, "Missing action from vCont package");
+ }
+
+ if (::strcmp(packet.Peek(), ";s") == 0) {
+ // Move past the ';', then do a simple 's'.
+ packet.SetFilePos(packet.GetFilePos() + 1);
+ return Handle_s(packet);
+ }
+
+ std::unordered_map<lldb::pid_t, ResumeActionList> thread_actions;
+
+ while (packet.GetBytesLeft() && *packet.Peek() == ';') {
+ // Skip the semi-colon.
+ packet.GetChar();
+
+ // Build up the thread action.
+ ResumeAction thread_action;
+ thread_action.tid = LLDB_INVALID_THREAD_ID;
+ thread_action.state = eStateInvalid;
+ thread_action.signal = LLDB_INVALID_SIGNAL_NUMBER;
+
+ const char action = packet.GetChar();
+ switch (action) {
+ case 'C':
+ thread_action.signal = packet.GetHexMaxU32(false, 0);
+ if (thread_action.signal == 0)
+ return SendIllFormedResponse(
+ packet, "Could not parse signal in vCont packet C action");
+ [[fallthrough]];
+
+ case 'c':
+ // Continue
+ thread_action.state = eStateRunning;
+ break;
+
+ case 'S':
+ thread_action.signal = packet.GetHexMaxU32(false, 0);
+ if (thread_action.signal == 0)
+ return SendIllFormedResponse(
+ packet, "Could not parse signal in vCont packet S action");
+ [[fallthrough]];
+
+ case 's':
+ // Step
+ thread_action.state = eStateStepping;
+ break;
+
+ case 't':
+ // Stop
+ thread_action.state = eStateSuspended;
+ break;
+
+ default:
+ return SendIllFormedResponse(packet, "Unsupported vCont action");
+ break;
+ }
+
+ // If there's no thread-id (e.g. "vCont;c"), it's "p-1.-1".
+ lldb::pid_t pid = StringExtractorGDBRemote::AllProcesses;
+ lldb::tid_t tid = StringExtractorGDBRemote::AllThreads;
+
+ // Parse out optional :{thread-id} value.
+ if (packet.GetBytesLeft() && (*packet.Peek() == ':')) {
+ // Consume the separator.
+ packet.GetChar();
+
+ auto pid_tid = packet.GetPidTid(LLDB_INVALID_PROCESS_ID);
+ if (!pid_tid)
+ return SendIllFormedResponse(packet, "Malformed thread-id");
+
+ pid = pid_tid->first;
+ tid = pid_tid->second;
+ }
+
+ if (thread_action.state == eStateSuspended &&
+ tid != StringExtractorGDBRemote::AllThreads) {
+ return SendIllFormedResponse(
+ packet, "'t' action not supported for individual threads");
+ }
+
+ // If we get TID without PID, it's the current process.
+ if (pid == LLDB_INVALID_PROCESS_ID) {
+ if (!m_continue_process) {
+ LLDB_LOG(log, "no process selected via Hc");
+ return SendErrorResponse(0x36);
+ }
+ pid = m_continue_process->GetID();
+ }
+
+ assert(pid != LLDB_INVALID_PROCESS_ID);
+ if (tid == StringExtractorGDBRemote::AllThreads)
+ tid = LLDB_INVALID_THREAD_ID;
+ thread_action.tid = tid;
+
+ if (pid == StringExtractorGDBRemote::AllProcesses) {
+ if (tid != LLDB_INVALID_THREAD_ID)
+ return SendIllFormedResponse(
+ packet, "vCont: p-1 is not valid with a specific tid");
+ for (auto &process_it : m_debugged_processes)
+ thread_actions[process_it.first].Append(thread_action);
+ } else
+ thread_actions[pid].Append(thread_action);
+ }
+
+ assert(thread_actions.size() >= 1);
+ if (thread_actions.size() > 1 && !m_non_stop)
+ return SendIllFormedResponse(
+ packet,
+ "Resuming multiple processes is supported in non-stop mode only");
+
+ for (std::pair<lldb::pid_t, ResumeActionList> x : thread_actions) {
+ auto process_it = m_debugged_processes.find(x.first);
+ if (process_it == m_debugged_processes.end()) {
+ LLDB_LOG(log, "vCont failed for process {0}: process not debugged",
+ x.first);
+ return SendErrorResponse(GDBRemoteServerError::eErrorResume);
+ }
+
+ // There are four possible scenarios here. These are:
+ // 1. vCont on a stopped process that resumes at least one thread.
+ // In this case, we call Resume().
+ // 2. vCont on a stopped process that leaves all threads suspended.
+ // A no-op.
+ // 3. vCont on a running process that requests suspending all
+ // running threads. In this case, we call Interrupt().
+ // 4. vCont on a running process that requests suspending a subset
+ // of running threads or resuming a subset of suspended threads.
+ // Since we do not support full nonstop mode, this is unsupported
+ // and we return an error.
+
+ assert(process_it->second.process_up);
+ if (ResumeActionListStopsAllThreads(x.second)) {
+ if (process_it->second.process_up->IsRunning()) {
+ assert(m_non_stop);
+
+ Status error = process_it->second.process_up->Interrupt();
+ if (error.Fail()) {
+ LLDB_LOG(log, "vCont failed to halt process {0}: {1}", x.first,
+ error);
+ return SendErrorResponse(GDBRemoteServerError::eErrorResume);
+ }
+
+ LLDB_LOG(log, "halted process {0}", x.first);
+
+ // hack to avoid enabling stdio forwarding after stop
+ // TODO: remove this when we improve stdio forwarding for nonstop
+ assert(thread_actions.size() == 1);
+ return SendOKResponse();
+ }
+ } else {
+ PacketResult resume_res =
+ ResumeProcess(*process_it->second.process_up, x.second);
+ if (resume_res != PacketResult::Success)
+ return resume_res;
+ }
+ }
+
+ return SendContinueSuccessResponse();
+}
+
+void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID(lldb::tid_t tid) {
+ Log *log = GetLog(LLDBLog::Thread);
+ LLDB_LOG(log, "setting current thread id to {0}", tid);
+
+ m_current_tid = tid;
+ if (m_current_process)
+ m_current_process->SetCurrentThreadID(m_current_tid);
+}
+
+void GDBRemoteCommunicationServerLLGS::SetContinueThreadID(lldb::tid_t tid) {
+ Log *log = GetLog(LLDBLog::Thread);
+ LLDB_LOG(log, "setting continue thread id to {0}", tid);
+
+ m_continue_tid = tid;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_stop_reason(
+ StringExtractorGDBRemote &packet) {
+ // Handle the $? gdbremote command.
+
+ if (m_non_stop) {
+ // Clear the notification queue first, except for pending exit
+ // notifications.
+ llvm::erase_if(m_stop_notification_queue, [](const std::string &x) {
+ return x.front() != 'W' && x.front() != 'X';
+ });
+
+ if (m_current_process) {
+ // Queue stop reply packets for all active threads. Start with
+ // the current thread (for clients that don't actually support multiple
+ // stop reasons).
+ NativeThreadProtocol *thread = m_current_process->GetCurrentThread();
+ if (thread) {
+ StreamString stop_reply = PrepareStopReplyPacketForThread(*thread);
+ if (!stop_reply.Empty())
+ m_stop_notification_queue.push_back(stop_reply.GetString().str());
+ }
+ EnqueueStopReplyPackets(thread ? thread->GetID()
+ : LLDB_INVALID_THREAD_ID);
+ }
+
+ // If the notification queue is empty (i.e. everything is running), send OK.
+ if (m_stop_notification_queue.empty())
+ return SendOKResponse();
+
+ // Send the first item from the new notification queue synchronously.
+ return SendPacketNoLock(m_stop_notification_queue.front());
+ }
+
+ // If no process, indicate error
+ if (!m_current_process)
+ return SendErrorResponse(02);
+
+ return SendStopReasonForState(*m_current_process,
+ m_current_process->GetState(),
+ /*force_synchronous=*/true);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendStopReasonForState(
+ NativeProcessProtocol &process, lldb::StateType process_state,
+ bool force_synchronous) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ if (m_disabling_non_stop) {
+ // Check if we are waiting for any more processes to stop. If we are,
+ // do not send the OK response yet.
+ for (const auto &it : m_debugged_processes) {
+ if (it.second.process_up->IsRunning())
+ return PacketResult::Success;
+ }
+
+ // If all expected processes were stopped after a QNonStop:0 request,
+ // send the OK response.
+ m_disabling_non_stop = false;
+ return SendOKResponse();
+ }
+
+ switch (process_state) {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ // NOTE: gdb protocol doc looks like it should return $OK
+ // when everything is running (i.e. no stopped result).
+ return PacketResult::Success; // Ignore
+
+ case eStateSuspended:
+ case eStateStopped:
+ case eStateCrashed: {
+ lldb::tid_t tid = process.GetCurrentThreadID();
+ // Make sure we set the current thread so g and p packets return the data
+ // the gdb will expect.
+ SetCurrentThreadID(tid);
+ return SendStopReplyPacketForThread(process, tid, force_synchronous);
+ }
+
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ return SendWResponse(&process);
+
+ default:
+ LLDB_LOG(log, "pid {0}, current state reporting not handled: {1}",
+ process.GetID(), process_state);
+ break;
+ }
+
+ return SendErrorResponse(0);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo(
+ StringExtractorGDBRemote &packet) {
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ // Ensure we have a thread.
+ NativeThreadProtocol *thread = m_current_process->GetThreadAtIndex(0);
+ if (!thread)
+ return SendErrorResponse(69);
+
+ // Get the register context for the first thread.
+ NativeRegisterContext &reg_context = thread->GetRegisterContext();
+
+ // Parse out the register number from the request.
+ packet.SetFilePos(strlen("qRegisterInfo"));
+ const uint32_t reg_index =
+ packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max());
+ if (reg_index == std::numeric_limits<uint32_t>::max())
+ return SendErrorResponse(69);
+
+ // Return the end of registers response if we've iterated one past the end of
+ // the register set.
+ if (reg_index >= reg_context.GetUserRegisterCount())
+ return SendErrorResponse(69);
+
+ const RegisterInfo *reg_info = reg_context.GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ return SendErrorResponse(69);
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ response.PutCString("name:");
+ response.PutCString(reg_info->name);
+ response.PutChar(';');
+
+ if (reg_info->alt_name && reg_info->alt_name[0]) {
+ response.PutCString("alt-name:");
+ response.PutCString(reg_info->alt_name);
+ response.PutChar(';');
+ }
+
+ response.Printf("bitsize:%" PRIu32 ";", reg_info->byte_size * 8);
+
+ if (!reg_context.RegisterOffsetIsDynamic())
+ response.Printf("offset:%" PRIu32 ";", reg_info->byte_offset);
+
+ llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info);
+ if (!encoding.empty())
+ response << "encoding:" << encoding << ';';
+
+ llvm::StringRef format = GetFormatNameOrEmpty(*reg_info);
+ if (!format.empty())
+ response << "format:" << format << ';';
+
+ const char *const register_set_name =
+ reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index);
+ if (register_set_name)
+ response << "set:" << register_set_name << ';';
+
+ if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] !=
+ LLDB_INVALID_REGNUM)
+ response.Printf("ehframe:%" PRIu32 ";",
+ reg_info->kinds[RegisterKind::eRegisterKindEHFrame]);
+
+ if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
+ response.Printf("dwarf:%" PRIu32 ";",
+ reg_info->kinds[RegisterKind::eRegisterKindDWARF]);
+
+ llvm::StringRef kind_generic = GetKindGenericOrEmpty(*reg_info);
+ if (!kind_generic.empty())
+ response << "generic:" << kind_generic << ';';
+
+ if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) {
+ response.PutCString("container-regs:");
+ CollectRegNums(reg_info->value_regs, response, true);
+ response.PutChar(';');
+ }
+
+ if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) {
+ response.PutCString("invalidate-regs:");
+ CollectRegNums(reg_info->invalidate_regs, response, true);
+ response.PutChar(';');
+ }
+
+ return SendPacketNoLock(response.GetString());
+}
+
+void GDBRemoteCommunicationServerLLGS::AddProcessThreads(
+ StreamGDBRemote &response, NativeProcessProtocol &process, bool &had_any) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ lldb::pid_t pid = process.GetID();
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return;
+
+ LLDB_LOG(log, "iterating over threads of process {0}", process.GetID());
+ for (NativeThreadProtocol &thread : process.Threads()) {
+ LLDB_LOG(log, "iterated thread tid={0}", thread.GetID());
+ response.PutChar(had_any ? ',' : 'm');
+ AppendThreadIDToResponse(response, pid, thread.GetID());
+ had_any = true;
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo(
+ StringExtractorGDBRemote &packet) {
+ assert(m_debugged_processes.size() <= 1 ||
+ bool(m_extensions_supported &
+ NativeProcessProtocol::Extension::multiprocess));
+
+ bool had_any = false;
+ StreamGDBRemote response;
+
+ for (auto &pid_ptr : m_debugged_processes)
+ AddProcessThreads(response, *pid_ptr.second.process_up, had_any);
+
+ if (!had_any)
+ return SendOKResponse();
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo(
+ StringExtractorGDBRemote &packet) {
+ // FIXME for now we return the full thread list in the initial packet and
+ // always do nothing here.
+ return SendPacketNoLock("l");
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_g(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ // Move past packet name.
+ packet.SetFilePos(strlen("g"));
+
+ // Get the thread to use.
+ NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
+ if (!thread) {
+ LLDB_LOG(log, "failed, no thread available");
+ return SendErrorResponse(0x15);
+ }
+
+ // Get the thread's register context.
+ NativeRegisterContext &reg_ctx = thread->GetRegisterContext();
+
+ std::vector<uint8_t> regs_buffer;
+ for (uint32_t reg_num = 0; reg_num < reg_ctx.GetUserRegisterCount();
+ ++reg_num) {
+ const RegisterInfo *reg_info = reg_ctx.GetRegisterInfoAtIndex(reg_num);
+
+ if (reg_info == nullptr) {
+ LLDB_LOG(log, "failed to get register info for register index {0}",
+ reg_num);
+ return SendErrorResponse(0x15);
+ }
+
+ if (reg_info->value_regs != nullptr)
+ continue; // skip registers that are contained in other registers
+
+ RegisterValue reg_value;
+ Status error = reg_ctx.ReadRegister(reg_info, reg_value);
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to read register at index {0}", reg_num);
+ return SendErrorResponse(0x15);
+ }
+
+ if (reg_info->byte_offset + reg_info->byte_size >= regs_buffer.size())
+ // Resize the buffer to guarantee it can store the register offsetted
+ // data.
+ regs_buffer.resize(reg_info->byte_offset + reg_info->byte_size);
+
+ // Copy the register offsetted data to the buffer.
+ memcpy(regs_buffer.data() + reg_info->byte_offset, reg_value.GetBytes(),
+ reg_info->byte_size);
+ }
+
+ // Write the response.
+ StreamGDBRemote response;
+ response.PutBytesAsRawHex8(regs_buffer.data(), regs_buffer.size());
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ // Parse out the register number from the request.
+ packet.SetFilePos(strlen("p"));
+ const uint32_t reg_index =
+ packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max());
+ if (reg_index == std::numeric_limits<uint32_t>::max()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, could not "
+ "parse register number from request \"%s\"",
+ __FUNCTION__, packet.GetStringRef().data());
+ return SendErrorResponse(0x15);
+ }
+
+ // Get the thread to use.
+ NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
+ if (!thread) {
+ LLDB_LOG(log, "failed, no thread available");
+ return SendErrorResponse(0x15);
+ }
+
+ // Get the thread's register context.
+ NativeRegisterContext &reg_context = thread->GetRegisterContext();
+
+ // Return the end of registers response if we've iterated one past the end of
+ // the register set.
+ if (reg_index >= reg_context.GetUserRegisterCount()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, requested "
+ "register %" PRIu32 " beyond register count %" PRIu32,
+ __FUNCTION__, reg_index, reg_context.GetUserRegisterCount());
+ return SendErrorResponse(0x15);
+ }
+
+ const RegisterInfo *reg_info = reg_context.GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, requested "
+ "register %" PRIu32 " returned NULL",
+ __FUNCTION__, reg_index);
+ return SendErrorResponse(0x15);
+ }
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ // Retrieve the value
+ RegisterValue reg_value;
+ Status error = reg_context.ReadRegister(reg_info, reg_value);
+ if (error.Fail()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, read of "
+ "requested register %" PRIu32 " (%s) failed: %s",
+ __FUNCTION__, reg_index, reg_info->name, error.AsCString());
+ return SendErrorResponse(0x15);
+ }
+
+ const uint8_t *const data =
+ static_cast<const uint8_t *>(reg_value.GetBytes());
+ if (!data) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed to get data "
+ "bytes from requested register %" PRIu32,
+ __FUNCTION__, reg_index);
+ return SendErrorResponse(0x15);
+ }
+
+ // FIXME flip as needed to get data in big/little endian format for this host.
+ for (uint32_t i = 0; i < reg_value.GetByteSize(); ++i)
+ response.PutHex8(data[i]);
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ // Ensure there is more content.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Empty P packet");
+
+ // Parse out the register number from the request.
+ packet.SetFilePos(strlen("P"));
+ const uint32_t reg_index =
+ packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max());
+ if (reg_index == std::numeric_limits<uint32_t>::max()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, could not "
+ "parse register number from request \"%s\"",
+ __FUNCTION__, packet.GetStringRef().data());
+ return SendErrorResponse(0x29);
+ }
+
+ // Note debugserver would send an E30 here.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != '='))
+ return SendIllFormedResponse(
+ packet, "P packet missing '=' char after register number");
+
+ // Parse out the value.
+ size_t reg_size = packet.GetHexBytesAvail(m_reg_bytes);
+
+ // Get the thread to use.
+ NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
+ if (!thread) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no thread "
+ "available (thread index 0)",
+ __FUNCTION__);
+ return SendErrorResponse(0x28);
+ }
+
+ // Get the thread's register context.
+ NativeRegisterContext &reg_context = thread->GetRegisterContext();
+ const RegisterInfo *reg_info = reg_context.GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, requested "
+ "register %" PRIu32 " returned NULL",
+ __FUNCTION__, reg_index);
+ return SendErrorResponse(0x48);
+ }
+
+ // Return the end of registers response if we've iterated one past the end of
+ // the register set.
+ if (reg_index >= reg_context.GetUserRegisterCount()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, requested "
+ "register %" PRIu32 " beyond register count %" PRIu32,
+ __FUNCTION__, reg_index, reg_context.GetUserRegisterCount());
+ return SendErrorResponse(0x47);
+ }
+
+ if (reg_size != reg_info->byte_size)
+ return SendIllFormedResponse(packet, "P packet register size is incorrect");
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ RegisterValue reg_value(ArrayRef<uint8_t>(m_reg_bytes, reg_size),
+ m_current_process->GetArchitecture().GetByteOrder());
+ Status error = reg_context.WriteRegister(reg_info, reg_value);
+ if (error.Fail()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, write of "
+ "requested register %" PRIu32 " (%s) failed: %s",
+ __FUNCTION__, reg_index, reg_info->name, error.AsCString());
+ return SendErrorResponse(0x32);
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ // Parse out which variant of $H is requested.
+ packet.SetFilePos(strlen("H"));
+ if (packet.GetBytesLeft() < 1) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, H command "
+ "missing {g,c} variant",
+ __FUNCTION__);
+ return SendIllFormedResponse(packet, "H command missing {g,c} variant");
+ }
+
+ const char h_variant = packet.GetChar();
+ NativeProcessProtocol *default_process;
+ switch (h_variant) {
+ case 'g':
+ default_process = m_current_process;
+ break;
+
+ case 'c':
+ default_process = m_continue_process;
+ break;
+
+ default:
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, invalid $H variant %c",
+ __FUNCTION__, h_variant);
+ return SendIllFormedResponse(packet,
+ "H variant unsupported, should be c or g");
+ }
+
+ // Parse out the thread number.
+ auto pid_tid = packet.GetPidTid(default_process ? default_process->GetID()
+ : LLDB_INVALID_PROCESS_ID);
+ if (!pid_tid)
+ return SendErrorResponse(llvm::make_error<StringError>(
+ inconvertibleErrorCode(), "Malformed thread-id"));
+
+ lldb::pid_t pid = pid_tid->first;
+ lldb::tid_t tid = pid_tid->second;
+
+ if (pid == StringExtractorGDBRemote::AllProcesses)
+ return SendUnimplementedResponse("Selecting all processes not supported");
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse(llvm::make_error<StringError>(
+ inconvertibleErrorCode(), "No current process and no PID provided"));
+
+ // Check the process ID and find respective process instance.
+ auto new_process_it = m_debugged_processes.find(pid);
+ if (new_process_it == m_debugged_processes.end())
+ return SendErrorResponse(llvm::make_error<StringError>(
+ inconvertibleErrorCode(),
+ llvm::formatv("No process with PID {0} debugged", pid)));
+
+ // Ensure we have the given thread when not specifying -1 (all threads) or 0
+ // (any thread).
+ if (tid != LLDB_INVALID_THREAD_ID && tid != 0) {
+ NativeThreadProtocol *thread =
+ new_process_it->second.process_up->GetThreadByID(tid);
+ if (!thread) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64
+ " not found",
+ __FUNCTION__, tid);
+ return SendErrorResponse(0x15);
+ }
+ }
+
+ // Now switch the given process and thread type.
+ switch (h_variant) {
+ case 'g':
+ m_current_process = new_process_it->second.process_up.get();
+ SetCurrentThreadID(tid);
+ break;
+
+ case 'c':
+ m_continue_process = new_process_it->second.process_up.get();
+ SetContinueThreadID(tid);
+ break;
+
+ default:
+ assert(false && "unsupported $H variant - shouldn't get here");
+ return SendIllFormedResponse(packet,
+ "H variant unsupported, should be c or g");
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ packet.SetFilePos(::strlen("I"));
+ uint8_t tmp[4096];
+ for (;;) {
+ size_t read = packet.GetHexBytesAvail(tmp);
+ if (read == 0) {
+ break;
+ }
+ // write directly to stdin *this might block if stdin buffer is full*
+ // TODO: enqueue this block in circular buffer and send window size to
+ // remote host
+ ConnectionStatus status;
+ Status error;
+ m_stdio_communication.WriteAll(tmp, read, status, &error);
+ if (error.Fail()) {
+ return SendErrorResponse(0x15);
+ }
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_interrupt(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
+
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOG(log, "failed, no process available");
+ return SendErrorResponse(0x15);
+ }
+
+ // Interrupt the process.
+ Status error = m_current_process->Interrupt();
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed for process {0}: {1}", m_current_process->GetID(),
+ error);
+ return SendErrorResponse(GDBRemoteServerError::eErrorResume);
+ }
+
+ LLDB_LOG(log, "stopped process {0}", m_current_process->GetID());
+
+ // No response required from stop all.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_memory_read(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("m"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short m packet");
+
+ // Read the address. Punting on validation.
+ // FIXME replace with Hex U64 read with no default value that fails on failed
+ // read.
+ const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
+
+ // Validate comma.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
+ return SendIllFormedResponse(packet, "Comma sep missing in m packet");
+
+ // Get # bytes to read.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Length missing in m packet");
+
+ const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
+ if (byte_count == 0) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s nothing to read: "
+ "zero-length packet",
+ __FUNCTION__);
+ return SendOKResponse();
+ }
+
+ // Allocate the response buffer.
+ std::string buf(byte_count, '\0');
+ if (buf.empty())
+ return SendErrorResponse(0x78);
+
+ // Retrieve the process memory.
+ size_t bytes_read = 0;
+ Status error = m_current_process->ReadMemoryWithoutTrap(
+ read_addr, &buf[0], byte_count, bytes_read);
+ if (error.Fail()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " mem 0x%" PRIx64 ": failed to read. Error: %s",
+ __FUNCTION__, m_current_process->GetID(), read_addr,
+ error.AsCString());
+ return SendErrorResponse(0x08);
+ }
+
+ if (bytes_read == 0) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes",
+ __FUNCTION__, m_current_process->GetID(), read_addr, byte_count);
+ return SendErrorResponse(0x08);
+ }
+
+ StreamGDBRemote response;
+ packet.SetFilePos(0);
+ char kind = packet.GetChar('?');
+ if (kind == 'x')
+ response.PutEscapedBytes(buf.data(), byte_count);
+ else {
+ assert(kind == 'm');
+ for (size_t i = 0; i < bytes_read; ++i)
+ response.PutHex8(buf[i]);
+ }
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("_M"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short _M packet");
+
+ const lldb::addr_t size = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ if (size == LLDB_INVALID_ADDRESS)
+ return SendIllFormedResponse(packet, "Address not valid");
+ if (packet.GetChar() != ',')
+ return SendIllFormedResponse(packet, "Bad packet");
+ Permissions perms = {};
+ while (packet.GetBytesLeft() > 0) {
+ switch (packet.GetChar()) {
+ case 'r':
+ perms |= ePermissionsReadable;
+ break;
+ case 'w':
+ perms |= ePermissionsWritable;
+ break;
+ case 'x':
+ perms |= ePermissionsExecutable;
+ break;
+ default:
+ return SendIllFormedResponse(packet, "Bad permissions");
+ }
+ }
+
+ llvm::Expected<addr_t> addr = m_current_process->AllocateMemory(size, perms);
+ if (!addr)
+ return SendErrorResponse(addr.takeError());
+
+ StreamGDBRemote response;
+ response.PutHex64(*addr);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("_m"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short m packet");
+
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ if (addr == LLDB_INVALID_ADDRESS)
+ return SendIllFormedResponse(packet, "Address not valid");
+
+ if (llvm::Error Err = m_current_process->DeallocateMemory(addr))
+ return SendErrorResponse(std::move(Err));
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("M"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short M packet");
+
+ // Read the address. Punting on validation.
+ // FIXME replace with Hex U64 read with no default value that fails on failed
+ // read.
+ const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0);
+
+ // Validate comma.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
+ return SendIllFormedResponse(packet, "Comma sep missing in M packet");
+
+ // Get # bytes to read.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Length missing in M packet");
+
+ const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
+ if (byte_count == 0) {
+ LLDB_LOG(log, "nothing to write: zero-length packet");
+ return PacketResult::Success;
+ }
+
+ // Validate colon.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':'))
+ return SendIllFormedResponse(
+ packet, "Comma sep missing in M packet after byte length");
+
+ // Allocate the conversion buffer.
+ std::vector<uint8_t> buf(byte_count, 0);
+ if (buf.empty())
+ return SendErrorResponse(0x78);
+
+ // Convert the hex memory write contents to bytes.
+ StreamGDBRemote response;
+ const uint64_t convert_count = packet.GetHexBytes(buf, 0);
+ if (convert_count != byte_count) {
+ LLDB_LOG(log,
+ "pid {0} mem {1:x}: asked to write {2} bytes, but only found {3} "
+ "to convert.",
+ m_current_process->GetID(), write_addr, byte_count, convert_count);
+ return SendIllFormedResponse(packet, "M content byte length specified did "
+ "not match hex-encoded content "
+ "length");
+ }
+
+ // Write the process memory.
+ size_t bytes_written = 0;
+ Status error = m_current_process->WriteMemory(write_addr, &buf[0], byte_count,
+ bytes_written);
+ if (error.Fail()) {
+ LLDB_LOG(log, "pid {0} mem {1:x}: failed to write. Error: {2}",
+ m_current_process->GetID(), write_addr, error);
+ return SendErrorResponse(0x09);
+ }
+
+ if (bytes_written == 0) {
+ LLDB_LOG(log, "pid {0} mem {1:x}: wrote 0 of {2} requested bytes",
+ m_current_process->GetID(), write_addr, byte_count);
+ return SendErrorResponse(0x09);
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ // Currently only the NativeProcessProtocol knows if it can handle a
+ // qMemoryRegionInfoSupported request, but we're not guaranteed to be
+ // attached to a process. For now we'll assume the client only asks this
+ // when a process is being debugged.
+
+ // Ensure we have a process running; otherwise, we can't figure this out
+ // since we won't have a NativeProcessProtocol.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Test if we can get any region back when asking for the region around NULL.
+ MemoryRegionInfo region_info;
+ const Status error = m_current_process->GetMemoryRegionInfo(0, region_info);
+ if (error.Fail()) {
+ // We don't support memory region info collection for this
+ // NativeProcessProtocol.
+ return SendUnimplementedResponse("");
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ // Ensure we have a process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("qMemoryRegionInfo:"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet");
+
+ // Read the address. Punting on validation.
+ const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
+
+ StreamGDBRemote response;
+
+ // Get the memory region info for the target address.
+ MemoryRegionInfo region_info;
+ const Status error =
+ m_current_process->GetMemoryRegionInfo(read_addr, region_info);
+ if (error.Fail()) {
+ // Return the error message.
+
+ response.PutCString("error:");
+ response.PutStringAsRawHex8(error.AsCString());
+ response.PutChar(';');
+ } else {
+ // Range start and size.
+ response.Printf("start:%" PRIx64 ";size:%" PRIx64 ";",
+ region_info.GetRange().GetRangeBase(),
+ region_info.GetRange().GetByteSize());
+
+ // Permissions.
+ if (region_info.GetReadable() || region_info.GetWritable() ||
+ region_info.GetExecutable()) {
+ // Write permissions info.
+ response.PutCString("permissions:");
+
+ if (region_info.GetReadable())
+ response.PutChar('r');
+ if (region_info.GetWritable())
+ response.PutChar('w');
+ if (region_info.GetExecutable())
+ response.PutChar('x');
+
+ response.PutChar(';');
+ }
+
+ // Flags
+ MemoryRegionInfo::OptionalBool memory_tagged =
+ region_info.GetMemoryTagged();
+ if (memory_tagged != MemoryRegionInfo::eDontKnow) {
+ response.PutCString("flags:");
+ if (memory_tagged == MemoryRegionInfo::eYes) {
+ response.PutCString("mt");
+ }
+ response.PutChar(';');
+ }
+
+ // Name
+ ConstString name = region_info.GetName();
+ if (name) {
+ response.PutCString("name:");
+ response.PutStringAsRawHex8(name.GetStringRef());
+ response.PutChar(';');
+ }
+ }
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) {
+ // Ensure we have a process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ Log *log = GetLog(LLDBLog::Process);
+ LLDB_LOG(log, "failed, no process available");
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out software or hardware breakpoint or watchpoint requested.
+ packet.SetFilePos(strlen("Z"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(
+ packet, "Too short Z packet, missing software/hardware specifier");
+
+ bool want_breakpoint = true;
+ bool want_hardware = false;
+ uint32_t watch_flags = 0;
+
+ const GDBStoppointType stoppoint_type =
+ GDBStoppointType(packet.GetS32(eStoppointInvalid));
+ switch (stoppoint_type) {
+ case eBreakpointSoftware:
+ want_hardware = false;
+ want_breakpoint = true;
+ break;
+ case eBreakpointHardware:
+ want_hardware = true;
+ want_breakpoint = true;
+ break;
+ case eWatchpointWrite:
+ watch_flags = 1;
+ want_hardware = true;
+ want_breakpoint = false;
+ break;
+ case eWatchpointRead:
+ watch_flags = 2;
+ want_hardware = true;
+ want_breakpoint = false;
+ break;
+ case eWatchpointReadWrite:
+ watch_flags = 3;
+ want_hardware = true;
+ want_breakpoint = false;
+ break;
+ case eStoppointInvalid:
+ return SendIllFormedResponse(
+ packet, "Z packet had invalid software/hardware specifier");
+ }
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',')
+ return SendIllFormedResponse(
+ packet, "Malformed Z packet, expecting comma after stoppoint type");
+
+ // Parse out the stoppoint address.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short Z packet, missing address");
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',')
+ return SendIllFormedResponse(
+ packet, "Malformed Z packet, expecting comma after address");
+
+ // Parse out the stoppoint size (i.e. size hint for opcode size).
+ const uint32_t size =
+ packet.GetHexMaxU32(false, std::numeric_limits<uint32_t>::max());
+ if (size == std::numeric_limits<uint32_t>::max())
+ return SendIllFormedResponse(
+ packet, "Malformed Z packet, failed to parse size argument");
+
+ if (want_breakpoint) {
+ // Try to set the breakpoint.
+ const Status error =
+ m_current_process->SetBreakpoint(addr, size, want_hardware);
+ if (error.Success())
+ return SendOKResponse();
+ Log *log = GetLog(LLDBLog::Breakpoints);
+ LLDB_LOG(log, "pid {0} failed to set breakpoint: {1}",
+ m_current_process->GetID(), error);
+ return SendErrorResponse(0x09);
+ } else {
+ // Try to set the watchpoint.
+ const Status error = m_current_process->SetWatchpoint(
+ addr, size, watch_flags, want_hardware);
+ if (error.Success())
+ return SendOKResponse();
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "pid {0} failed to set watchpoint: {1}",
+ m_current_process->GetID(), error);
+ return SendErrorResponse(0x09);
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) {
+ // Ensure we have a process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ Log *log = GetLog(LLDBLog::Process);
+ LLDB_LOG(log, "failed, no process available");
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out software or hardware breakpoint or watchpoint requested.
+ packet.SetFilePos(strlen("z"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(
+ packet, "Too short z packet, missing software/hardware specifier");
+
+ bool want_breakpoint = true;
+ bool want_hardware = false;
+
+ const GDBStoppointType stoppoint_type =
+ GDBStoppointType(packet.GetS32(eStoppointInvalid));
+ switch (stoppoint_type) {
+ case eBreakpointHardware:
+ want_breakpoint = true;
+ want_hardware = true;
+ break;
+ case eBreakpointSoftware:
+ want_breakpoint = true;
+ break;
+ case eWatchpointWrite:
+ want_breakpoint = false;
+ break;
+ case eWatchpointRead:
+ want_breakpoint = false;
+ break;
+ case eWatchpointReadWrite:
+ want_breakpoint = false;
+ break;
+ default:
+ return SendIllFormedResponse(
+ packet, "z packet had invalid software/hardware specifier");
+ }
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',')
+ return SendIllFormedResponse(
+ packet, "Malformed z packet, expecting comma after stoppoint type");
+
+ // Parse out the stoppoint address.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short z packet, missing address");
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar() != ',')
+ return SendIllFormedResponse(
+ packet, "Malformed z packet, expecting comma after address");
+
+ /*
+ // Parse out the stoppoint size (i.e. size hint for opcode size).
+ const uint32_t size = packet.GetHexMaxU32 (false,
+ std::numeric_limits<uint32_t>::max ());
+ if (size == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed z packet, failed to parse
+ size argument");
+ */
+
+ if (want_breakpoint) {
+ // Try to clear the breakpoint.
+ const Status error =
+ m_current_process->RemoveBreakpoint(addr, want_hardware);
+ if (error.Success())
+ return SendOKResponse();
+ Log *log = GetLog(LLDBLog::Breakpoints);
+ LLDB_LOG(log, "pid {0} failed to remove breakpoint: {1}",
+ m_current_process->GetID(), error);
+ return SendErrorResponse(0x09);
+ } else {
+ // Try to clear the watchpoint.
+ const Status error = m_current_process->RemoveWatchpoint(addr);
+ if (error.Success())
+ return SendOKResponse();
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "pid {0} failed to remove watchpoint: {1}",
+ m_current_process->GetID(), error);
+ return SendErrorResponse(0x09);
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
+
+ // Ensure we have a process.
+ if (!m_continue_process ||
+ (m_continue_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x32);
+ }
+
+ // We first try to use a continue thread id. If any one or any all set, use
+ // the current thread. Bail out if we don't have a thread id.
+ lldb::tid_t tid = GetContinueThreadID();
+ if (tid == 0 || tid == LLDB_INVALID_THREAD_ID)
+ tid = GetCurrentThreadID();
+ if (tid == LLDB_INVALID_THREAD_ID)
+ return SendErrorResponse(0x33);
+
+ // Double check that we have such a thread.
+ // TODO investigate: on MacOSX we might need to do an UpdateThreads () here.
+ NativeThreadProtocol *thread = m_continue_process->GetThreadByID(tid);
+ if (!thread)
+ return SendErrorResponse(0x33);
+
+ // Create the step action for the given thread.
+ ResumeAction action = {tid, eStateStepping, LLDB_INVALID_SIGNAL_NUMBER};
+
+ // Setup the actions list.
+ ResumeActionList actions;
+ actions.Append(action);
+
+ // All other threads stop while we're single stepping a thread.
+ actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
+
+ PacketResult resume_res = ResumeProcess(*m_continue_process, actions);
+ if (resume_res != PacketResult::Success)
+ return resume_res;
+
+ // No response here, unless in non-stop mode.
+ // Otherwise, the stop or exit will come from the resulting action.
+ return SendContinueSuccessResponse();
+}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+GDBRemoteCommunicationServerLLGS::BuildTargetXml() {
+ // Ensure we have a thread.
+ NativeThreadProtocol *thread = m_current_process->GetThreadAtIndex(0);
+ if (!thread)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No thread available");
+
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
+ // Get the register context for the first thread.
+ NativeRegisterContext &reg_context = thread->GetRegisterContext();
+
+ StreamString response;
+
+ response.Printf("<?xml version=\"1.0\"?>\n");
+ response.Printf("<target version=\"1.0\">\n");
+ response.IndentMore();
+
+ response.Indent();
+ response.Printf("<architecture>%s</architecture>\n",
+ m_current_process->GetArchitecture()
+ .GetTriple()
+ .getArchName()
+ .str()
+ .c_str());
+
+ response.Indent("<feature>\n");
+
+ const int registers_count = reg_context.GetUserRegisterCount();
+ if (registers_count)
+ response.IndentMore();
+
+ llvm::StringSet<> field_enums_seen;
+ for (int reg_index = 0; reg_index < registers_count; reg_index++) {
+ const RegisterInfo *reg_info =
+ reg_context.GetRegisterInfoAtIndex(reg_index);
+
+ if (!reg_info) {
+ LLDB_LOGF(log,
+ "%s failed to get register info for register index %" PRIu32,
+ "target.xml", reg_index);
+ continue;
+ }
+
+ if (reg_info->flags_type) {
+ response.IndentMore();
+ reg_info->flags_type->EnumsToXML(response, field_enums_seen);
+ reg_info->flags_type->ToXML(response);
+ response.IndentLess();
+ }
+
+ response.Indent();
+ response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32
+ "\" regnum=\"%d\" ",
+ reg_info->name, reg_info->byte_size * 8, reg_index);
+
+ if (!reg_context.RegisterOffsetIsDynamic())
+ response.Printf("offset=\"%" PRIu32 "\" ", reg_info->byte_offset);
+
+ if (reg_info->alt_name && reg_info->alt_name[0])
+ response.Printf("altname=\"%s\" ", reg_info->alt_name);
+
+ llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info);
+ if (!encoding.empty())
+ response << "encoding=\"" << encoding << "\" ";
+
+ llvm::StringRef format = GetFormatNameOrEmpty(*reg_info);
+ if (!format.empty())
+ response << "format=\"" << format << "\" ";
+
+ if (reg_info->flags_type)
+ response << "type=\"" << reg_info->flags_type->GetID() << "\" ";
+
+ const char *const register_set_name =
+ reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index);
+ if (register_set_name)
+ response << "group=\"" << register_set_name << "\" ";
+
+ if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] !=
+ LLDB_INVALID_REGNUM)
+ response.Printf("ehframe_regnum=\"%" PRIu32 "\" ",
+ reg_info->kinds[RegisterKind::eRegisterKindEHFrame]);
+
+ if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] !=
+ LLDB_INVALID_REGNUM)
+ response.Printf("dwarf_regnum=\"%" PRIu32 "\" ",
+ reg_info->kinds[RegisterKind::eRegisterKindDWARF]);
+
+ llvm::StringRef kind_generic = GetKindGenericOrEmpty(*reg_info);
+ if (!kind_generic.empty())
+ response << "generic=\"" << kind_generic << "\" ";
+
+ if (reg_info->value_regs &&
+ reg_info->value_regs[0] != LLDB_INVALID_REGNUM) {
+ response.PutCString("value_regnums=\"");
+ CollectRegNums(reg_info->value_regs, response, false);
+ response.Printf("\" ");
+ }
+
+ if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) {
+ response.PutCString("invalidate_regnums=\"");
+ CollectRegNums(reg_info->invalidate_regs, response, false);
+ response.Printf("\" ");
+ }
+
+ response.Printf("/>\n");
+ }
+
+ if (registers_count)
+ response.IndentLess();
+
+ response.Indent("</feature>\n");
+ response.IndentLess();
+ response.Indent("</target>\n");
+ return MemoryBuffer::getMemBufferCopy(response.GetString(), "target.xml");
+}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object,
+ llvm::StringRef annex) {
+ // Make sure we have a valid process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No process available");
+ }
+
+ if (object == "auxv") {
+ // Grab the auxv data.
+ auto buffer_or_error = m_current_process->GetAuxvData();
+ if (!buffer_or_error)
+ return llvm::errorCodeToError(buffer_or_error.getError());
+ return std::move(*buffer_or_error);
+ }
+
+ if (object == "siginfo") {
+ NativeThreadProtocol *thread = m_current_process->GetCurrentThread();
+ if (!thread)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "no current thread");
+
+ auto buffer_or_error = thread->GetSiginfo();
+ if (!buffer_or_error)
+ return buffer_or_error.takeError();
+ return std::move(*buffer_or_error);
+ }
+
+ if (object == "libraries-svr4") {
+ auto library_list = m_current_process->GetLoadedSVR4Libraries();
+ if (!library_list)
+ return library_list.takeError();
+
+ StreamString response;
+ response.Printf("<library-list-svr4 version=\"1.0\">");
+ for (auto const &library : *library_list) {
+ response.Printf("<library name=\"%s\" ",
+ XMLEncodeAttributeValue(library.name.c_str()).c_str());
+ response.Printf("lm=\"0x%" PRIx64 "\" ", library.link_map);
+ response.Printf("l_addr=\"0x%" PRIx64 "\" ", library.base_addr);
+ response.Printf("l_ld=\"0x%" PRIx64 "\" />", library.ld_addr);
+ }
+ response.Printf("</library-list-svr4>");
+ return MemoryBuffer::getMemBufferCopy(response.GetString(), __FUNCTION__);
+ }
+
+ if (object == "features" && annex == "target.xml")
+ return BuildTargetXml();
+
+ return llvm::make_error<UnimplementedError>();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qXfer(
+ StringExtractorGDBRemote &packet) {
+ SmallVector<StringRef, 5> fields;
+ // The packet format is "qXfer:<object>:<action>:<annex>:offset,length"
+ StringRef(packet.GetStringRef()).split(fields, ':', 4);
+ if (fields.size() != 5)
+ return SendIllFormedResponse(packet, "malformed qXfer packet");
+ StringRef &xfer_object = fields[1];
+ StringRef &xfer_action = fields[2];
+ StringRef &xfer_annex = fields[3];
+ StringExtractor offset_data(fields[4]);
+ if (xfer_action != "read")
+ return SendUnimplementedResponse("qXfer action not supported");
+ // Parse offset.
+ const uint64_t xfer_offset =
+ offset_data.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max());
+ if (xfer_offset == std::numeric_limits<uint64_t>::max())
+ return SendIllFormedResponse(packet, "qXfer packet missing offset");
+ // Parse out comma.
+ if (offset_data.GetChar() != ',')
+ return SendIllFormedResponse(packet,
+ "qXfer packet missing comma after offset");
+ // Parse out the length.
+ const uint64_t xfer_length =
+ offset_data.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max());
+ if (xfer_length == std::numeric_limits<uint64_t>::max())
+ return SendIllFormedResponse(packet, "qXfer packet missing length");
+
+ // Get a previously constructed buffer if it exists or create it now.
+ std::string buffer_key = (xfer_object + xfer_action + xfer_annex).str();
+ auto buffer_it = m_xfer_buffer_map.find(buffer_key);
+ if (buffer_it == m_xfer_buffer_map.end()) {
+ auto buffer_up = ReadXferObject(xfer_object, xfer_annex);
+ if (!buffer_up)
+ return SendErrorResponse(buffer_up.takeError());
+ buffer_it = m_xfer_buffer_map
+ .insert(std::make_pair(buffer_key, std::move(*buffer_up)))
+ .first;
+ }
+
+ // Send back the response
+ StreamGDBRemote response;
+ bool done_with_buffer = false;
+ llvm::StringRef buffer = buffer_it->second->getBuffer();
+ if (xfer_offset >= buffer.size()) {
+ // We have nothing left to send. Mark the buffer as complete.
+ response.PutChar('l');
+ done_with_buffer = true;
+ } else {
+ // Figure out how many bytes are available starting at the given offset.
+ buffer = buffer.drop_front(xfer_offset);
+ // Mark the response type according to whether we're reading the remainder
+ // of the data.
+ if (xfer_length >= buffer.size()) {
+ // There will be nothing left to read after this
+ response.PutChar('l');
+ done_with_buffer = true;
+ } else {
+ // There will still be bytes to read after this request.
+ response.PutChar('m');
+ buffer = buffer.take_front(xfer_length);
+ }
+ // Now write the data in encoded binary form.
+ response.PutEscapedBytes(buffer.data(), buffer.size());
+ }
+
+ if (done_with_buffer)
+ m_xfer_buffer_map.erase(buffer_it);
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ // Move past packet name.
+ packet.SetFilePos(strlen("QSaveRegisterState"));
+
+ // Get the thread to use.
+ NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
+ if (!thread) {
+ if (m_thread_suffix_supported)
+ return SendIllFormedResponse(
+ packet, "No thread specified in QSaveRegisterState packet");
+ else
+ return SendIllFormedResponse(packet,
+ "No thread was is set with the Hg packet");
+ }
+
+ // Grab the register context for the thread.
+ NativeRegisterContext& reg_context = thread->GetRegisterContext();
+
+ // Save registers to a buffer.
+ WritableDataBufferSP register_data_sp;
+ Status error = reg_context.ReadAllRegisterValues(register_data_sp);
+ if (error.Fail()) {
+ LLDB_LOG(log, "pid {0} failed to save all register values: {1}",
+ m_current_process->GetID(), error);
+ return SendErrorResponse(0x75);
+ }
+
+ // Allocate a new save id.
+ const uint32_t save_id = GetNextSavedRegistersID();
+ assert((m_saved_registers_map.find(save_id) == m_saved_registers_map.end()) &&
+ "GetNextRegisterSaveID() returned an existing register save id");
+
+ // Save the register data buffer under the save id.
+ {
+ std::lock_guard<std::mutex> guard(m_saved_registers_mutex);
+ m_saved_registers_map[save_id] = register_data_sp;
+ }
+
+ // Write the response.
+ StreamGDBRemote response;
+ response.Printf("%" PRIu32, save_id);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ // Parse out save id.
+ packet.SetFilePos(strlen("QRestoreRegisterState:"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(
+ packet, "QRestoreRegisterState packet missing register save id");
+
+ const uint32_t save_id = packet.GetU32(0);
+ if (save_id == 0) {
+ LLDB_LOG(log, "QRestoreRegisterState packet has malformed save id, "
+ "expecting decimal uint32_t");
+ return SendErrorResponse(0x76);
+ }
+
+ // Get the thread to use.
+ NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
+ if (!thread) {
+ if (m_thread_suffix_supported)
+ return SendIllFormedResponse(
+ packet, "No thread specified in QRestoreRegisterState packet");
+ else
+ return SendIllFormedResponse(packet,
+ "No thread was is set with the Hg packet");
+ }
+
+ // Grab the register context for the thread.
+ NativeRegisterContext &reg_context = thread->GetRegisterContext();
+
+ // Retrieve register state buffer, then remove from the list.
+ DataBufferSP register_data_sp;
+ {
+ std::lock_guard<std::mutex> guard(m_saved_registers_mutex);
+
+ // Find the register set buffer for the given save id.
+ auto it = m_saved_registers_map.find(save_id);
+ if (it == m_saved_registers_map.end()) {
+ LLDB_LOG(log,
+ "pid {0} does not have a register set save buffer for id {1}",
+ m_current_process->GetID(), save_id);
+ return SendErrorResponse(0x77);
+ }
+ register_data_sp = it->second;
+
+ // Remove it from the map.
+ m_saved_registers_map.erase(it);
+ }
+
+ Status error = reg_context.WriteAllRegisterValues(register_data_sp);
+ if (error.Fail()) {
+ LLDB_LOG(log, "pid {0} failed to restore all register values: {1}",
+ m_current_process->GetID(), error);
+ return SendErrorResponse(0x77);
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vAttach(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ // Consume the ';' after vAttach.
+ packet.SetFilePos(strlen("vAttach"));
+ if (!packet.GetBytesLeft() || packet.GetChar() != ';')
+ return SendIllFormedResponse(packet, "vAttach missing expected ';'");
+
+ // Grab the PID to which we will attach (assume hex encoding).
+ lldb::pid_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16);
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendIllFormedResponse(packet,
+ "vAttach failed to parse the process id");
+
+ // Attempt to attach.
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s attempting to attach to "
+ "pid %" PRIu64,
+ __FUNCTION__, pid);
+
+ Status error = AttachToProcess(pid);
+
+ if (error.Fail()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed to attach to "
+ "pid %" PRIu64 ": %s\n",
+ __FUNCTION__, pid, error.AsCString());
+ return SendErrorResponse(error);
+ }
+
+ // Notify we attached by sending a stop packet.
+ assert(m_current_process);
+ return SendStopReasonForState(*m_current_process,
+ m_current_process->GetState(),
+ /*force_synchronous=*/false);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vAttachWait(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ // Consume the ';' after the identifier.
+ packet.SetFilePos(strlen("vAttachWait"));
+
+ if (!packet.GetBytesLeft() || packet.GetChar() != ';')
+ return SendIllFormedResponse(packet, "vAttachWait missing expected ';'");
+
+ // Allocate the buffer for the process name from vAttachWait.
+ std::string process_name;
+ if (!packet.GetHexByteString(process_name))
+ return SendIllFormedResponse(packet,
+ "vAttachWait failed to parse process name");
+
+ LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
+
+ Status error = AttachWaitProcess(process_name, false);
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
+ error);
+ return SendErrorResponse(error);
+ }
+
+ // Notify we attached by sending a stop packet.
+ assert(m_current_process);
+ return SendStopReasonForState(*m_current_process,
+ m_current_process->GetState(),
+ /*force_synchronous=*/false);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported(
+ StringExtractorGDBRemote &packet) {
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ // Consume the ';' after the identifier.
+ packet.SetFilePos(strlen("vAttachOrWait"));
+
+ if (!packet.GetBytesLeft() || packet.GetChar() != ';')
+ return SendIllFormedResponse(packet, "vAttachOrWait missing expected ';'");
+
+ // Allocate the buffer for the process name from vAttachWait.
+ std::string process_name;
+ if (!packet.GetHexByteString(process_name))
+ return SendIllFormedResponse(packet,
+ "vAttachOrWait failed to parse process name");
+
+ LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
+
+ Status error = AttachWaitProcess(process_name, true);
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
+ error);
+ return SendErrorResponse(error);
+ }
+
+ // Notify we attached by sending a stop packet.
+ assert(m_current_process);
+ return SendStopReasonForState(*m_current_process,
+ m_current_process->GetState(),
+ /*force_synchronous=*/false);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vRun(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ llvm::StringRef s = packet.GetStringRef();
+ if (!s.consume_front("vRun;"))
+ return SendErrorResponse(8);
+
+ llvm::SmallVector<llvm::StringRef, 16> argv;
+ s.split(argv, ';');
+
+ for (llvm::StringRef hex_arg : argv) {
+ StringExtractor arg_ext{hex_arg};
+ std::string arg;
+ arg_ext.GetHexByteString(arg);
+ m_process_launch_info.GetArguments().AppendArgument(arg);
+ LLDB_LOGF(log, "LLGSPacketHandler::%s added arg: \"%s\"", __FUNCTION__,
+ arg.c_str());
+ }
+
+ if (argv.empty())
+ return SendErrorResponse(Status("No arguments"));
+ m_process_launch_info.GetExecutableFile().SetFile(
+ m_process_launch_info.GetArguments()[0].ref(), FileSpec::Style::native);
+ m_process_launch_error = LaunchProcess();
+ if (m_process_launch_error.Fail())
+ return SendErrorResponse(m_process_launch_error);
+ assert(m_current_process);
+ return SendStopReasonForState(*m_current_process,
+ m_current_process->GetState(),
+ /*force_synchronous=*/true);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+ if (!m_non_stop)
+ StopSTDIOForwarding();
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ // Consume the ';' after D.
+ packet.SetFilePos(1);
+ if (packet.GetBytesLeft()) {
+ if (packet.GetChar() != ';')
+ return SendIllFormedResponse(packet, "D missing expected ';'");
+
+ // Grab the PID from which we will detach (assume hex encoding).
+ pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16);
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendIllFormedResponse(packet, "D failed to parse the process id");
+ }
+
+ // Detach forked children if their PID was specified *or* no PID was requested
+ // (i.e. detach-all packet).
+ llvm::Error detach_error = llvm::Error::success();
+ bool detached = false;
+ for (auto it = m_debugged_processes.begin();
+ it != m_debugged_processes.end();) {
+ if (pid == LLDB_INVALID_PROCESS_ID || pid == it->first) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s detaching %" PRId64,
+ __FUNCTION__, it->first);
+ if (llvm::Error e = it->second.process_up->Detach().ToError())
+ detach_error = llvm::joinErrors(std::move(detach_error), std::move(e));
+ else {
+ if (it->second.process_up.get() == m_current_process)
+ m_current_process = nullptr;
+ if (it->second.process_up.get() == m_continue_process)
+ m_continue_process = nullptr;
+ it = m_debugged_processes.erase(it);
+ detached = true;
+ continue;
+ }
+ }
+ ++it;
+ }
+
+ if (detach_error)
+ return SendErrorResponse(std::move(detach_error));
+ if (!detached)
+ return SendErrorResponse(Status("PID %" PRIu64 " not traced", pid));
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(50);
+
+ packet.SetFilePos(strlen("qThreadStopInfo"));
+ const lldb::tid_t tid = packet.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID);
+ if (tid == LLDB_INVALID_THREAD_ID) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, could not "
+ "parse thread id from request \"%s\"",
+ __FUNCTION__, packet.GetStringRef().data());
+ return SendErrorResponse(0x15);
+ }
+ return SendStopReplyPacketForThread(*m_current_process, tid,
+ /*force_synchronous=*/true);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo(
+ StringExtractorGDBRemote &) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
+
+ // Ensure we have a debugged process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(50);
+ LLDB_LOG(log, "preparing packet for pid {0}", m_current_process->GetID());
+
+ StreamString response;
+ const bool threads_with_valid_stop_info_only = false;
+ llvm::Expected<json::Value> threads_info =
+ GetJSONThreadsInfo(*m_current_process, threads_with_valid_stop_info_only);
+ if (!threads_info) {
+ LLDB_LOG_ERROR(log, threads_info.takeError(),
+ "failed to prepare a packet for pid {1}: {0}",
+ m_current_process->GetID());
+ return SendErrorResponse(52);
+ }
+
+ response.AsRawOstream() << *threads_info;
+ StreamGDBRemote escaped_response;
+ escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo(
+ StringExtractorGDBRemote &packet) {
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse(68);
+
+ packet.SetFilePos(strlen("qWatchpointSupportInfo"));
+ if (packet.GetBytesLeft() == 0)
+ return SendOKResponse();
+ if (packet.GetChar() != ':')
+ return SendErrorResponse(67);
+
+ auto hw_debug_cap = m_current_process->GetHardwareDebugSupportInfo();
+
+ StreamGDBRemote response;
+ if (hw_debug_cap == std::nullopt)
+ response.Printf("num:0;");
+ else
+ response.Printf("num:%d;", hw_debug_cap->second);
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress(
+ StringExtractorGDBRemote &packet) {
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse(67);
+
+ packet.SetFilePos(strlen("qFileLoadAddress:"));
+ if (packet.GetBytesLeft() == 0)
+ return SendErrorResponse(68);
+
+ std::string file_name;
+ packet.GetHexByteString(file_name);
+
+ lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS;
+ Status error =
+ m_current_process->GetFileLoadAddress(file_name, file_load_address);
+ if (error.Fail())
+ return SendErrorResponse(69);
+
+ if (file_load_address == LLDB_INVALID_ADDRESS)
+ return SendErrorResponse(1); // File not loaded
+
+ StreamGDBRemote response;
+ response.PutHex64(file_load_address);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QPassSignals(
+ StringExtractorGDBRemote &packet) {
+ std::vector<int> signals;
+ packet.SetFilePos(strlen("QPassSignals:"));
+
+ // Read sequence of hex signal numbers divided by a semicolon and optionally
+ // spaces.
+ while (packet.GetBytesLeft() > 0) {
+ int signal = packet.GetS32(-1, 16);
+ if (signal < 0)
+ return SendIllFormedResponse(packet, "Failed to parse signal number.");
+ signals.push_back(signal);
+
+ packet.SkipSpaces();
+ char separator = packet.GetChar();
+ if (separator == '\0')
+ break; // End of string
+ if (separator != ';')
+ return SendIllFormedResponse(packet, "Invalid separator,"
+ " expected semicolon.");
+ }
+
+ // Fail if we don't have a current process.
+ if (!m_current_process)
+ return SendErrorResponse(68);
+
+ Status error = m_current_process->IgnoreSignals(signals);
+ if (error.Fail())
+ return SendErrorResponse(69);
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qMemTags(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ // Ensure we have a process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(1);
+ }
+
+ // We are expecting
+ // qMemTags:<hex address>,<hex length>:<hex type>
+
+ // Address
+ packet.SetFilePos(strlen("qMemTags:"));
+ const char *current_char = packet.Peek();
+ if (!current_char || *current_char == ',')
+ return SendIllFormedResponse(packet, "Missing address in qMemTags packet");
+ const lldb::addr_t addr = packet.GetHexMaxU64(/*little_endian=*/false, 0);
+
+ // Length
+ char previous_char = packet.GetChar();
+ current_char = packet.Peek();
+ // If we don't have a separator or the length field is empty
+ if (previous_char != ',' || (current_char && *current_char == ':'))
+ return SendIllFormedResponse(packet,
+ "Invalid addr,length pair in qMemTags packet");
+
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(
+ packet, "Too short qMemtags: packet (looking for length)");
+ const size_t length = packet.GetHexMaxU64(/*little_endian=*/false, 0);
+
+ // Type
+ const char *invalid_type_err = "Invalid type field in qMemTags: packet";
+ if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':')
+ return SendIllFormedResponse(packet, invalid_type_err);
+
+ // Type is a signed integer but packed into the packet as its raw bytes.
+ // However, our GetU64 uses strtoull which allows +/-. We do not want this.
+ const char *first_type_char = packet.Peek();
+ if (first_type_char && (*first_type_char == '+' || *first_type_char == '-'))
+ return SendIllFormedResponse(packet, invalid_type_err);
+
+ // Extract type as unsigned then cast to signed.
+ // Using a uint64_t here so that we have some value outside of the 32 bit
+ // range to use as the invalid return value.
+ uint64_t raw_type =
+ packet.GetU64(std::numeric_limits<uint64_t>::max(), /*base=*/16);
+
+ if ( // Make sure the cast below would be valid
+ raw_type > std::numeric_limits<uint32_t>::max() ||
+ // To catch inputs like "123aardvark" that will parse but clearly aren't
+ // valid in this case.
+ packet.GetBytesLeft()) {
+ return SendIllFormedResponse(packet, invalid_type_err);
+ }
+
+ // First narrow to 32 bits otherwise the copy into type would take
+ // the wrong 4 bytes on big endian.
+ uint32_t raw_type_32 = raw_type;
+ int32_t type = reinterpret_cast<int32_t &>(raw_type_32);
+
+ StreamGDBRemote response;
+ std::vector<uint8_t> tags;
+ Status error = m_current_process->ReadMemoryTags(type, addr, length, tags);
+ if (error.Fail())
+ return SendErrorResponse(1);
+
+ // This m is here in case we want to support multi part replies in the future.
+ // In the same manner as qfThreadInfo/qsThreadInfo.
+ response.PutChar('m');
+ response.PutBytesAsRawHex8(tags.data(), tags.size());
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QMemTags(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ // Ensure we have a process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(1);
+ }
+
+ // We are expecting
+ // QMemTags:<hex address>,<hex length>:<hex type>:<tags as hex bytes>
+
+ // Address
+ packet.SetFilePos(strlen("QMemTags:"));
+ const char *current_char = packet.Peek();
+ if (!current_char || *current_char == ',')
+ return SendIllFormedResponse(packet, "Missing address in QMemTags packet");
+ const lldb::addr_t addr = packet.GetHexMaxU64(/*little_endian=*/false, 0);
+
+ // Length
+ char previous_char = packet.GetChar();
+ current_char = packet.Peek();
+ // If we don't have a separator or the length field is empty
+ if (previous_char != ',' || (current_char && *current_char == ':'))
+ return SendIllFormedResponse(packet,
+ "Invalid addr,length pair in QMemTags packet");
+
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(
+ packet, "Too short QMemtags: packet (looking for length)");
+ const size_t length = packet.GetHexMaxU64(/*little_endian=*/false, 0);
+
+ // Type
+ const char *invalid_type_err = "Invalid type field in QMemTags: packet";
+ if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':')
+ return SendIllFormedResponse(packet, invalid_type_err);
+
+ // Our GetU64 uses strtoull which allows leading +/-, we don't want that.
+ const char *first_type_char = packet.Peek();
+ if (first_type_char && (*first_type_char == '+' || *first_type_char == '-'))
+ return SendIllFormedResponse(packet, invalid_type_err);
+
+ // The type is a signed integer but is in the packet as its raw bytes.
+ // So parse first as unsigned then cast to signed later.
+ // We extract to 64 bit, even though we only expect 32, so that we've
+ // got some invalid value we can check for.
+ uint64_t raw_type =
+ packet.GetU64(std::numeric_limits<uint64_t>::max(), /*base=*/16);
+ if (raw_type > std::numeric_limits<uint32_t>::max())
+ return SendIllFormedResponse(packet, invalid_type_err);
+
+ // First narrow to 32 bits. Otherwise the copy below would get the wrong
+ // 4 bytes on big endian.
+ uint32_t raw_type_32 = raw_type;
+ int32_t type = reinterpret_cast<int32_t &>(raw_type_32);
+
+ // Tag data
+ if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':')
+ return SendIllFormedResponse(packet,
+ "Missing tag data in QMemTags: packet");
+
+ // Must be 2 chars per byte
+ const char *invalid_data_err = "Invalid tag data in QMemTags: packet";
+ if (packet.GetBytesLeft() % 2)
+ return SendIllFormedResponse(packet, invalid_data_err);
+
+ // This is bytes here and is unpacked into target specific tags later
+ // We cannot assume that number of bytes == length here because the server
+ // can repeat tags to fill a given range.
+ std::vector<uint8_t> tag_data;
+ // Zero length writes will not have any tag data
+ // (but we pass them on because it will still check that tagging is enabled)
+ if (packet.GetBytesLeft()) {
+ size_t byte_count = packet.GetBytesLeft() / 2;
+ tag_data.resize(byte_count);
+ size_t converted_bytes = packet.GetHexBytes(tag_data, 0);
+ if (converted_bytes != byte_count) {
+ return SendIllFormedResponse(packet, invalid_data_err);
+ }
+ }
+
+ Status status =
+ m_current_process->WriteMemoryTags(type, addr, length, tag_data);
+ return status.Success() ? SendOKResponse() : SendErrorResponse(1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qSaveCore(
+ StringExtractorGDBRemote &packet) {
+ // Fail if we don't have a current process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(Status("Process not running."));
+
+ std::string path_hint;
+
+ StringRef packet_str{packet.GetStringRef()};
+ assert(packet_str.starts_with("qSaveCore"));
+ if (packet_str.consume_front("qSaveCore;")) {
+ for (auto x : llvm::split(packet_str, ';')) {
+ if (x.consume_front("path-hint:"))
+ StringExtractor(x).GetHexByteString(path_hint);
+ else
+ return SendErrorResponse(Status("Unsupported qSaveCore option"));
+ }
+ }
+
+ llvm::Expected<std::string> ret = m_current_process->SaveCore(path_hint);
+ if (!ret)
+ return SendErrorResponse(ret.takeError());
+
+ StreamString response;
+ response.PutCString("core-path:");
+ response.PutStringAsRawHex8(ret.get());
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QNonStop(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ StringRef packet_str{packet.GetStringRef()};
+ assert(packet_str.starts_with("QNonStop:"));
+ packet_str.consume_front("QNonStop:");
+ if (packet_str == "0") {
+ if (m_non_stop)
+ StopSTDIOForwarding();
+ for (auto &process_it : m_debugged_processes) {
+ if (process_it.second.process_up->IsRunning()) {
+ assert(m_non_stop);
+ Status error = process_it.second.process_up->Interrupt();
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "while disabling nonstop, failed to halt process {0}: {1}",
+ process_it.first, error);
+ return SendErrorResponse(0x41);
+ }
+ // we must not send stop reasons after QNonStop
+ m_disabling_non_stop = true;
+ }
+ }
+ m_stdio_notification_queue.clear();
+ m_stop_notification_queue.clear();
+ m_non_stop = false;
+ // If we are stopping anything, defer sending the OK response until we're
+ // done.
+ if (m_disabling_non_stop)
+ return PacketResult::Success;
+ } else if (packet_str == "1") {
+ if (!m_non_stop)
+ StartSTDIOForwarding();
+ m_non_stop = true;
+ } else
+ return SendErrorResponse(Status("Invalid QNonStop packet"));
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::HandleNotificationAck(
+ std::deque<std::string> &queue) {
+ // Per the protocol, the first message put into the queue is sent
+ // immediately. However, it remains the queue until the client ACKs it --
+ // then we pop it and send the next message. The process repeats until
+ // the last message in the queue is ACK-ed, in which case the packet sends
+ // an OK response.
+ if (queue.empty())
+ return SendErrorResponse(Status("No pending notification to ack"));
+ queue.pop_front();
+ if (!queue.empty())
+ return SendPacketNoLock(queue.front());
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vStdio(
+ StringExtractorGDBRemote &packet) {
+ return HandleNotificationAck(m_stdio_notification_queue);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vStopped(
+ StringExtractorGDBRemote &packet) {
+ PacketResult ret = HandleNotificationAck(m_stop_notification_queue);
+ // If this was the last notification and all the processes exited,
+ // terminate the server.
+ if (m_stop_notification_queue.empty() && m_debugged_processes.empty()) {
+ m_exit_now = true;
+ m_mainloop.RequestTermination();
+ }
+ return ret;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vCtrlC(
+ StringExtractorGDBRemote &packet) {
+ if (!m_non_stop)
+ return SendErrorResponse(Status("vCtrl is only valid in non-stop mode"));
+
+ PacketResult interrupt_res = Handle_interrupt(packet);
+ // If interrupting the process failed, pass the result through.
+ if (interrupt_res != PacketResult::Success)
+ return interrupt_res;
+ // Otherwise, vCtrlC should issue an OK response (normal interrupts do not).
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_T(StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(strlen("T"));
+ auto pid_tid = packet.GetPidTid(m_current_process ? m_current_process->GetID()
+ : LLDB_INVALID_PROCESS_ID);
+ if (!pid_tid)
+ return SendErrorResponse(llvm::make_error<StringError>(
+ inconvertibleErrorCode(), "Malformed thread-id"));
+
+ lldb::pid_t pid = pid_tid->first;
+ lldb::tid_t tid = pid_tid->second;
+
+ // Technically, this would also be caught by the PID check but let's be more
+ // explicit about the error.
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse(llvm::make_error<StringError>(
+ inconvertibleErrorCode(), "No current process and no PID provided"));
+
+ // Check the process ID and find respective process instance.
+ auto new_process_it = m_debugged_processes.find(pid);
+ if (new_process_it == m_debugged_processes.end())
+ return SendErrorResponse(1);
+
+ // Check the thread ID
+ if (!new_process_it->second.process_up->GetThreadByID(tid))
+ return SendErrorResponse(2);
+
+ return SendOKResponse();
+}
+
+void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() {
+ Log *log = GetLog(LLDBLog::Process);
+
+ // Tell the stdio connection to shut down.
+ if (m_stdio_communication.IsConnected()) {
+ auto connection = m_stdio_communication.GetConnection();
+ if (connection) {
+ Status error;
+ connection->Disconnect(&error);
+
+ if (error.Success()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s disconnect process "
+ "terminal stdio - SUCCESS",
+ __FUNCTION__);
+ } else {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s disconnect process "
+ "terminal stdio - FAIL: %s",
+ __FUNCTION__, error.AsCString());
+ }
+ }
+ }
+}
+
+NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix(
+ StringExtractorGDBRemote &packet) {
+ // We have no thread if we don't have a process.
+ if (!m_current_process ||
+ m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)
+ return nullptr;
+
+ // If the client hasn't asked for thread suffix support, there will not be a
+ // thread suffix. Use the current thread in that case.
+ if (!m_thread_suffix_supported) {
+ const lldb::tid_t current_tid = GetCurrentThreadID();
+ if (current_tid == LLDB_INVALID_THREAD_ID)
+ return nullptr;
+ else if (current_tid == 0) {
+ // Pick a thread.
+ return m_current_process->GetThreadAtIndex(0);
+ } else
+ return m_current_process->GetThreadByID(current_tid);
+ }
+
+ Log *log = GetLog(LLDBLog::Thread);
+
+ // Parse out the ';'.
+ if (packet.GetBytesLeft() < 1 || packet.GetChar() != ';') {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s gdb-remote parse "
+ "error: expected ';' prior to start of thread suffix: packet "
+ "contents = '%s'",
+ __FUNCTION__, packet.GetStringRef().data());
+ return nullptr;
+ }
+
+ if (!packet.GetBytesLeft())
+ return nullptr;
+
+ // Parse out thread: portion.
+ if (strncmp(packet.Peek(), "thread:", strlen("thread:")) != 0) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s gdb-remote parse "
+ "error: expected 'thread:' but not found, packet contents = "
+ "'%s'",
+ __FUNCTION__, packet.GetStringRef().data());
+ return nullptr;
+ }
+ packet.SetFilePos(packet.GetFilePos() + strlen("thread:"));
+ const lldb::tid_t tid = packet.GetHexMaxU64(false, 0);
+ if (tid != 0)
+ return m_current_process->GetThreadByID(tid);
+
+ return nullptr;
+}
+
+lldb::tid_t GDBRemoteCommunicationServerLLGS::GetCurrentThreadID() const {
+ if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) {
+ // Use whatever the debug process says is the current thread id since the
+ // protocol either didn't specify or specified we want any/all threads
+ // marked as the current thread.
+ if (!m_current_process)
+ return LLDB_INVALID_THREAD_ID;
+ return m_current_process->GetCurrentThreadID();
+ }
+ // Use the specific current thread id set by the gdb remote protocol.
+ return m_current_tid;
+}
+
+uint32_t GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID() {
+ std::lock_guard<std::mutex> guard(m_saved_registers_mutex);
+ return m_next_saved_registers_id++;
+}
+
+void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() {
+ Log *log = GetLog(LLDBLog::Process);
+
+ LLDB_LOG(log, "clearing {0} xfer buffers", m_xfer_buffer_map.size());
+ m_xfer_buffer_map.clear();
+}
+
+FileSpec
+GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path,
+ const ArchSpec &arch) {
+ if (m_current_process) {
+ FileSpec file_spec;
+ if (m_current_process
+ ->GetLoadedModuleFileSpec(module_path.c_str(), file_spec)
+ .Success()) {
+ if (FileSystem::Instance().Exists(file_spec))
+ return file_spec;
+ }
+ }
+
+ return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch);
+}
+
+std::string GDBRemoteCommunicationServerLLGS::XMLEncodeAttributeValue(
+ llvm::StringRef value) {
+ std::string result;
+ for (const char &c : value) {
+ switch (c) {
+ case '\'':
+ result += "&apos;";
+ break;
+ case '"':
+ result += "&quot;";
+ break;
+ case '<':
+ result += "&lt;";
+ break;
+ case '>':
+ result += "&gt;";
+ break;
+ default:
+ result += c;
+ break;
+ }
+ }
+ return result;
+}
+
+std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures(
+ const llvm::ArrayRef<llvm::StringRef> client_features) {
+ std::vector<std::string> ret =
+ GDBRemoteCommunicationServerCommon::HandleFeatures(client_features);
+ ret.insert(ret.end(), {
+ "QThreadSuffixSupported+",
+ "QListThreadsInStopReply+",
+ "qXfer:features:read+",
+ "QNonStop+",
+ });
+
+ // report server-only features
+ using Extension = NativeProcessProtocol::Extension;
+ Extension plugin_features = m_process_manager.GetSupportedExtensions();
+ if (bool(plugin_features & Extension::pass_signals))
+ ret.push_back("QPassSignals+");
+ if (bool(plugin_features & Extension::auxv))
+ ret.push_back("qXfer:auxv:read+");
+ if (bool(plugin_features & Extension::libraries_svr4))
+ ret.push_back("qXfer:libraries-svr4:read+");
+ if (bool(plugin_features & Extension::siginfo_read))
+ ret.push_back("qXfer:siginfo:read+");
+ if (bool(plugin_features & Extension::memory_tagging))
+ ret.push_back("memory-tagging+");
+ if (bool(plugin_features & Extension::savecore))
+ ret.push_back("qSaveCore+");
+
+ // check for client features
+ m_extensions_supported = {};
+ for (llvm::StringRef x : client_features)
+ m_extensions_supported |=
+ llvm::StringSwitch<Extension>(x)
+ .Case("multiprocess+", Extension::multiprocess)
+ .Case("fork-events+", Extension::fork)
+ .Case("vfork-events+", Extension::vfork)
+ .Default({});
+
+ m_extensions_supported &= plugin_features;
+
+ // fork & vfork require multiprocess
+ if (!bool(m_extensions_supported & Extension::multiprocess))
+ m_extensions_supported &= ~(Extension::fork | Extension::vfork);
+
+ // report only if actually supported
+ if (bool(m_extensions_supported & Extension::multiprocess))
+ ret.push_back("multiprocess+");
+ if (bool(m_extensions_supported & Extension::fork))
+ ret.push_back("fork-events+");
+ if (bool(m_extensions_supported & Extension::vfork))
+ ret.push_back("vfork-events+");
+
+ for (auto &x : m_debugged_processes)
+ SetEnabledExtensions(*x.second.process_up);
+ return ret;
+}
+
+void GDBRemoteCommunicationServerLLGS::SetEnabledExtensions(
+ NativeProcessProtocol &process) {
+ NativeProcessProtocol::Extension flags = m_extensions_supported;
+ assert(!bool(flags & ~m_process_manager.GetSupportedExtensions()));
+ process.SetEnabledExtensions(flags);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendContinueSuccessResponse() {
+ if (m_non_stop)
+ return SendOKResponse();
+ StartSTDIOForwarding();
+ return PacketResult::Success;
+}
+
+void GDBRemoteCommunicationServerLLGS::AppendThreadIDToResponse(
+ Stream &response, lldb::pid_t pid, lldb::tid_t tid) {
+ if (bool(m_extensions_supported &
+ NativeProcessProtocol::Extension::multiprocess))
+ response.Format("p{0:x-}.", pid);
+ response.Format("{0:x-}", tid);
+}
+
+std::string
+lldb_private::process_gdb_remote::LLGSArgToURL(llvm::StringRef url_arg,
+ bool reverse_connect) {
+ // Try parsing the argument as URL.
+ if (std::optional<URI> url = URI::Parse(url_arg)) {
+ if (reverse_connect)
+ return url_arg.str();
+
+ // Translate the scheme from LLGS notation to ConnectionFileDescriptor.
+ // If the scheme doesn't match any, pass it through to support using CFD
+ // schemes directly.
+ std::string new_url = llvm::StringSwitch<std::string>(url->scheme)
+ .Case("tcp", "listen")
+ .Case("unix", "unix-accept")
+ .Case("unix-abstract", "unix-abstract-accept")
+ .Default(url->scheme.str());
+ llvm::append_range(new_url, url_arg.substr(url->scheme.size()));
+ return new_url;
+ }
+
+ std::string host_port = url_arg.str();
+ // If host_and_port starts with ':', default the host to be "localhost" and
+ // expect the remainder to be the port.
+ if (url_arg.starts_with(":"))
+ host_port.insert(0, "localhost");
+
+ // Try parsing the (preprocessed) argument as host:port pair.
+ if (!llvm::errorToBool(Socket::DecodeHostAndPort(host_port).takeError()))
+ return (reverse_connect ? "connect://" : "listen://") + host_port;
+
+ // If none of the above applied, interpret the argument as UNIX socket path.
+ return (reverse_connect ? "unix-connect://" : "unix-accept://") +
+ url_arg.str();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
new file mode 100644
index 000000000000..646b6a102abf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -0,0 +1,342 @@
+//===-- GDBRemoteCommunicationServerLLGS.h ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERLLGS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERLLGS_H
+
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "lldb/Core/Communication.h"
+#include "lldb/Host/MainLoop.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/lldb-private-forward.h"
+
+#include "GDBRemoteCommunicationServerCommon.h"
+
+class StringExtractorGDBRemote;
+
+namespace lldb_private {
+
+namespace process_gdb_remote {
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunicationServerLLGS
+ : public GDBRemoteCommunicationServerCommon,
+ public NativeProcessProtocol::NativeDelegate {
+public:
+ // Constructors and Destructors
+ GDBRemoteCommunicationServerLLGS(
+ MainLoop &mainloop,
+ NativeProcessProtocol::Manager &process_manager);
+
+ void SetLaunchInfo(const ProcessLaunchInfo &info);
+
+ /// Launch a process with the current launch settings.
+ ///
+ /// This method supports running an lldb-gdbserver or similar
+ /// server in a situation where the startup code has been provided
+ /// with all the information for a child process to be launched.
+ ///
+ /// \return
+ /// An Status object indicating the success or failure of the
+ /// launch.
+ Status LaunchProcess() override;
+
+ /// Attach to a process.
+ ///
+ /// This method supports attaching llgs to a process accessible via the
+ /// configured Platform.
+ ///
+ /// \return
+ /// An Status object indicating the success or failure of the
+ /// attach operation.
+ Status AttachToProcess(lldb::pid_t pid);
+
+ /// Wait to attach to a process with a given name.
+ ///
+ /// This method supports waiting for the next instance of a process
+ /// with a given name and attaching llgs to that via the configured
+ /// Platform.
+ ///
+ /// \return
+ /// An Status object indicating the success or failure of the
+ /// attach operation.
+ Status AttachWaitProcess(llvm::StringRef process_name, bool include_existing);
+
+ // NativeProcessProtocol::NativeDelegate overrides
+ void InitializeDelegate(NativeProcessProtocol *process) override;
+
+ void ProcessStateChanged(NativeProcessProtocol *process,
+ lldb::StateType state) override;
+
+ void DidExec(NativeProcessProtocol *process) override;
+
+ void
+ NewSubprocess(NativeProcessProtocol *parent_process,
+ std::unique_ptr<NativeProcessProtocol> child_process) override;
+
+ Status InitializeConnection(std::unique_ptr<Connection> connection);
+
+ struct DebuggedProcess {
+ enum class Flag {
+ vkilled = (1u << 0),
+
+ LLVM_MARK_AS_BITMASK_ENUM(vkilled)
+ };
+
+ std::unique_ptr<NativeProcessProtocol> process_up;
+ Flag flags;
+ };
+
+protected:
+ MainLoop &m_mainloop;
+ MainLoop::ReadHandleUP m_network_handle_up;
+ NativeProcessProtocol::Manager &m_process_manager;
+ lldb::tid_t m_current_tid = LLDB_INVALID_THREAD_ID;
+ lldb::tid_t m_continue_tid = LLDB_INVALID_THREAD_ID;
+ NativeProcessProtocol *m_current_process;
+ NativeProcessProtocol *m_continue_process;
+ std::recursive_mutex m_debugged_process_mutex;
+ std::unordered_map<lldb::pid_t, DebuggedProcess> m_debugged_processes;
+
+ Communication m_stdio_communication;
+ MainLoop::ReadHandleUP m_stdio_handle_up;
+
+ llvm::StringMap<std::unique_ptr<llvm::MemoryBuffer>> m_xfer_buffer_map;
+ std::mutex m_saved_registers_mutex;
+ std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map;
+ uint32_t m_next_saved_registers_id = 1;
+ bool m_thread_suffix_supported = false;
+ bool m_list_threads_in_stop_reply = false;
+ bool m_non_stop = false;
+ bool m_disabling_non_stop = false;
+ std::deque<std::string> m_stdio_notification_queue;
+ std::deque<std::string> m_stop_notification_queue;
+
+ NativeProcessProtocol::Extension m_extensions_supported = {};
+
+ // Typically we would use a SmallVector for this data but in this context we
+ // don't know how much data we're recieving so we would have to heap allocate
+ // a lot, or have a very large stack frame. So it's a member instead.
+ uint8_t m_reg_bytes[RegisterValue::kMaxRegisterByteSize];
+
+ PacketResult SendONotification(const char *buffer, uint32_t len);
+
+ PacketResult SendWResponse(NativeProcessProtocol *process);
+
+ StreamString PrepareStopReplyPacketForThread(NativeThreadProtocol &thread);
+
+ PacketResult SendStopReplyPacketForThread(NativeProcessProtocol &process,
+ lldb::tid_t tid,
+ bool force_synchronous);
+
+ PacketResult SendStopReasonForState(NativeProcessProtocol &process,
+ lldb::StateType process_state,
+ bool force_synchronous);
+
+ void EnqueueStopReplyPackets(lldb::tid_t thread_to_skip);
+
+ PacketResult Handle_k(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vKill(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qC(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QSetDisableASLR(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QSetWorkingDir(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QThreadSuffixSupported(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QListThreadsInStopReply(StringExtractorGDBRemote &packet);
+
+ PacketResult ResumeProcess(NativeProcessProtocol &process,
+ const ResumeActionList &actions);
+
+ PacketResult Handle_C(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_c(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vCont(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vCont_actions(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_stop_reason(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qRegisterInfo(StringExtractorGDBRemote &packet);
+
+ void AddProcessThreads(StreamGDBRemote &response,
+ NativeProcessProtocol &process, bool &had_any);
+
+ PacketResult Handle_qfThreadInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qsThreadInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_p(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_P(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_H(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_I(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_interrupt(StringExtractorGDBRemote &packet);
+
+ // Handles $m and $x packets.
+ PacketResult Handle_memory_read(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_M(StringExtractorGDBRemote &packet);
+ PacketResult Handle__M(StringExtractorGDBRemote &packet);
+ PacketResult Handle__m(StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qMemoryRegionInfoSupported(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qMemoryRegionInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_Z(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_z(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_s(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qXfer(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jLLDBTraceSupported(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jLLDBTraceStart(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jLLDBTraceStop(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jLLDBTraceGetState(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jLLDBTraceGetBinaryData(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vAttachWait(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qVAttachOrWaitSupported(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vAttachOrWait(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vRun(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_D(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jThreadsInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qWatchpointSupportInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qFileLoadAddress(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QPassSignals(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qSaveCore(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QNonStop(StringExtractorGDBRemote &packet);
+
+ PacketResult HandleNotificationAck(std::deque<std::string> &queue);
+
+ PacketResult Handle_vStdio(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vStopped(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vCtrlC(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_g(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qMemTags(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QMemTags(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_T(StringExtractorGDBRemote &packet);
+
+ void SetCurrentThreadID(lldb::tid_t tid);
+
+ lldb::tid_t GetCurrentThreadID() const;
+
+ void SetContinueThreadID(lldb::tid_t tid);
+
+ lldb::tid_t GetContinueThreadID() const { return m_continue_tid; }
+
+ Status SetSTDIOFileDescriptor(int fd);
+
+ FileSpec FindModuleFile(const std::string &module_path,
+ const ArchSpec &arch) override;
+
+ llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+ ReadXferObject(llvm::StringRef object, llvm::StringRef annex);
+
+ static std::string XMLEncodeAttributeValue(llvm::StringRef value);
+
+ std::vector<std::string> HandleFeatures(
+ const llvm::ArrayRef<llvm::StringRef> client_features) override;
+
+ // Provide a response for successful continue action, i.e. send "OK"
+ // in non-stop mode, no response otherwise.
+ PacketResult SendContinueSuccessResponse();
+
+ void AppendThreadIDToResponse(Stream &response, lldb::pid_t pid,
+ lldb::tid_t tid);
+
+private:
+ llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> BuildTargetXml();
+
+ void HandleInferiorState_Exited(NativeProcessProtocol *process);
+
+ void HandleInferiorState_Stopped(NativeProcessProtocol *process);
+
+ NativeThreadProtocol *GetThreadFromSuffix(StringExtractorGDBRemote &packet);
+
+ uint32_t GetNextSavedRegistersID();
+
+ void MaybeCloseInferiorTerminalConnection();
+
+ void ClearProcessSpecificData();
+
+ void RegisterPacketHandlers();
+
+ void DataAvailableCallback();
+
+ void SendProcessOutput();
+
+ void StartSTDIOForwarding();
+
+ void StopSTDIOForwarding();
+
+ // Call SetEnabledExtensions() with appropriate flags on the process.
+ void SetEnabledExtensions(NativeProcessProtocol &process);
+
+ // For GDBRemoteCommunicationServerLLGS only
+ GDBRemoteCommunicationServerLLGS(const GDBRemoteCommunicationServerLLGS &) =
+ delete;
+ const GDBRemoteCommunicationServerLLGS &
+ operator=(const GDBRemoteCommunicationServerLLGS &) = delete;
+};
+
+std::string LLGSArgToURL(llvm::StringRef url_arg, bool reverse_connect);
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERLLGS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
new file mode 100644
index 000000000000..65f1cc12ba30
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
@@ -0,0 +1,606 @@
+//===-- GDBRemoteCommunicationServerPlatform.cpp --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteCommunicationServerPlatform.h"
+
+#include <cerrno>
+
+#include <chrono>
+#include <csignal>
+#include <cstring>
+#include <mutex>
+#include <optional>
+#include <sstream>
+#include <thread>
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/Threading.h"
+
+#include "lldb/Host/Config.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/FileAction.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/GDBRemote.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/TildeExpressionResolver.h"
+#include "lldb/Utility/UriParser.h"
+
+#include "lldb/Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private;
+
+GDBRemoteCommunicationServerPlatform::PortMap::PortMap(uint16_t min_port,
+ uint16_t max_port) {
+ assert(min_port);
+ for (; min_port < max_port; ++min_port)
+ m_port_map[min_port] = LLDB_INVALID_PROCESS_ID;
+}
+
+void GDBRemoteCommunicationServerPlatform::PortMap::AllowPort(uint16_t port) {
+ assert(port);
+ // Do not modify existing mappings
+ m_port_map.insert({port, LLDB_INVALID_PROCESS_ID});
+}
+
+llvm::Expected<uint16_t>
+GDBRemoteCommunicationServerPlatform::PortMap::GetNextAvailablePort() {
+ if (m_port_map.empty())
+ return 0; // Bind to port zero and get a port, we didn't have any
+ // limitations
+
+ for (auto &pair : m_port_map) {
+ if (pair.second == LLDB_INVALID_PROCESS_ID) {
+ pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
+ return pair.first;
+ }
+ }
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No free port found in port map");
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::AssociatePortWithProcess(
+ uint16_t port, lldb::pid_t pid) {
+ auto pos = m_port_map.find(port);
+ if (pos != m_port_map.end()) {
+ pos->second = pid;
+ return true;
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::FreePort(uint16_t port) {
+ std::map<uint16_t, lldb::pid_t>::iterator pos = m_port_map.find(port);
+ if (pos != m_port_map.end()) {
+ pos->second = LLDB_INVALID_PROCESS_ID;
+ return true;
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::FreePortForProcess(
+ lldb::pid_t pid) {
+ if (!m_port_map.empty()) {
+ for (auto &pair : m_port_map) {
+ if (pair.second == pid) {
+ pair.second = LLDB_INVALID_PROCESS_ID;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::empty() const {
+ return m_port_map.empty();
+}
+
+// GDBRemoteCommunicationServerPlatform constructor
+GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
+ const Socket::SocketProtocol socket_protocol, const char *socket_scheme)
+ : GDBRemoteCommunicationServerCommon(),
+ m_socket_protocol(socket_protocol), m_socket_scheme(socket_scheme),
+ m_spawned_pids_mutex(), m_port_map(), m_port_offset(0) {
+ m_pending_gdb_server.pid = LLDB_INVALID_PROCESS_ID;
+ m_pending_gdb_server.port = 0;
+
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qC,
+ &GDBRemoteCommunicationServerPlatform::Handle_qC);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
+ &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer,
+ &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer,
+ &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess,
+ &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
+ &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qPathComplete,
+ &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
+ &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jSignalsInfo,
+ &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo);
+
+ RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
+ [](StringExtractorGDBRemote packet, Status &error,
+ bool &interrupt, bool &quit) {
+ error.SetErrorString("interrupt received");
+ interrupt = true;
+ return PacketResult::Success;
+ });
+}
+
+// Destructor
+GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() =
+ default;
+
+Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
+ const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid,
+ std::optional<uint16_t> &port, std::string &socket_name) {
+ if (!port) {
+ llvm::Expected<uint16_t> available_port = m_port_map.GetNextAvailablePort();
+ if (available_port)
+ port = *available_port;
+ else
+ return Status(available_port.takeError());
+ }
+
+ // Spawn a new thread to accept the port that gets bound after binding to
+ // port 0 (zero).
+
+ // ignore the hostname send from the remote end, just use the ip address that
+ // we're currently communicating with as the hostname
+
+ // Spawn a debugserver and try to get the port it listens to.
+ ProcessLaunchInfo debugserver_launch_info;
+ if (hostname.empty())
+ hostname = "127.0.0.1";
+
+ Log *log = GetLog(LLDBLog::Platform);
+ LLDB_LOGF(log, "Launching debugserver with: %s:%u...", hostname.c_str(),
+ *port);
+
+ // Do not run in a new session so that it can not linger after the platform
+ // closes.
+ debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
+ debugserver_launch_info.SetMonitorProcessCallback(
+ std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped,
+ this, std::placeholders::_1));
+
+ std::ostringstream url;
+// debugserver does not accept the URL scheme prefix.
+#if !defined(__APPLE__)
+ url << m_socket_scheme << "://";
+#endif
+ uint16_t *port_ptr = &*port;
+ if (m_socket_protocol == Socket::ProtocolTcp) {
+ std::string platform_uri = GetConnection()->GetURI();
+ std::optional<URI> parsed_uri = URI::Parse(platform_uri);
+ url << '[' << parsed_uri->hostname.str() << "]:" << *port;
+ } else {
+ socket_name = GetDomainSocketPath("gdbserver").GetPath();
+ url << socket_name;
+ port_ptr = nullptr;
+ }
+
+ Status error = StartDebugserverProcess(
+ url.str().c_str(), nullptr, debugserver_launch_info, port_ptr, &args, -1);
+
+ pid = debugserver_launch_info.GetProcessID();
+ if (pid != LLDB_INVALID_PROCESS_ID) {
+ std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
+ m_spawned_pids.insert(pid);
+ if (*port > 0)
+ m_port_map.AssociatePortWithProcess(*port, pid);
+ } else {
+ if (*port > 0)
+ m_port_map.FreePort(*port);
+ }
+ return error;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
+ StringExtractorGDBRemote &packet) {
+ // Spawn a local debugserver as a platform so we can then attach or launch a
+ // process...
+
+ Log *log = GetLog(LLDBLog::Platform);
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerPlatform::%s() called",
+ __FUNCTION__);
+
+ ConnectionFileDescriptor file_conn;
+ std::string hostname;
+ packet.SetFilePos(::strlen("qLaunchGDBServer;"));
+ llvm::StringRef name;
+ llvm::StringRef value;
+ std::optional<uint16_t> port;
+ while (packet.GetNameColonValue(name, value)) {
+ if (name == "host")
+ hostname = std::string(value);
+ else if (name == "port") {
+ // Make the Optional valid so we can use its value
+ port = 0;
+ value.getAsInteger(0, *port);
+ }
+ }
+
+ lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ std::string socket_name;
+ Status error =
+ LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name);
+ if (error.Fail()) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerPlatform::%s() debugserver "
+ "launch failed: %s",
+ __FUNCTION__, error.AsCString());
+ return SendErrorResponse(9);
+ }
+
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerPlatform::%s() debugserver "
+ "launched successfully as pid %" PRIu64,
+ __FUNCTION__, debugserver_pid);
+
+ StreamGDBRemote response;
+ assert(port);
+ response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid,
+ *port + m_port_offset);
+ if (!socket_name.empty()) {
+ response.PutCString("socket_name:");
+ response.PutStringAsRawHex8(socket_name);
+ response.PutChar(';');
+ }
+
+ PacketResult packet_result = SendPacketNoLock(response.GetString());
+ if (packet_result != PacketResult::Success) {
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ Host::Kill(debugserver_pid, SIGINT);
+ }
+ return packet_result;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer(
+ StringExtractorGDBRemote &packet) {
+ namespace json = llvm::json;
+
+ if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse(4);
+
+ json::Object server{{"port", m_pending_gdb_server.port}};
+
+ if (!m_pending_gdb_server.socket_name.empty())
+ server.try_emplace("socket_name", m_pending_gdb_server.socket_name);
+
+ json::Array server_list;
+ server_list.push_back(std::move(server));
+
+ StreamGDBRemote response;
+ response.AsRawOstream() << std::move(server_list);
+
+ StreamGDBRemote escaped_response;
+ escaped_response.PutEscapedBytes(response.GetString().data(),
+ response.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("qKillSpawnedProcess:"));
+
+ lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+
+ // verify that we know anything about this pid. Scope for locker
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end()) {
+ // not a pid we know about
+ return SendErrorResponse(10);
+ }
+ }
+
+ // go ahead and attempt to kill the spawned process
+ if (KillSpawnedProcess(pid))
+ return SendOKResponse();
+ else
+ return SendErrorResponse(11);
+}
+
+bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) {
+ // make sure we know about this process
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return false;
+ }
+
+ // first try a SIGTERM (standard kill)
+ Host::Kill(pid, SIGTERM);
+
+ // check if that worked
+ for (size_t i = 0; i < 10; ++i) {
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end()) {
+ // it is now killed
+ return true;
+ }
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+
+ // the launched process still lives. Now try killing it again, this time
+ // with an unblockable signal.
+ Host::Kill(pid, SIGKILL);
+
+ for (size_t i = 0; i < 10; ++i) {
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end()) {
+ // it is now killed
+ return true;
+ }
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+
+ // check one more time after the final sleep
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+
+ // no luck - the process still lives
+ return false;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo(
+ StringExtractorGDBRemote &packet) {
+ lldb::pid_t pid = m_process_launch_info.GetProcessID();
+ m_process_launch_info.Clear();
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse(1);
+
+ ProcessInstanceInfo proc_info;
+ if (!Host::GetProcessInfo(pid, proc_info))
+ return SendErrorResponse(1);
+
+ StreamString response;
+ CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qPathComplete(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("qPathComplete:"));
+ const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1);
+ if (packet.GetChar() != ',')
+ return SendErrorResponse(85);
+ std::string path;
+ packet.GetHexByteString(path);
+
+ StringList matches;
+ StandardTildeExpressionResolver resolver;
+ if (only_dir)
+ CommandCompletions::DiskDirectories(path, matches, resolver);
+ else
+ CommandCompletions::DiskFiles(path, matches, resolver);
+
+ StreamString response;
+ response.PutChar('M');
+ llvm::StringRef separator;
+ std::sort(matches.begin(), matches.end());
+ for (const auto &match : matches) {
+ response << separator;
+ separator = ",";
+ // encode result strings into hex bytes to avoid unexpected error caused by
+ // special characters like '$'.
+ response.PutStringAsRawHex8(match.c_str());
+ }
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir(
+ StringExtractorGDBRemote &packet) {
+
+ llvm::SmallString<64> cwd;
+ if (std::error_code ec = llvm::sys::fs::current_path(cwd))
+ return SendErrorResponse(ec.value());
+
+ StreamString response;
+ response.PutBytesAsRawHex8(cwd.data(), cwd.size());
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("QSetWorkingDir:"));
+ std::string path;
+ packet.GetHexByteString(path);
+
+ if (std::error_code ec = llvm::sys::fs::set_current_path(path))
+ return SendErrorResponse(ec.value());
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qC(
+ StringExtractorGDBRemote &packet) {
+ // NOTE: lldb should now be using qProcessInfo for process IDs. This path
+ // here
+ // should not be used. It is reporting process id instead of thread id. The
+ // correct answer doesn't seem to make much sense for lldb-platform.
+ // CONSIDER: flip to "unsupported".
+ lldb::pid_t pid = m_process_launch_info.GetProcessID();
+
+ StreamString response;
+ response.Printf("QC%" PRIx64, pid);
+
+ // If we launch a process and this GDB server is acting as a platform, then
+ // we need to clear the process launch state so we can start launching
+ // another process. In order to launch a process a bunch or packets need to
+ // be sent: environment packets, working directory, disable ASLR, and many
+ // more settings. When we launch a process we then need to know when to clear
+ // this information. Currently we are selecting the 'qC' packet as that
+ // packet which seems to make the most sense.
+ if (pid != LLDB_INVALID_PROCESS_ID) {
+ m_process_launch_info.Clear();
+ }
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(
+ StringExtractorGDBRemote &packet) {
+ StructuredData::Array signal_array;
+
+ lldb::UnixSignalsSP signals = UnixSignals::CreateForHost();
+ for (auto signo = signals->GetFirstSignalNumber();
+ signo != LLDB_INVALID_SIGNAL_NUMBER;
+ signo = signals->GetNextSignalNumber(signo)) {
+ auto dictionary = std::make_shared<StructuredData::Dictionary>();
+
+ dictionary->AddIntegerItem("signo", signo);
+ dictionary->AddStringItem("name", signals->GetSignalAsStringRef(signo));
+
+ bool suppress, stop, notify;
+ signals->GetSignalInfo(signo, suppress, stop, notify);
+ dictionary->AddBooleanItem("suppress", suppress);
+ dictionary->AddBooleanItem("stop", stop);
+ dictionary->AddBooleanItem("notify", notify);
+
+ signal_array.Push(dictionary);
+ }
+
+ StreamString response;
+ signal_array.Dump(response);
+ return SendPacketNoLock(response.GetString());
+}
+
+void GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped(
+ lldb::pid_t pid) {
+ std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
+ m_port_map.FreePortForProcess(pid);
+ m_spawned_pids.erase(pid);
+}
+
+Status GDBRemoteCommunicationServerPlatform::LaunchProcess() {
+ if (!m_process_launch_info.GetArguments().GetArgumentCount())
+ return Status("%s: no process command line specified to launch",
+ __FUNCTION__);
+
+ // specify the process monitor if not already set. This should generally be
+ // what happens since we need to reap started processes.
+ if (!m_process_launch_info.GetMonitorProcessCallback())
+ m_process_launch_info.SetMonitorProcessCallback(std::bind(
+ &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, this,
+ std::placeholders::_1));
+
+ Status error = Host::LaunchProcess(m_process_launch_info);
+ if (!error.Success()) {
+ fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__,
+ m_process_launch_info.GetArguments().GetArgumentAtIndex(0));
+ return error;
+ }
+
+ printf("Launched '%s' as process %" PRIu64 "...\n",
+ m_process_launch_info.GetArguments().GetArgumentAtIndex(0),
+ m_process_launch_info.GetProcessID());
+
+ // add to list of spawned processes. On an lldb-gdbserver, we would expect
+ // there to be only one.
+ const auto pid = m_process_launch_info.GetProcessID();
+ if (pid != LLDB_INVALID_PROCESS_ID) {
+ // add to spawned pids
+ std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
+ m_spawned_pids.insert(pid);
+ }
+
+ return error;
+}
+
+void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) {
+ m_port_map = std::move(port_map);
+}
+
+const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() {
+ static FileSpec g_domainsocket_dir;
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ const char *domainsocket_dir_env =
+ ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR");
+ if (domainsocket_dir_env != nullptr)
+ g_domainsocket_dir = FileSpec(domainsocket_dir_env);
+ else
+ g_domainsocket_dir = HostInfo::GetProcessTempDir();
+ });
+
+ return g_domainsocket_dir;
+}
+
+FileSpec
+GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) {
+ llvm::SmallString<128> socket_path;
+ llvm::SmallString<128> socket_name(
+ (llvm::StringRef(prefix) + ".%%%%%%").str());
+
+ FileSpec socket_path_spec(GetDomainSocketDir());
+ socket_path_spec.AppendPathComponent(socket_name.c_str());
+
+ llvm::sys::fs::createUniqueFile(socket_path_spec.GetPath().c_str(),
+ socket_path);
+ return FileSpec(socket_path.c_str());
+}
+
+void GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) {
+ m_port_offset = port_offset;
+}
+
+void GDBRemoteCommunicationServerPlatform::SetPendingGdbServer(
+ lldb::pid_t pid, uint16_t port, const std::string &socket_name) {
+ m_pending_gdb_server.pid = pid;
+ m_pending_gdb_server.port = port;
+ m_pending_gdb_server.socket_name = socket_name;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
new file mode 100644
index 000000000000..1853025466cf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
@@ -0,0 +1,149 @@
+//===-- GDBRemoteCommunicationServerPlatform.h ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H
+
+#include <map>
+#include <mutex>
+#include <optional>
+#include <set>
+
+#include "GDBRemoteCommunicationServerCommon.h"
+#include "lldb/Host/Socket.h"
+
+#include "llvm/Support/Error.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class GDBRemoteCommunicationServerPlatform
+ : public GDBRemoteCommunicationServerCommon {
+public:
+ class PortMap {
+ public:
+ // This class is used to restrict the range of ports that
+ // platform created debugserver/gdbserver processes will
+ // communicate on.
+
+ // Construct an empty map, where empty means any port is allowed.
+ PortMap() = default;
+
+ // Make a port map with a range of free ports
+ // from min_port to max_port-1.
+ PortMap(uint16_t min_port, uint16_t max_port);
+
+ // Add a port to the map. If it is already in the map do not modify
+ // its mapping. (used ports remain used, new ports start as free)
+ void AllowPort(uint16_t port);
+
+ // If we are using a port map where we can only use certain ports,
+ // get the next available port.
+ //
+ // If we are using a port map and we are out of ports, return an error.
+ //
+ // If we aren't using a port map, return 0 to indicate we should bind to
+ // port 0 and then figure out which port we used.
+ llvm::Expected<uint16_t> GetNextAvailablePort();
+
+ // Tie a port to a process ID. Returns false if the port is not in the port
+ // map. If the port is already in use it will be moved to the given pid.
+ // FIXME: This is and GetNextAvailablePort make create a race condition if
+ // the portmap is shared between processes.
+ bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid);
+
+ // Free the given port. Returns false if the port is not in the map.
+ bool FreePort(uint16_t port);
+
+ // Free the port associated with the given pid. Returns false if there is
+ // no port associated with the pid.
+ bool FreePortForProcess(lldb::pid_t pid);
+
+ // Returns true if there are no ports in the map, regardless of the state
+ // of those ports. Meaning a map with 1 used port is not empty.
+ bool empty() const;
+
+ private:
+ std::map<uint16_t, lldb::pid_t> m_port_map;
+ };
+
+ GDBRemoteCommunicationServerPlatform(
+ const Socket::SocketProtocol socket_protocol, const char *socket_scheme);
+
+ ~GDBRemoteCommunicationServerPlatform() override;
+
+ Status LaunchProcess() override;
+
+ // Set both ports to zero to let the platform automatically bind to
+ // a port chosen by the OS.
+ void SetPortMap(PortMap &&port_map);
+
+ void SetPortOffset(uint16_t port_offset);
+
+ void SetInferiorArguments(const lldb_private::Args &args);
+
+ // Set port if you want to use a specific port number.
+ // Otherwise port will be set to the port that was chosen for you.
+ Status LaunchGDBServer(const lldb_private::Args &args, std::string hostname,
+ lldb::pid_t &pid, std::optional<uint16_t> &port,
+ std::string &socket_name);
+
+ void SetPendingGdbServer(lldb::pid_t pid, uint16_t port,
+ const std::string &socket_name);
+
+protected:
+ const Socket::SocketProtocol m_socket_protocol;
+ const std::string m_socket_scheme;
+ std::recursive_mutex m_spawned_pids_mutex;
+ std::set<lldb::pid_t> m_spawned_pids;
+
+ PortMap m_port_map;
+ uint16_t m_port_offset;
+ struct {
+ lldb::pid_t pid;
+ uint16_t port;
+ std::string socket_name;
+ } m_pending_gdb_server;
+
+ PacketResult Handle_qLaunchGDBServer(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qQueryGDBServer(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qPathComplete(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_QSetWorkingDir(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qC(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jSignalsInfo(StringExtractorGDBRemote &packet);
+
+private:
+ bool KillSpawnedProcess(lldb::pid_t pid);
+
+ void DebugserverProcessReaped(lldb::pid_t pid);
+
+ static const FileSpec &GetDomainSocketDir();
+
+ static FileSpec GetDomainSocketPath(const char *prefix);
+
+ GDBRemoteCommunicationServerPlatform(
+ const GDBRemoteCommunicationServerPlatform &) = delete;
+ const GDBRemoteCommunicationServerPlatform &
+ operator=(const GDBRemoteCommunicationServerPlatform &) = delete;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONSERVERPLATFORM_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteErrno.def b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteErrno.def
new file mode 100644
index 000000000000..e26d23fdad0c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteErrno.def
@@ -0,0 +1,39 @@
+//===-- GDBRemoteErrno.def --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+// HANDLE_ERRNO(name, value)
+#ifndef HANDLE_ERRNO
+#error "HANDLE_ERRNO must be defined"
+#endif
+
+// from gdb's include/gdb/fileio.h
+HANDLE_ERRNO(EPERM, 1)
+HANDLE_ERRNO(ENOENT, 2)
+HANDLE_ERRNO(EINTR, 4)
+HANDLE_ERRNO(EIO, 5)
+HANDLE_ERRNO(EBADF, 9)
+HANDLE_ERRNO(EACCES, 13)
+HANDLE_ERRNO(EFAULT, 14)
+HANDLE_ERRNO(EBUSY, 16)
+HANDLE_ERRNO(EEXIST, 17)
+HANDLE_ERRNO(ENODEV, 19)
+HANDLE_ERRNO(ENOTDIR, 20)
+HANDLE_ERRNO(EISDIR, 21)
+HANDLE_ERRNO(EINVAL, 22)
+HANDLE_ERRNO(ENFILE, 23)
+HANDLE_ERRNO(EMFILE, 24)
+HANDLE_ERRNO(EFBIG, 27)
+HANDLE_ERRNO(ENOSPC, 28)
+HANDLE_ERRNO(ESPIPE, 29)
+HANDLE_ERRNO(EROFS, 30)
+HANDLE_ERRNO(ENOSYS, 88)
+HANDLE_ERRNO(ENAMETOOLONG, 91)
+
+#undef HANDLE_ERRNO
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
new file mode 100644
index 000000000000..e9bd65fad150
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -0,0 +1,777 @@
+//===-- GDBRemoteRegisterContext.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteRegisterContext.h"
+
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "ThreadGDBRemote.h"
+#include "Utility/ARM_DWARF_Registers.h"
+#include "Utility/ARM_ehframe_Registers.h"
+#include "lldb/Core/Architecture.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StringExtractorGDBRemote.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+// GDBRemoteRegisterContext constructor
+GDBRemoteRegisterContext::GDBRemoteRegisterContext(
+ ThreadGDBRemote &thread, uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfoSP reg_info_sp, bool read_all_at_once,
+ bool write_all_at_once)
+ : RegisterContext(thread, concrete_frame_idx),
+ m_reg_info_sp(std::move(reg_info_sp)), m_reg_valid(), m_reg_data(),
+ m_read_all_at_once(read_all_at_once),
+ m_write_all_at_once(write_all_at_once), m_gpacket_cached(false) {
+ // Resize our vector of bools to contain one bool for every register. We will
+ // use these boolean values to know when a register value is valid in
+ // m_reg_data.
+ m_reg_valid.resize(m_reg_info_sp->GetNumRegisters());
+
+ // Make a heap based buffer that is big enough to store all registers
+ DataBufferSP reg_data_sp(
+ new DataBufferHeap(m_reg_info_sp->GetRegisterDataByteSize(), 0));
+ m_reg_data.SetData(reg_data_sp);
+ m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder());
+}
+
+// Destructor
+GDBRemoteRegisterContext::~GDBRemoteRegisterContext() = default;
+
+void GDBRemoteRegisterContext::InvalidateAllRegisters() {
+ SetAllRegisterValid(false);
+}
+
+void GDBRemoteRegisterContext::SetAllRegisterValid(bool b) {
+ m_gpacket_cached = b;
+ std::vector<bool>::iterator pos, end = m_reg_valid.end();
+ for (pos = m_reg_valid.begin(); pos != end; ++pos)
+ *pos = b;
+}
+
+size_t GDBRemoteRegisterContext::GetRegisterCount() {
+ return m_reg_info_sp->GetNumRegisters();
+}
+
+const RegisterInfo *
+GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) {
+ return m_reg_info_sp->GetRegisterInfoAtIndex(reg);
+}
+
+size_t GDBRemoteRegisterContext::GetRegisterSetCount() {
+ return m_reg_info_sp->GetNumRegisterSets();
+}
+
+const RegisterSet *GDBRemoteRegisterContext::GetRegisterSet(size_t reg_set) {
+ return m_reg_info_sp->GetRegisterSet(reg_set);
+}
+
+bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ // Read the register
+ if (ReadRegisterBytes(reg_info)) {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ if (m_reg_valid[reg] == false)
+ return false;
+ if (reg_info->value_regs &&
+ reg_info->value_regs[0] != LLDB_INVALID_REGNUM &&
+ reg_info->value_regs[1] != LLDB_INVALID_REGNUM) {
+ std::vector<char> combined_data;
+ uint32_t offset = 0;
+ for (int i = 0; reg_info->value_regs[i] != LLDB_INVALID_REGNUM; i++) {
+ const RegisterInfo *parent_reg = GetRegisterInfo(
+ eRegisterKindLLDB, reg_info->value_regs[i]);
+ if (!parent_reg)
+ return false;
+ combined_data.resize(offset + parent_reg->byte_size);
+ if (m_reg_data.CopyData(parent_reg->byte_offset, parent_reg->byte_size,
+ combined_data.data() + offset) !=
+ parent_reg->byte_size)
+ return false;
+ offset += parent_reg->byte_size;
+ }
+
+ Status error;
+ return value.SetFromMemoryData(
+ *reg_info, combined_data.data(), combined_data.size(),
+ m_reg_data.GetByteOrder(), error) == combined_data.size();
+ } else {
+ const bool partial_data_ok = false;
+ Status error(value.SetValueFromData(
+ *reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok));
+ return error.Success();
+ }
+ }
+ return false;
+}
+
+bool GDBRemoteRegisterContext::PrivateSetRegisterValue(
+ uint32_t reg, llvm::ArrayRef<uint8_t> data) {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info == nullptr)
+ return false;
+
+ // Invalidate if needed
+ InvalidateIfNeeded(false);
+
+ const size_t reg_byte_size = reg_info->byte_size;
+ memcpy(const_cast<uint8_t *>(
+ m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)),
+ data.data(), std::min(data.size(), reg_byte_size));
+ bool success = data.size() >= reg_byte_size;
+ if (success) {
+ SetRegisterIsValid(reg, true);
+ } else if (data.size() > 0) {
+ // Only set register is valid to false if we copied some bytes, else leave
+ // it as it was.
+ SetRegisterIsValid(reg, false);
+ }
+ return success;
+}
+
+bool GDBRemoteRegisterContext::PrivateSetRegisterValue(uint32_t reg,
+ uint64_t new_reg_val) {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info == nullptr)
+ return false;
+
+ // Early in process startup, we can get a thread that has an invalid byte
+ // order because the process hasn't been completely set up yet (see the ctor
+ // where the byte order is setfrom the process). If that's the case, we
+ // can't set the value here.
+ if (m_reg_data.GetByteOrder() == eByteOrderInvalid) {
+ return false;
+ }
+
+ // Invalidate if needed
+ InvalidateIfNeeded(false);
+
+ DataBufferSP buffer_sp(new DataBufferHeap(&new_reg_val, sizeof(new_reg_val)));
+ DataExtractor data(buffer_sp, endian::InlHostByteOrder(), sizeof(void *));
+
+ // If our register context and our register info disagree, which should never
+ // happen, don't overwrite past the end of the buffer.
+ if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size)
+ return false;
+
+ // Grab a pointer to where we are going to put this register
+ uint8_t *dst = const_cast<uint8_t *>(
+ m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size));
+
+ if (dst == nullptr)
+ return false;
+
+ if (data.CopyByteOrderedData(0, // src offset
+ reg_info->byte_size, // src length
+ dst, // dst
+ reg_info->byte_size, // dst length
+ m_reg_data.GetByteOrder())) // dst byte order
+ {
+ SetRegisterIsValid(reg, true);
+ return true;
+ }
+ return false;
+}
+
+// Helper function for GDBRemoteRegisterContext::ReadRegisterBytes().
+bool GDBRemoteRegisterContext::GetPrimordialRegister(
+ const RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) {
+ const uint32_t lldb_reg = reg_info->kinds[eRegisterKindLLDB];
+ const uint32_t remote_reg = reg_info->kinds[eRegisterKindProcessPlugin];
+
+ if (DataBufferSP buffer_sp =
+ gdb_comm.ReadRegister(m_thread.GetProtocolID(), remote_reg))
+ return PrivateSetRegisterValue(
+ lldb_reg, llvm::ArrayRef<uint8_t>(buffer_sp->GetBytes(),
+ buffer_sp->GetByteSize()));
+ return false;
+}
+
+bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info) {
+ ExecutionContext exe_ctx(CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == nullptr || thread == nullptr)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm(
+ ((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ InvalidateIfNeeded(false);
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (!GetRegisterIsValid(reg)) {
+ if (m_read_all_at_once && !m_gpacket_cached) {
+ if (DataBufferSP buffer_sp =
+ gdb_comm.ReadAllRegisters(m_thread.GetProtocolID())) {
+ memcpy(const_cast<uint8_t *>(m_reg_data.GetDataStart()),
+ buffer_sp->GetBytes(),
+ std::min(buffer_sp->GetByteSize(), m_reg_data.GetByteSize()));
+ if (buffer_sp->GetByteSize() >= m_reg_data.GetByteSize()) {
+ SetAllRegisterValid(true);
+ return true;
+ } else if (buffer_sp->GetByteSize() > 0) {
+ for (auto x : llvm::enumerate(
+ m_reg_info_sp->registers<
+ DynamicRegisterInfo::reg_collection_const_range>())) {
+ const struct RegisterInfo &reginfo = x.value();
+ m_reg_valid[x.index()] =
+ (reginfo.byte_offset + reginfo.byte_size <=
+ buffer_sp->GetByteSize());
+ }
+
+ m_gpacket_cached = true;
+ if (GetRegisterIsValid(reg))
+ return true;
+ } else {
+ Log *log(GetLog(GDBRLog::Thread | GDBRLog::Packets));
+ LLDB_LOGF(
+ log,
+ "error: GDBRemoteRegisterContext::ReadRegisterBytes tried "
+ "to read the "
+ "entire register context at once, expected at least %" PRId64
+ " bytes "
+ "but only got %" PRId64 " bytes.",
+ m_reg_data.GetByteSize(), buffer_sp->GetByteSize());
+ return false;
+ }
+ }
+ }
+ if (reg_info->value_regs) {
+ // Process this composite register request by delegating to the
+ // constituent primordial registers.
+
+ // Index of the primordial register.
+ bool success = true;
+ for (uint32_t idx = 0; success; ++idx) {
+ const uint32_t prim_reg = reg_info->value_regs[idx];
+ if (prim_reg == LLDB_INVALID_REGNUM)
+ break;
+ // We have a valid primordial register as our constituent. Grab the
+ // corresponding register info.
+ const RegisterInfo *prim_reg_info =
+ GetRegisterInfo(eRegisterKindLLDB, prim_reg);
+ if (prim_reg_info == nullptr)
+ success = false;
+ else {
+ // Read the containing register if it hasn't already been read
+ if (!GetRegisterIsValid(prim_reg))
+ success = GetPrimordialRegister(prim_reg_info, gdb_comm);
+ }
+ }
+
+ if (success) {
+ // If we reach this point, all primordial register requests have
+ // succeeded. Validate this composite register.
+ SetRegisterIsValid(reg_info, true);
+ }
+ } else {
+ // Get each register individually
+ GetPrimordialRegister(reg_info, gdb_comm);
+ }
+
+ // Make sure we got a valid register value after reading it
+ if (!GetRegisterIsValid(reg))
+ return false;
+ }
+
+ return true;
+}
+
+bool GDBRemoteRegisterContext::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ DataExtractor data;
+ if (value.GetData(data)) {
+ if (reg_info->value_regs &&
+ reg_info->value_regs[0] != LLDB_INVALID_REGNUM &&
+ reg_info->value_regs[1] != LLDB_INVALID_REGNUM) {
+ uint32_t combined_size = 0;
+ for (int i = 0; reg_info->value_regs[i] != LLDB_INVALID_REGNUM; i++) {
+ const RegisterInfo *parent_reg = GetRegisterInfo(
+ eRegisterKindLLDB, reg_info->value_regs[i]);
+ if (!parent_reg)
+ return false;
+ combined_size += parent_reg->byte_size;
+ }
+
+ if (data.GetByteSize() < combined_size)
+ return false;
+
+ uint32_t offset = 0;
+ for (int i = 0; reg_info->value_regs[i] != LLDB_INVALID_REGNUM; i++) {
+ const RegisterInfo *parent_reg = GetRegisterInfo(
+ eRegisterKindLLDB, reg_info->value_regs[i]);
+ assert(parent_reg);
+
+ DataExtractor parent_data{data, offset, parent_reg->byte_size};
+ if (!WriteRegisterBytes(parent_reg, parent_data, 0))
+ return false;
+ offset += parent_reg->byte_size;
+ }
+ assert(offset == combined_size);
+ return true;
+ } else
+ return WriteRegisterBytes(reg_info, data, 0);
+ }
+ return false;
+}
+
+// Helper function for GDBRemoteRegisterContext::WriteRegisterBytes().
+bool GDBRemoteRegisterContext::SetPrimordialRegister(
+ const RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) {
+ StreamString packet;
+ StringExtractorGDBRemote response;
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ // Invalidate just this register
+ SetRegisterIsValid(reg, false);
+
+ return gdb_comm.WriteRegister(
+ m_thread.GetProtocolID(), reg_info->kinds[eRegisterKindProcessPlugin],
+ {m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size),
+ reg_info->byte_size});
+}
+
+bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
+ DataExtractor &data,
+ uint32_t data_offset) {
+ ExecutionContext exe_ctx(CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == nullptr || thread == nullptr)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm(
+ ((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ assert(m_reg_data.GetByteSize() >=
+ reg_info->byte_offset + reg_info->byte_size);
+
+ // If our register context and our register info disagree, which should never
+ // happen, don't overwrite past the end of the buffer.
+ if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size)
+ return false;
+
+ // Grab a pointer to where we are going to put this register
+ uint8_t *dst = const_cast<uint8_t *>(
+ m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size));
+
+ if (dst == nullptr)
+ return false;
+
+ const bool should_reconfigure_registers =
+ RegisterWriteCausesReconfigure(reg_info->name);
+
+ if (data.CopyByteOrderedData(data_offset, // src offset
+ reg_info->byte_size, // src length
+ dst, // dst
+ reg_info->byte_size, // dst length
+ m_reg_data.GetByteOrder())) // dst byte order
+ {
+ GDBRemoteClientBase::Lock lock(gdb_comm);
+ if (lock) {
+ if (m_write_all_at_once) {
+ // Invalidate all register values
+ InvalidateIfNeeded(true);
+
+ // Set all registers in one packet
+ if (gdb_comm.WriteAllRegisters(
+ m_thread.GetProtocolID(),
+ {m_reg_data.GetDataStart(), size_t(m_reg_data.GetByteSize())}))
+
+ {
+ if (should_reconfigure_registers)
+ ReconfigureRegisterInfo();
+
+ InvalidateAllRegisters();
+
+ return true;
+ }
+ } else {
+ bool success = true;
+
+ if (reg_info->value_regs) {
+ // This register is part of another register. In this case we read
+ // the actual register data for any "value_regs", and once all that
+ // data is read, we will have enough data in our register context
+ // bytes for the value of this register
+
+ // Invalidate this composite register first.
+
+ for (uint32_t idx = 0; success; ++idx) {
+ const uint32_t reg = reg_info->value_regs[idx];
+ if (reg == LLDB_INVALID_REGNUM)
+ break;
+ // We have a valid primordial register as our constituent. Grab the
+ // corresponding register info.
+ const RegisterInfo *value_reg_info =
+ GetRegisterInfo(eRegisterKindLLDB, reg);
+ if (value_reg_info == nullptr)
+ success = false;
+ else
+ success = SetPrimordialRegister(value_reg_info, gdb_comm);
+ }
+ } else {
+ // This is an actual register, write it
+ success = SetPrimordialRegister(reg_info, gdb_comm);
+ }
+
+ // Check if writing this register will invalidate any other register
+ // values? If so, invalidate them
+ if (reg_info->invalidate_regs) {
+ for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0];
+ reg != LLDB_INVALID_REGNUM;
+ reg = reg_info->invalidate_regs[++idx])
+ SetRegisterIsValid(ConvertRegisterKindToRegisterNumber(
+ eRegisterKindLLDB, reg),
+ false);
+ }
+
+ if (success && should_reconfigure_registers &&
+ ReconfigureRegisterInfo())
+ InvalidateAllRegisters();
+
+ return success;
+ }
+ } else {
+ Log *log(GetLog(GDBRLog::Thread | GDBRLog::Packets));
+ if (log) {
+ if (log->GetVerbose()) {
+ StreamString strm;
+ process->DumpPluginHistory(strm);
+ LLDB_LOGF(log,
+ "error: failed to get packet sequence mutex, not sending "
+ "write register for \"%s\":\n%s",
+ reg_info->name, strm.GetData());
+ } else
+ LLDB_LOGF(log,
+ "error: failed to get packet sequence mutex, not sending "
+ "write register for \"%s\"",
+ reg_info->name);
+ }
+ }
+ }
+ return false;
+}
+
+bool GDBRemoteRegisterContext::ReadAllRegisterValues(
+ RegisterCheckpoint &reg_checkpoint) {
+ ExecutionContext exe_ctx(CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == nullptr || thread == nullptr)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm(
+ ((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ uint32_t save_id = 0;
+ if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id)) {
+ reg_checkpoint.SetID(save_id);
+ reg_checkpoint.GetData().reset();
+ return true;
+ } else {
+ reg_checkpoint.SetID(0); // Invalid save ID is zero
+ return ReadAllRegisterValues(reg_checkpoint.GetData());
+ }
+}
+
+bool GDBRemoteRegisterContext::WriteAllRegisterValues(
+ const RegisterCheckpoint &reg_checkpoint) {
+ uint32_t save_id = reg_checkpoint.GetID();
+ if (save_id != 0) {
+ ExecutionContext exe_ctx(CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == nullptr || thread == nullptr)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm(
+ ((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id);
+ } else {
+ return WriteAllRegisterValues(reg_checkpoint.GetData());
+ }
+}
+
+bool GDBRemoteRegisterContext::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ ExecutionContext exe_ctx(CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == nullptr || thread == nullptr)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm(
+ ((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ const bool use_g_packet =
+ !gdb_comm.AvoidGPackets((ProcessGDBRemote *)process);
+
+ GDBRemoteClientBase::Lock lock(gdb_comm);
+ if (lock) {
+ if (gdb_comm.SyncThreadState(m_thread.GetProtocolID()))
+ InvalidateAllRegisters();
+
+ if (use_g_packet) {
+ if (DataBufferSP data_buffer =
+ gdb_comm.ReadAllRegisters(m_thread.GetProtocolID())) {
+ data_sp = std::make_shared<DataBufferHeap>(*data_buffer);
+ return true;
+ }
+ }
+
+ // We're going to read each register
+ // individually and store them as binary data in a buffer.
+ const RegisterInfo *reg_info;
+
+ for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex(i)) != nullptr;
+ i++) {
+ if (reg_info
+ ->value_regs) // skip registers that are slices of real registers
+ continue;
+ ReadRegisterBytes(reg_info);
+ // ReadRegisterBytes saves the contents of the register in to the
+ // m_reg_data buffer
+ }
+ data_sp = std::make_shared<DataBufferHeap>(
+ m_reg_data.GetDataStart(), m_reg_info_sp->GetRegisterDataByteSize());
+ return true;
+ } else {
+
+ Log *log(GetLog(GDBRLog::Thread | GDBRLog::Packets));
+ if (log) {
+ if (log->GetVerbose()) {
+ StreamString strm;
+ process->DumpPluginHistory(strm);
+ LLDB_LOGF(log,
+ "error: failed to get packet sequence mutex, not sending "
+ "read all registers:\n%s",
+ strm.GetData());
+ } else
+ LLDB_LOGF(log,
+ "error: failed to get packet sequence mutex, not sending "
+ "read all registers");
+ }
+ }
+
+ data_sp.reset();
+ return false;
+}
+
+bool GDBRemoteRegisterContext::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ if (!data_sp || data_sp->GetBytes() == nullptr || data_sp->GetByteSize() == 0)
+ return false;
+
+ ExecutionContext exe_ctx(CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == nullptr || thread == nullptr)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm(
+ ((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ const bool use_g_packet =
+ !gdb_comm.AvoidGPackets((ProcessGDBRemote *)process);
+
+ GDBRemoteClientBase::Lock lock(gdb_comm);
+ if (lock) {
+ // The data_sp contains the G response packet.
+ if (use_g_packet) {
+ if (gdb_comm.WriteAllRegisters(
+ m_thread.GetProtocolID(),
+ {data_sp->GetBytes(), size_t(data_sp->GetByteSize())}))
+ return true;
+
+ uint32_t num_restored = 0;
+ // We need to manually go through all of the registers and restore them
+ // manually
+ DataExtractor restore_data(data_sp, m_reg_data.GetByteOrder(),
+ m_reg_data.GetAddressByteSize());
+
+ const RegisterInfo *reg_info;
+
+ // The g packet contents may either include the slice registers
+ // (registers defined in terms of other registers, e.g. eax is a subset
+ // of rax) or not. The slice registers should NOT be in the g packet,
+ // but some implementations may incorrectly include them.
+ //
+ // If the slice registers are included in the packet, we must step over
+ // the slice registers when parsing the packet -- relying on the
+ // RegisterInfo byte_offset field would be incorrect. If the slice
+ // registers are not included, then using the byte_offset values into the
+ // data buffer is the best way to find individual register values.
+
+ uint64_t size_including_slice_registers = 0;
+ uint64_t size_not_including_slice_registers = 0;
+ uint64_t size_by_highest_offset = 0;
+
+ for (uint32_t reg_idx = 0;
+ (reg_info = GetRegisterInfoAtIndex(reg_idx)) != nullptr; ++reg_idx) {
+ size_including_slice_registers += reg_info->byte_size;
+ if (reg_info->value_regs == nullptr)
+ size_not_including_slice_registers += reg_info->byte_size;
+ if (reg_info->byte_offset >= size_by_highest_offset)
+ size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size;
+ }
+
+ bool use_byte_offset_into_buffer;
+ if (size_by_highest_offset == restore_data.GetByteSize()) {
+ // The size of the packet agrees with the highest offset: + size in the
+ // register file
+ use_byte_offset_into_buffer = true;
+ } else if (size_not_including_slice_registers ==
+ restore_data.GetByteSize()) {
+ // The size of the packet is the same as concatenating all of the
+ // registers sequentially, skipping the slice registers
+ use_byte_offset_into_buffer = true;
+ } else if (size_including_slice_registers == restore_data.GetByteSize()) {
+ // The slice registers are present in the packet (when they shouldn't
+ // be). Don't try to use the RegisterInfo byte_offset into the
+ // restore_data, it will point to the wrong place.
+ use_byte_offset_into_buffer = false;
+ } else {
+ // None of our expected sizes match the actual g packet data we're
+ // looking at. The most conservative approach here is to use the
+ // running total byte offset.
+ use_byte_offset_into_buffer = false;
+ }
+
+ // In case our register definitions don't include the correct offsets,
+ // keep track of the size of each reg & compute offset based on that.
+ uint32_t running_byte_offset = 0;
+ for (uint32_t reg_idx = 0;
+ (reg_info = GetRegisterInfoAtIndex(reg_idx)) != nullptr;
+ ++reg_idx, running_byte_offset += reg_info->byte_size) {
+ // Skip composite aka slice registers (e.g. eax is a slice of rax).
+ if (reg_info->value_regs)
+ continue;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ uint32_t register_offset;
+ if (use_byte_offset_into_buffer) {
+ register_offset = reg_info->byte_offset;
+ } else {
+ register_offset = running_byte_offset;
+ }
+
+ const uint32_t reg_byte_size = reg_info->byte_size;
+
+ const uint8_t *restore_src =
+ restore_data.PeekData(register_offset, reg_byte_size);
+ if (restore_src) {
+ SetRegisterIsValid(reg, false);
+ if (gdb_comm.WriteRegister(
+ m_thread.GetProtocolID(),
+ reg_info->kinds[eRegisterKindProcessPlugin],
+ {restore_src, reg_byte_size}))
+ ++num_restored;
+ }
+ }
+ return num_restored > 0;
+ } else {
+ // For the use_g_packet == false case, we're going to write each register
+ // individually. The data buffer is binary data in this case, instead of
+ // ascii characters.
+
+ bool arm64_debugserver = false;
+ if (m_thread.GetProcess().get()) {
+ const ArchSpec &arch =
+ m_thread.GetProcess()->GetTarget().GetArchitecture();
+ if (arch.IsValid() && (arch.GetMachine() == llvm::Triple::aarch64 ||
+ arch.GetMachine() == llvm::Triple::aarch64_32) &&
+ arch.GetTriple().getVendor() == llvm::Triple::Apple &&
+ arch.GetTriple().getOS() == llvm::Triple::IOS) {
+ arm64_debugserver = true;
+ }
+ }
+ uint32_t num_restored = 0;
+ const RegisterInfo *reg_info;
+ for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex(i)) != nullptr;
+ i++) {
+ if (reg_info->value_regs) // skip registers that are slices of real
+ // registers
+ continue;
+ // Skip the fpsr and fpcr floating point status/control register
+ // writing to work around a bug in an older version of debugserver that
+ // would lead to register context corruption when writing fpsr/fpcr.
+ if (arm64_debugserver && (strcmp(reg_info->name, "fpsr") == 0 ||
+ strcmp(reg_info->name, "fpcr") == 0)) {
+ continue;
+ }
+
+ SetRegisterIsValid(reg_info, false);
+ if (gdb_comm.WriteRegister(m_thread.GetProtocolID(),
+ reg_info->kinds[eRegisterKindProcessPlugin],
+ {data_sp->GetBytes() + reg_info->byte_offset,
+ reg_info->byte_size}))
+ ++num_restored;
+ }
+ return num_restored > 0;
+ }
+ } else {
+ Log *log(GetLog(GDBRLog::Thread | GDBRLog::Packets));
+ if (log) {
+ if (log->GetVerbose()) {
+ StreamString strm;
+ process->DumpPluginHistory(strm);
+ LLDB_LOGF(log,
+ "error: failed to get packet sequence mutex, not sending "
+ "write all registers:\n%s",
+ strm.GetData());
+ } else
+ LLDB_LOGF(log,
+ "error: failed to get packet sequence mutex, not sending "
+ "write all registers");
+ }
+ }
+ return false;
+}
+
+uint32_t GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ return m_reg_info_sp->ConvertRegisterKindToRegisterNumber(kind, num);
+}
+
+bool GDBRemoteRegisterContext::RegisterWriteCausesReconfigure(
+ const llvm::StringRef name) {
+ ExecutionContext exe_ctx(CalculateThread());
+ const Architecture *architecture =
+ exe_ctx.GetProcessRef().GetTarget().GetArchitecturePlugin();
+ return architecture && architecture->RegisterWriteCausesReconfigure(name);
+}
+
+bool GDBRemoteRegisterContext::ReconfigureRegisterInfo() {
+ ExecutionContext exe_ctx(CalculateThread());
+ const Architecture *architecture =
+ exe_ctx.GetProcessRef().GetTarget().GetArchitecturePlugin();
+ if (architecture)
+ return architecture->ReconfigureRegisterInfo(*(m_reg_info_sp.get()),
+ m_reg_data, *this);
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
new file mode 100644
index 000000000000..6a90f911353f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -0,0 +1,141 @@
+//===-- GDBRemoteRegisterContext.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERCONTEXT_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERCONTEXT_H
+
+#include <vector>
+
+#include "lldb/Target/DynamicRegisterInfo.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private.h"
+
+#include "GDBRemoteCommunicationClient.h"
+
+class StringExtractor;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ThreadGDBRemote;
+class ProcessGDBRemote;
+class GDBRemoteDynamicRegisterInfo;
+
+typedef std::shared_ptr<GDBRemoteDynamicRegisterInfo>
+ GDBRemoteDynamicRegisterInfoSP;
+
+class GDBRemoteDynamicRegisterInfo final : public DynamicRegisterInfo {
+public:
+ GDBRemoteDynamicRegisterInfo() : DynamicRegisterInfo() {}
+
+ ~GDBRemoteDynamicRegisterInfo() override = default;
+
+ void UpdateARM64SVERegistersInfos(uint64_t vg);
+ void UpdateARM64SMERegistersInfos(uint64_t svg);
+};
+
+class GDBRemoteRegisterContext : public RegisterContext {
+public:
+ GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfoSP reg_info_sp,
+ bool read_all_at_once, bool write_all_at_once);
+
+ ~GDBRemoteRegisterContext() override;
+
+ void InvalidateAllRegisters() override;
+
+ 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 &value) override;
+
+ bool WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) override;
+
+ bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ bool ReadAllRegisterValues(RegisterCheckpoint &reg_checkpoint) override;
+
+ bool
+ WriteAllRegisterValues(const RegisterCheckpoint &reg_checkpoint) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ bool RegisterWriteCausesReconfigure(const llvm::StringRef name) override;
+
+ bool ReconfigureRegisterInfo() override;
+
+protected:
+ friend class ThreadGDBRemote;
+
+ bool ReadRegisterBytes(const RegisterInfo *reg_info);
+
+ bool WriteRegisterBytes(const RegisterInfo *reg_info, DataExtractor &data,
+ uint32_t data_offset);
+
+ bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data);
+
+ bool PrivateSetRegisterValue(uint32_t reg, uint64_t val);
+
+ void SetAllRegisterValid(bool b);
+
+ bool GetRegisterIsValid(uint32_t reg) const {
+ assert(reg < m_reg_valid.size());
+ if (reg < m_reg_valid.size())
+ return m_reg_valid[reg];
+ return false;
+ }
+
+ void SetRegisterIsValid(const RegisterInfo *reg_info, bool valid) {
+ if (reg_info)
+ return SetRegisterIsValid(reg_info->kinds[lldb::eRegisterKindLLDB],
+ valid);
+ }
+
+ void SetRegisterIsValid(uint32_t reg, bool valid) {
+ assert(reg < m_reg_valid.size());
+ if (reg < m_reg_valid.size())
+ m_reg_valid[reg] = valid;
+ }
+
+ GDBRemoteDynamicRegisterInfoSP m_reg_info_sp;
+ std::vector<bool> m_reg_valid;
+ DataExtractor m_reg_data;
+ bool m_read_all_at_once;
+ bool m_write_all_at_once;
+ bool m_gpacket_cached;
+
+private:
+ // Helper function for ReadRegisterBytes().
+ bool GetPrimordialRegister(const RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm);
+ // Helper function for WriteRegisterBytes().
+ bool SetPrimordialRegister(const RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm);
+
+ GDBRemoteRegisterContext(const GDBRemoteRegisterContext &) = delete;
+ const GDBRemoteRegisterContext &
+ operator=(const GDBRemoteRegisterContext &) = delete;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERCONTEXT_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.cpp
new file mode 100644
index 000000000000..8068614c9350
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.cpp
@@ -0,0 +1,101 @@
+//===-- GDBRemoteRegisterFallback.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteRegisterFallback.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+#define REG(name, size) \
+ DynamicRegisterInfo::Register { \
+ ConstString(#name), empty_alt_name, reg_set, size, LLDB_INVALID_INDEX32, \
+ lldb::eEncodingUint, lldb::eFormatHex, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, {}, {} \
+ }
+#define R64(name) REG(name, 8)
+#define R32(name) REG(name, 4)
+#define R16(name) REG(name, 2)
+
+static std::vector<DynamicRegisterInfo::Register> GetRegisters_aarch64() {
+ ConstString empty_alt_name;
+ ConstString reg_set{"general purpose registers"};
+
+ std::vector<DynamicRegisterInfo::Register> registers{
+ R64(x0), R64(x1), R64(x2), R64(x3), R64(x4), R64(x5), R64(x6),
+ R64(x7), R64(x8), R64(x9), R64(x10), R64(x11), R64(x12), R64(x13),
+ R64(x14), R64(x15), R64(x16), R64(x17), R64(x18), R64(x19), R64(x20),
+ R64(x21), R64(x22), R64(x23), R64(x24), R64(x25), R64(x26), R64(x27),
+ R64(x28), R64(x29), R64(x30), R64(sp), R64(pc), R32(cpsr),
+ };
+
+ return registers;
+}
+
+static std::vector<DynamicRegisterInfo::Register> GetRegisters_msp430() {
+ ConstString empty_alt_name;
+ ConstString reg_set{"general purpose registers"};
+
+ std::vector<DynamicRegisterInfo::Register> registers{
+ R16(pc), R16(sp), R16(r2), R16(r3), R16(fp), R16(r5),
+ R16(r6), R16(r7), R16(r8), R16(r9), R16(r10), R16(r11),
+ R16(r12), R16(r13), R16(r14), R16(r15)};
+
+ return registers;
+}
+
+static std::vector<DynamicRegisterInfo::Register> GetRegisters_x86() {
+ ConstString empty_alt_name;
+ ConstString reg_set{"general purpose registers"};
+
+ std::vector<DynamicRegisterInfo::Register> registers{
+ R32(eax), R32(ecx), R32(edx), R32(ebx), R32(esp), R32(ebp),
+ R32(esi), R32(edi), R32(eip), R32(eflags), R32(cs), R32(ss),
+ R32(ds), R32(es), R32(fs), R32(gs),
+ };
+
+ return registers;
+}
+
+static std::vector<DynamicRegisterInfo::Register> GetRegisters_x86_64() {
+ ConstString empty_alt_name;
+ ConstString reg_set{"general purpose registers"};
+
+ std::vector<DynamicRegisterInfo::Register> registers{
+ R64(rax), R64(rbx), R64(rcx), R64(rdx), R64(rsi), R64(rdi),
+ R64(rbp), R64(rsp), R64(r8), R64(r9), R64(r10), R64(r11),
+ R64(r12), R64(r13), R64(r14), R64(r15), R64(rip), R32(eflags),
+ R32(cs), R32(ss), R32(ds), R32(es), R32(fs), R32(gs),
+ };
+
+ return registers;
+}
+
+#undef R32
+#undef R64
+#undef REG
+
+std::vector<DynamicRegisterInfo::Register>
+GetFallbackRegisters(const ArchSpec &arch_to_use) {
+ switch (arch_to_use.GetMachine()) {
+ case llvm::Triple::aarch64:
+ return GetRegisters_aarch64();
+ case llvm::Triple::msp430:
+ return GetRegisters_msp430();
+ case llvm::Triple::x86:
+ return GetRegisters_x86();
+ case llvm::Triple::x86_64:
+ return GetRegisters_x86_64();
+ default:
+ break;
+ }
+
+ return {};
+}
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.h
new file mode 100644
index 000000000000..82e03c6b9b1c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.h
@@ -0,0 +1,26 @@
+//===-- GDBRemoteRegisterFallback.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERFALLBACK_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERFALLBACK_H
+
+#include <vector>
+
+#include "lldb/Target/DynamicRegisterInfo.h"
+#include "lldb/Utility/ArchSpec.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+std::vector<DynamicRegisterInfo::Register>
+GetFallbackRegisters(const ArchSpec &arch_to_use);
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERFALLBACK_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
new file mode 100644
index 000000000000..604c92369e9a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -0,0 +1,5876 @@
+//===-- ProcessGDBRemote.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Config.h"
+
+#include <cerrno>
+#include <cstdlib>
+#if LLDB_ENABLE_POSIX
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+#if defined(__APPLE__)
+#include <sys/sysctl.h>
+#endif
+#include <ctime>
+#include <sys/types.h>
+
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/WatchpointAlgorithms.h"
+#include "lldb/Breakpoint/WatchpointResource.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Value.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Host/PseudoTerminal.h"
+#include "lldb/Host/StreamFile.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/XML.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionGroupBoolean.h"
+#include "lldb/Interpreter/OptionGroupUInt64.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/Property.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/RegisterFlags.h"
+#include "lldb/Target/SystemRuntime.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/State.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
+#include <algorithm>
+#include <csignal>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <sstream>
+#include <thread>
+
+#include "GDBRemoteRegisterContext.h"
+#include "GDBRemoteRegisterFallback.h"
+#include "Plugins/Process/Utility/GDBRemoteSignals.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "Plugins/Process/Utility/StopInfoMachException.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "ThreadGDBRemote.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Utility/StringExtractorGDBRemote.h"
+
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUGSERVER_BASENAME "debugserver"
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+LLDB_PLUGIN_DEFINE(ProcessGDBRemote)
+
+namespace lldb {
+// Provide a function that can easily dump the packet history if we know a
+// ProcessGDBRemote * value (which we can get from logs or from debugging). We
+// need the function in the lldb namespace so it makes it into the final
+// executable since the LLDB shared library only exports stuff in the lldb
+// namespace. This allows you to attach with a debugger and call this function
+// and get the packet history dumped to a file.
+void DumpProcessGDBRemotePacketHistory(void *p, const char *path) {
+ auto file = FileSystem::Instance().Open(
+ FileSpec(path), File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate);
+ if (!file) {
+ llvm::consumeError(file.takeError());
+ return;
+ }
+ StreamFile stream(std::move(file.get()));
+ ((Process *)p)->DumpPluginHistory(stream);
+}
+} // namespace lldb
+
+namespace {
+
+#define LLDB_PROPERTIES_processgdbremote
+#include "ProcessGDBRemoteProperties.inc"
+
+enum {
+#define LLDB_PROPERTIES_processgdbremote
+#include "ProcessGDBRemotePropertiesEnum.inc"
+};
+
+class PluginProperties : public Properties {
+public:
+ static llvm::StringRef GetSettingName() {
+ return ProcessGDBRemote::GetPluginNameStatic();
+ }
+
+ PluginProperties() : Properties() {
+ m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
+ m_collection_sp->Initialize(g_processgdbremote_properties);
+ }
+
+ ~PluginProperties() override = default;
+
+ uint64_t GetPacketTimeout() {
+ const uint32_t idx = ePropertyPacketTimeout;
+ return GetPropertyAtIndexAs<uint64_t>(
+ idx, g_processgdbremote_properties[idx].default_uint_value);
+ }
+
+ bool SetPacketTimeout(uint64_t timeout) {
+ const uint32_t idx = ePropertyPacketTimeout;
+ return SetPropertyAtIndex(idx, timeout);
+ }
+
+ FileSpec GetTargetDefinitionFile() const {
+ const uint32_t idx = ePropertyTargetDefinitionFile;
+ return GetPropertyAtIndexAs<FileSpec>(idx, {});
+ }
+
+ bool GetUseSVR4() const {
+ const uint32_t idx = ePropertyUseSVR4;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_processgdbremote_properties[idx].default_uint_value != 0);
+ }
+
+ bool GetUseGPacketForReading() const {
+ const uint32_t idx = ePropertyUseGPacketForReading;
+ return GetPropertyAtIndexAs<bool>(idx, true);
+ }
+};
+
+} // namespace
+
+static PluginProperties &GetGlobalPluginProperties() {
+ static PluginProperties g_settings;
+ return g_settings;
+}
+
+// TODO Randomly assigning a port is unsafe. We should get an unused
+// ephemeral port from the kernel and make sure we reserve it before passing it
+// to debugserver.
+
+#if defined(__APPLE__)
+#define LOW_PORT (IPPORT_RESERVED)
+#define HIGH_PORT (IPPORT_HIFIRSTAUTO)
+#else
+#define LOW_PORT (1024u)
+#define HIGH_PORT (49151u)
+#endif
+
+llvm::StringRef ProcessGDBRemote::GetPluginDescriptionStatic() {
+ return "GDB Remote protocol based debugging plug-in.";
+}
+
+void ProcessGDBRemote::Terminate() {
+ PluginManager::UnregisterPlugin(ProcessGDBRemote::CreateInstance);
+}
+
+lldb::ProcessSP ProcessGDBRemote::CreateInstance(
+ lldb::TargetSP target_sp, ListenerSP listener_sp,
+ const FileSpec *crash_file_path, bool can_connect) {
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == nullptr)
+ process_sp = std::shared_ptr<ProcessGDBRemote>(
+ new ProcessGDBRemote(target_sp, listener_sp));
+ return process_sp;
+}
+
+void ProcessGDBRemote::DumpPluginHistory(Stream &s) {
+ GDBRemoteCommunicationClient &gdb_comm(GetGDBRemote());
+ gdb_comm.DumpHistory(s);
+}
+
+std::chrono::seconds ProcessGDBRemote::GetPacketTimeout() {
+ return std::chrono::seconds(GetGlobalPluginProperties().GetPacketTimeout());
+}
+
+ArchSpec ProcessGDBRemote::GetSystemArchitecture() {
+ return m_gdb_comm.GetHostArchitecture();
+}
+
+bool ProcessGDBRemote::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
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+ if (exe_module) {
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ // We can't debug core files...
+ switch (exe_objfile->GetType()) {
+ case ObjectFile::eTypeInvalid:
+ case ObjectFile::eTypeCoreFile:
+ case ObjectFile::eTypeDebugInfo:
+ case ObjectFile::eTypeObjectFile:
+ case ObjectFile::eTypeSharedLibrary:
+ case ObjectFile::eTypeStubLibrary:
+ case ObjectFile::eTypeJIT:
+ return false;
+ case ObjectFile::eTypeExecutable:
+ case ObjectFile::eTypeDynamicLinker:
+ case ObjectFile::eTypeUnknown:
+ break;
+ }
+ return FileSystem::Instance().Exists(exe_module->GetFileSpec());
+ }
+ // However, if there is no executable module, we return true since we might
+ // be preparing to attach.
+ return true;
+}
+
+// ProcessGDBRemote constructor
+ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
+ ListenerSP listener_sp)
+ : Process(target_sp, listener_sp),
+ m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_register_info_sp(nullptr),
+ m_async_broadcaster(nullptr, "lldb.process.gdb-remote.async-broadcaster"),
+ m_async_listener_sp(
+ Listener::MakeListener("lldb.process.gdb-remote.async-listener")),
+ m_async_thread_state_mutex(), m_thread_ids(), m_thread_pcs(),
+ m_jstopinfo_sp(), m_jthreadsinfo_sp(), m_continue_c_tids(),
+ m_continue_C_tids(), m_continue_s_tids(), m_continue_S_tids(),
+ m_max_memory_size(0), m_remote_stub_max_memory_size(0),
+ m_addr_to_mmap_size(), m_thread_create_bp_sp(),
+ m_waiting_for_attach(false), m_command_sp(), m_breakpoint_pc_offset(0),
+ m_initial_tid(LLDB_INVALID_THREAD_ID), m_allow_flash_writes(false),
+ m_erased_flash_ranges(), m_vfork_in_progress_count(0) {
+ m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit,
+ "async thread should exit");
+ m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue,
+ "async thread continue");
+ m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit,
+ "async thread did exit");
+
+ Log *log = GetLog(GDBRLog::Async);
+
+ const uint32_t async_event_mask =
+ eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit;
+
+ if (m_async_listener_sp->StartListeningForEvents(
+ &m_async_broadcaster, async_event_mask) != async_event_mask) {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s failed to listen for "
+ "m_async_broadcaster events",
+ __FUNCTION__);
+ }
+
+ const uint64_t timeout_seconds =
+ GetGlobalPluginProperties().GetPacketTimeout();
+ if (timeout_seconds > 0)
+ m_gdb_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds));
+
+ m_use_g_packet_for_reading =
+ GetGlobalPluginProperties().GetUseGPacketForReading();
+}
+
+// Destructor
+ProcessGDBRemote::~ProcessGDBRemote() {
+ // m_mach_process.UnregisterNotificationCallbacks (this);
+ 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(true /* destructing */);
+
+ // 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.
+ StopAsyncThread();
+ KillDebugserverProcess();
+}
+
+bool ProcessGDBRemote::ParsePythonTargetDefinition(
+ const FileSpec &target_definition_fspec) {
+ ScriptInterpreter *interpreter =
+ GetTarget().GetDebugger().GetScriptInterpreter();
+ Status error;
+ StructuredData::ObjectSP module_object_sp(
+ interpreter->LoadPluginModule(target_definition_fspec, error));
+ if (module_object_sp) {
+ StructuredData::DictionarySP target_definition_sp(
+ interpreter->GetDynamicSettings(module_object_sp, &GetTarget(),
+ "gdb-server-target-definition", error));
+
+ if (target_definition_sp) {
+ StructuredData::ObjectSP target_object(
+ target_definition_sp->GetValueForKey("host-info"));
+ if (target_object) {
+ if (auto host_info_dict = target_object->GetAsDictionary()) {
+ StructuredData::ObjectSP triple_value =
+ host_info_dict->GetValueForKey("triple");
+ if (auto triple_string_value = triple_value->GetAsString()) {
+ std::string triple_string =
+ std::string(triple_string_value->GetValue());
+ ArchSpec host_arch(triple_string.c_str());
+ if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture())) {
+ GetTarget().SetArchitecture(host_arch);
+ }
+ }
+ }
+ }
+ m_breakpoint_pc_offset = 0;
+ StructuredData::ObjectSP breakpoint_pc_offset_value =
+ target_definition_sp->GetValueForKey("breakpoint-pc-offset");
+ if (breakpoint_pc_offset_value) {
+ if (auto breakpoint_pc_int_value =
+ breakpoint_pc_offset_value->GetAsSignedInteger())
+ m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue();
+ }
+
+ if (m_register_info_sp->SetRegisterInfo(
+ *target_definition_sp, GetTarget().GetArchitecture()) > 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static size_t SplitCommaSeparatedRegisterNumberString(
+ const llvm::StringRef &comma_separated_register_numbers,
+ std::vector<uint32_t> &regnums, int base) {
+ regnums.clear();
+ for (llvm::StringRef x : llvm::split(comma_separated_register_numbers, ',')) {
+ uint32_t reg;
+ if (llvm::to_integer(x, reg, base))
+ regnums.push_back(reg);
+ }
+ return regnums.size();
+}
+
+void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
+ if (!force && m_register_info_sp)
+ return;
+
+ m_register_info_sp = std::make_shared<GDBRemoteDynamicRegisterInfo>();
+
+ // Check if qHostInfo specified a specific packet timeout for this
+ // connection. If so then lets update our setting so the user knows what the
+ // timeout is and can see it.
+ const auto host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout();
+ if (host_packet_timeout > std::chrono::seconds(0)) {
+ GetGlobalPluginProperties().SetPacketTimeout(host_packet_timeout.count());
+ }
+
+ // 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.
+ // 4 - Use hardcoded defaults if available.
+
+ FileSpec target_definition_fspec =
+ GetGlobalPluginProperties().GetTargetDefinitionFile();
+ if (!FileSystem::Instance().Exists(target_definition_fspec)) {
+ // If the filename doesn't exist, it may be a ~ not having been expanded -
+ // try to resolve it.
+ FileSystem::Instance().Resolve(target_definition_fspec);
+ }
+ if (target_definition_fspec) {
+ // See if we can get register definitions from a python file
+ if (ParsePythonTargetDefinition(target_definition_fspec))
+ return;
+
+ Debugger::ReportError("target description file " +
+ target_definition_fspec.GetPath() +
+ " failed to parse",
+ GetTarget().GetDebugger().GetID());
+ }
+
+ const ArchSpec &target_arch = GetTarget().GetArchitecture();
+ const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture();
+ const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture();
+
+ // Use the process' architecture instead of the host arch, if available
+ ArchSpec arch_to_use;
+ if (remote_process_arch.IsValid())
+ arch_to_use = remote_process_arch;
+ else
+ arch_to_use = remote_host_arch;
+
+ if (!arch_to_use.IsValid())
+ arch_to_use = target_arch;
+
+ if (GetGDBServerRegisterInfo(arch_to_use))
+ return;
+
+ char packet[128];
+ std::vector<DynamicRegisterInfo::Register> registers;
+ uint32_t reg_num = 0;
+ for (StringExtractorGDBRemote::ResponseType response_type =
+ StringExtractorGDBRemote::eResponse;
+ response_type == StringExtractorGDBRemote::eResponse; ++reg_num) {
+ const int packet_len =
+ ::snprintf(packet, sizeof(packet), "qRegisterInfo%x", reg_num);
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ response_type = response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse) {
+ llvm::StringRef name;
+ llvm::StringRef value;
+ DynamicRegisterInfo::Register reg_info;
+
+ while (response.GetNameColonValue(name, value)) {
+ if (name == "name") {
+ reg_info.name.SetString(value);
+ } else if (name == "alt-name") {
+ reg_info.alt_name.SetString(value);
+ } else if (name == "bitsize") {
+ if (!value.getAsInteger(0, reg_info.byte_size))
+ reg_info.byte_size /= CHAR_BIT;
+ } else if (name == "offset") {
+ value.getAsInteger(0, reg_info.byte_offset);
+ } else if (name == "encoding") {
+ const Encoding encoding = Args::StringToEncoding(value);
+ if (encoding != eEncodingInvalid)
+ reg_info.encoding = encoding;
+ } else if (name == "format") {
+ if (!OptionArgParser::ToFormat(value.str().c_str(), reg_info.format, nullptr)
+ .Success())
+ reg_info.format =
+ llvm::StringSwitch<Format>(value)
+ .Case("binary", eFormatBinary)
+ .Case("decimal", eFormatDecimal)
+ .Case("hex", eFormatHex)
+ .Case("float", eFormatFloat)
+ .Case("vector-sint8", eFormatVectorOfSInt8)
+ .Case("vector-uint8", eFormatVectorOfUInt8)
+ .Case("vector-sint16", eFormatVectorOfSInt16)
+ .Case("vector-uint16", eFormatVectorOfUInt16)
+ .Case("vector-sint32", eFormatVectorOfSInt32)
+ .Case("vector-uint32", eFormatVectorOfUInt32)
+ .Case("vector-float32", eFormatVectorOfFloat32)
+ .Case("vector-uint64", eFormatVectorOfUInt64)
+ .Case("vector-uint128", eFormatVectorOfUInt128)
+ .Default(eFormatInvalid);
+ } else if (name == "set") {
+ reg_info.set_name.SetString(value);
+ } else if (name == "gcc" || name == "ehframe") {
+ value.getAsInteger(0, reg_info.regnum_ehframe);
+ } else if (name == "dwarf") {
+ value.getAsInteger(0, reg_info.regnum_dwarf);
+ } else if (name == "generic") {
+ reg_info.regnum_generic = Args::StringToGenericRegister(value);
+ } else if (name == "container-regs") {
+ SplitCommaSeparatedRegisterNumberString(value, reg_info.value_regs, 16);
+ } else if (name == "invalidate-regs") {
+ SplitCommaSeparatedRegisterNumberString(value, reg_info.invalidate_regs, 16);
+ }
+ }
+
+ assert(reg_info.byte_size != 0);
+ registers.push_back(reg_info);
+ } else {
+ break; // ensure exit before reg_num is incremented
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (registers.empty())
+ registers = GetFallbackRegisters(arch_to_use);
+
+ AddRemoteRegisters(registers, arch_to_use);
+}
+
+Status ProcessGDBRemote::DoWillLaunch(lldb_private::Module *module) {
+ return WillLaunchOrAttach();
+}
+
+Status ProcessGDBRemote::DoWillAttachToProcessWithID(lldb::pid_t pid) {
+ return WillLaunchOrAttach();
+}
+
+Status ProcessGDBRemote::DoWillAttachToProcessWithName(const char *process_name,
+ bool wait_for_launch) {
+ return WillLaunchOrAttach();
+}
+
+Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ Status error(WillLaunchOrAttach());
+ if (error.Fail())
+ return error;
+
+ error = ConnectToDebugserver(remote_url);
+ if (error.Fail())
+ return error;
+
+ StartAsyncThread();
+
+ lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID();
+ 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 listings...
+ SetPrivateState(eStateConnected);
+ } else {
+ // We have a valid process
+ SetID(pid);
+ GetThreadList();
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.GetStopReply(response)) {
+ SetLastStopPacket(response);
+
+ Target &target = GetTarget();
+ if (!target.GetArchitecture().IsValid()) {
+ if (m_gdb_comm.GetProcessArchitecture().IsValid()) {
+ target.SetArchitecture(m_gdb_comm.GetProcessArchitecture());
+ } else {
+ if (m_gdb_comm.GetHostArchitecture().IsValid()) {
+ target.SetArchitecture(m_gdb_comm.GetHostArchitecture());
+ }
+ }
+ }
+
+ const StateType state = SetThreadStopInfo(response);
+ if (state != eStateInvalid) {
+ SetPrivateState(state);
+ } else
+ error.SetErrorStringWithFormat(
+ "Process %" PRIu64 " was reported after connecting to "
+ "'%s', but state was not stopped: %s",
+ pid, remote_url.str().c_str(), StateAsCString(state));
+ } else
+ error.SetErrorStringWithFormat("Process %" PRIu64
+ " was reported after connecting to '%s', "
+ "but no stop reply packet was received",
+ pid, remote_url.str().c_str());
+ }
+
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s pid %" PRIu64
+ ": normalizing target architecture initial triple: %s "
+ "(GetTarget().GetArchitecture().IsValid() %s, "
+ "m_gdb_comm.GetHostArchitecture().IsValid(): %s)",
+ __FUNCTION__, GetID(),
+ GetTarget().GetArchitecture().GetTriple().getTriple().c_str(),
+ GetTarget().GetArchitecture().IsValid() ? "true" : "false",
+ m_gdb_comm.GetHostArchitecture().IsValid() ? "true" : "false");
+
+ if (error.Success() && !GetTarget().GetArchitecture().IsValid() &&
+ m_gdb_comm.GetHostArchitecture().IsValid()) {
+ // Prefer the *process'* architecture over that of the *host*, if
+ // available.
+ if (m_gdb_comm.GetProcessArchitecture().IsValid())
+ GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture());
+ else
+ GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture());
+ }
+
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s pid %" PRIu64
+ ": normalized target architecture triple: %s",
+ __FUNCTION__, GetID(),
+ GetTarget().GetArchitecture().GetTriple().getTriple().c_str());
+
+ return error;
+}
+
+Status ProcessGDBRemote::WillLaunchOrAttach() {
+ Status error;
+ m_stdio_communication.Clear();
+ return error;
+}
+
+// Process Control
+Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module,
+ ProcessLaunchInfo &launch_info) {
+ Log *log = GetLog(GDBRLog::Process);
+ Status error;
+
+ LLDB_LOGF(log, "ProcessGDBRemote::%s() entered", __FUNCTION__);
+
+ uint32_t launch_flags = launch_info.GetFlags().Get();
+ FileSpec stdin_file_spec{};
+ FileSpec stdout_file_spec{};
+ FileSpec stderr_file_spec{};
+ FileSpec working_dir = launch_info.GetWorkingDirectory();
+
+ const FileAction *file_action;
+ file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
+ if (file_action) {
+ if (file_action->GetAction() == FileAction::eFileActionOpen)
+ stdin_file_spec = file_action->GetFileSpec();
+ }
+ file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
+ if (file_action) {
+ if (file_action->GetAction() == FileAction::eFileActionOpen)
+ stdout_file_spec = file_action->GetFileSpec();
+ }
+ file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
+ if (file_action) {
+ if (file_action->GetAction() == FileAction::eFileActionOpen)
+ stderr_file_spec = file_action->GetFileSpec();
+ }
+
+ if (log) {
+ if (stdin_file_spec || stdout_file_spec || stderr_file_spec)
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s provided with STDIO paths via "
+ "launch_info: stdin=%s, stdout=%s, stderr=%s",
+ __FUNCTION__,
+ stdin_file_spec ? stdin_file_spec.GetPath().c_str() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetPath().c_str() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetPath().c_str() : "<null>");
+ else
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s no STDIO paths given via launch_info",
+ __FUNCTION__);
+ }
+
+ const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
+ if (stdin_file_spec || disable_stdio) {
+ // the inferior will be reading stdin from the specified file or stdio is
+ // completely disabled
+ m_stdin_forward = false;
+ } else {
+ m_stdin_forward = true;
+ }
+
+ // ::LogSetBitMask (GDBR_LOG_DEFAULT);
+ // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE |
+ // LLDB_LOG_OPTION_PREPEND_TIMESTAMP |
+ // LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
+ // ::LogSetLogFile ("/dev/stdout");
+
+ error = EstablishConnectionIfNeeded(launch_info);
+ if (error.Success()) {
+ PseudoTerminal pty;
+ const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
+
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+ if (disable_stdio) {
+ // set to /dev/null unless redirected to a file above
+ if (!stdin_file_spec)
+ stdin_file_spec.SetFile(FileSystem::DEV_NULL,
+ FileSpec::Style::native);
+ if (!stdout_file_spec)
+ stdout_file_spec.SetFile(FileSystem::DEV_NULL,
+ FileSpec::Style::native);
+ if (!stderr_file_spec)
+ stderr_file_spec.SetFile(FileSystem::DEV_NULL,
+ FileSpec::Style::native);
+ } else if (platform_sp && platform_sp->IsHost()) {
+ // If the debugserver is local and we aren't disabling STDIO, lets use
+ // a pseudo terminal to instead of relying on the 'O' packets for stdio
+ // since 'O' packets can really slow down debugging if the inferior
+ // does a lot of output.
+ if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
+ !errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) {
+ FileSpec secondary_name(pty.GetSecondaryName());
+
+ if (!stdin_file_spec)
+ stdin_file_spec = secondary_name;
+
+ if (!stdout_file_spec)
+ stdout_file_spec = secondary_name;
+
+ if (!stderr_file_spec)
+ stderr_file_spec = secondary_name;
+ }
+ LLDB_LOGF(
+ log,
+ "ProcessGDBRemote::%s adjusted STDIO paths for local platform "
+ "(IsHost() is true) using secondary: stdin=%s, stdout=%s, "
+ "stderr=%s",
+ __FUNCTION__,
+ stdin_file_spec ? stdin_file_spec.GetPath().c_str() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetPath().c_str() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetPath().c_str() : "<null>");
+ }
+
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s final STDIO paths after all "
+ "adjustments: stdin=%s, stdout=%s, stderr=%s",
+ __FUNCTION__,
+ stdin_file_spec ? stdin_file_spec.GetPath().c_str() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetPath().c_str() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetPath().c_str() : "<null>");
+
+ if (stdin_file_spec)
+ m_gdb_comm.SetSTDIN(stdin_file_spec);
+ if (stdout_file_spec)
+ m_gdb_comm.SetSTDOUT(stdout_file_spec);
+ if (stderr_file_spec)
+ m_gdb_comm.SetSTDERR(stderr_file_spec);
+
+ m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR);
+ 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 != nullptr && *launch_event_data != '\0')
+ m_gdb_comm.SendLaunchEventDataPacket(launch_event_data);
+
+ if (working_dir) {
+ m_gdb_comm.SetWorkingDir(working_dir);
+ }
+
+ // Send the environment and the program + arguments after we connect
+ m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
+
+ {
+ // Scope for the scoped timeout object
+ GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm,
+ std::chrono::seconds(10));
+
+ // Since we can't send argv0 separate from the executable path, we need to
+ // make sure to use the actual executable path found in the launch_info...
+ Args args = launch_info.GetArguments();
+ if (FileSpec exe_file = launch_info.GetExecutableFile())
+ args.ReplaceArgumentAtIndex(0, exe_file.GetPath(false));
+ if (llvm::Error err = m_gdb_comm.LaunchProcess(args)) {
+ error.SetErrorStringWithFormatv("Cannot launch '{0}': {1}",
+ args.GetArgumentAtIndex(0),
+ llvm::fmt_consume(std::move(err)));
+ } else {
+ SetID(m_gdb_comm.GetCurrentProcessID());
+ }
+ }
+
+ if (GetID() == LLDB_INVALID_PROCESS_ID) {
+ LLDB_LOGF(log, "failed to connect to debugserver: %s",
+ error.AsCString());
+ KillDebugserverProcess();
+ return error;
+ }
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.GetStopReply(response)) {
+ SetLastStopPacket(response);
+
+ const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
+
+ if (process_arch.IsValid()) {
+ GetTarget().MergeArchitecture(process_arch);
+ } else {
+ const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture();
+ if (host_arch.IsValid())
+ GetTarget().MergeArchitecture(host_arch);
+ }
+
+ SetPrivateState(SetThreadStopInfo(response));
+
+ if (!disable_stdio) {
+ if (pty.GetPrimaryFileDescriptor() != PseudoTerminal::invalid_fd)
+ SetSTDIOFileDescriptor(pty.ReleasePrimaryFileDescriptor());
+ }
+ }
+ } else {
+ LLDB_LOGF(log, "failed to connect to debugserver: %s", error.AsCString());
+ }
+ return error;
+}
+
+Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
+ Status error;
+ // Only connect if we have a valid connect URL
+ Log *log = GetLog(GDBRLog::Process);
+
+ if (!connect_url.empty()) {
+ LLDB_LOGF(log, "ProcessGDBRemote::%s Connecting to %s", __FUNCTION__,
+ connect_url.str().c_str());
+ std::unique_ptr<ConnectionFileDescriptor> conn_up(
+ new ConnectionFileDescriptor());
+ if (conn_up) {
+ const uint32_t max_retry_count = 50;
+ uint32_t retry_count = 0;
+ while (!m_gdb_comm.IsConnected()) {
+ if (conn_up->Connect(connect_url, &error) == eConnectionStatusSuccess) {
+ m_gdb_comm.SetConnection(std::move(conn_up));
+ break;
+ }
+
+ retry_count++;
+
+ if (retry_count >= max_retry_count)
+ break;
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+ }
+ }
+
+ if (!m_gdb_comm.IsConnected()) {
+ if (error.Success())
+ error.SetErrorString("not connected to remote gdb server");
+ return error;
+ }
+
+ // 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 alright.
+ if (!m_gdb_comm.HandshakeWithServer(&error)) {
+ m_gdb_comm.Disconnect();
+ if (error.Success())
+ error.SetErrorString("not connected to remote gdb server");
+ return error;
+ }
+
+ m_gdb_comm.GetEchoSupported();
+ m_gdb_comm.GetThreadSuffixSupported();
+ m_gdb_comm.GetListThreadsInStopReplySupported();
+ m_gdb_comm.GetHostInfo();
+ m_gdb_comm.GetVContSupported('c');
+ m_gdb_comm.GetVAttachOrWaitSupported();
+ m_gdb_comm.EnableErrorStringInPacket();
+
+ // First dispatch any commands from the platform:
+ auto handle_cmds = [&] (const Args &args) -> void {
+ for (const Args::ArgEntry &entry : args) {
+ StringExtractorGDBRemote response;
+ m_gdb_comm.SendPacketAndWaitForResponse(
+ entry.c_str(), response);
+ }
+ };
+
+ PlatformSP platform_sp = GetTarget().GetPlatform();
+ if (platform_sp) {
+ handle_cmds(platform_sp->GetExtraStartupCommands());
+ }
+
+ // Then dispatch any process commands:
+ handle_cmds(GetExtraStartupCommands());
+
+ return error;
+}
+
+void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {
+ Log *log = GetLog(GDBRLog::Process);
+ BuildDynamicRegisterInfo(false);
+
+ // See if the GDB server supports qHostInfo or qProcessInfo packets. Prefer
+ // qProcessInfo as it will be more specific to our process.
+
+ const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture();
+ if (remote_process_arch.IsValid()) {
+ process_arch = remote_process_arch;
+ LLDB_LOG(log, "gdb-remote had process architecture, using {0} {1}",
+ process_arch.GetArchitectureName(),
+ process_arch.GetTriple().getTriple());
+ } else {
+ process_arch = m_gdb_comm.GetHostArchitecture();
+ LLDB_LOG(log,
+ "gdb-remote did not have process architecture, using gdb-remote "
+ "host architecture {0} {1}",
+ process_arch.GetArchitectureName(),
+ process_arch.GetTriple().getTriple());
+ }
+
+ AddressableBits addressable_bits = m_gdb_comm.GetAddressableBits();
+ SetAddressableBitMasks(addressable_bits);
+
+ if (process_arch.IsValid()) {
+ const ArchSpec &target_arch = GetTarget().GetArchitecture();
+ if (target_arch.IsValid()) {
+ LLDB_LOG(log, "analyzing target arch, currently {0} {1}",
+ target_arch.GetArchitectureName(),
+ target_arch.GetTriple().getTriple());
+
+ // If the remote host is ARM and we have apple as the vendor, then
+ // ARM executables and shared libraries can have mixed ARM
+ // architectures.
+ // You can have an armv6 executable, and if the host is armv7, then the
+ // system will load the best possible architecture for all shared
+ // libraries it has, so we really need to take the remote host
+ // architecture as our defacto architecture in this case.
+
+ if ((process_arch.GetMachine() == llvm::Triple::arm ||
+ process_arch.GetMachine() == llvm::Triple::thumb) &&
+ process_arch.GetTriple().getVendor() == llvm::Triple::Apple) {
+ GetTarget().SetArchitecture(process_arch);
+ LLDB_LOG(log,
+ "remote process is ARM/Apple, "
+ "setting target arch to {0} {1}",
+ process_arch.GetArchitectureName(),
+ process_arch.GetTriple().getTriple());
+ } else {
+ // Fill in what is missing in the triple
+ const llvm::Triple &remote_triple = process_arch.GetTriple();
+ llvm::Triple new_target_triple = target_arch.GetTriple();
+ if (new_target_triple.getVendorName().size() == 0) {
+ new_target_triple.setVendor(remote_triple.getVendor());
+
+ if (new_target_triple.getOSName().size() == 0) {
+ new_target_triple.setOS(remote_triple.getOS());
+
+ if (new_target_triple.getEnvironmentName().size() == 0)
+ new_target_triple.setEnvironment(remote_triple.getEnvironment());
+ }
+
+ ArchSpec new_target_arch = target_arch;
+ new_target_arch.SetTriple(new_target_triple);
+ GetTarget().SetArchitecture(new_target_arch);
+ }
+ }
+
+ LLDB_LOG(log,
+ "final target arch after adjustments for remote architecture: "
+ "{0} {1}",
+ target_arch.GetArchitectureName(),
+ target_arch.GetTriple().getTriple());
+ } else {
+ // The target doesn't have a valid architecture yet, set it from the
+ // architecture we got from the remote GDB server
+ GetTarget().SetArchitecture(process_arch);
+ }
+ }
+
+ // Target and Process are reasonably initailized;
+ // load any binaries we have metadata for / set load address.
+ LoadStubBinaries();
+ MaybeLoadExecutableModule();
+
+ // Find out which StructuredDataPlugins are supported by the debug monitor.
+ // These plugins transmit data over async $J packets.
+ if (StructuredData::Array *supported_packets =
+ m_gdb_comm.GetSupportedStructuredDataPlugins())
+ MapSupportedStructuredDataPlugins(*supported_packets);
+
+ // If connected to LLDB ("native-signals+"), use signal defs for
+ // the remote platform. If connected to GDB, just use the standard set.
+ if (!m_gdb_comm.UsesNativeSignals()) {
+ SetUnixSignals(std::make_shared<GDBRemoteSignals>());
+ } else {
+ PlatformSP platform_sp = GetTarget().GetPlatform();
+ if (platform_sp && platform_sp->IsConnected())
+ SetUnixSignals(platform_sp->GetUnixSignals());
+ else
+ SetUnixSignals(UnixSignals::Create(GetTarget().GetArchitecture()));
+ }
+}
+
+void ProcessGDBRemote::LoadStubBinaries() {
+ // The remote stub may know about the "main binary" in
+ // the context of a firmware debug session, and can
+ // give us a UUID and an address/slide of where the
+ // binary is loaded in memory.
+ UUID standalone_uuid;
+ addr_t standalone_value;
+ bool standalone_value_is_offset;
+ if (m_gdb_comm.GetProcessStandaloneBinary(standalone_uuid, standalone_value,
+ standalone_value_is_offset)) {
+ ModuleSP module_sp;
+
+ if (standalone_uuid.IsValid()) {
+ const bool force_symbol_search = true;
+ const bool notify = true;
+ const bool set_address_in_target = true;
+ const bool allow_memory_image_last_resort = false;
+ DynamicLoader::LoadBinaryWithUUIDAndAddress(
+ this, "", standalone_uuid, standalone_value,
+ standalone_value_is_offset, force_symbol_search, notify,
+ set_address_in_target, allow_memory_image_last_resort);
+ }
+ }
+
+ // The remote stub may know about a list of binaries to
+ // force load into the process -- a firmware type situation
+ // where multiple binaries are present in virtual memory,
+ // and we are only given the addresses of the binaries.
+ // Not intended for use with userland debugging, when we use
+ // a DynamicLoader plugin that knows how to find the loaded
+ // binaries, and will track updates as binaries are added.
+
+ std::vector<addr_t> bin_addrs = m_gdb_comm.GetProcessStandaloneBinaries();
+ if (bin_addrs.size()) {
+ UUID uuid;
+ const bool value_is_slide = false;
+ for (addr_t addr : bin_addrs) {
+ const bool notify = true;
+ // First see if this is a special platform
+ // binary that may determine the DynamicLoader and
+ // Platform to be used in this Process and Target.
+ if (GetTarget()
+ .GetDebugger()
+ .GetPlatformList()
+ .LoadPlatformBinaryAndSetup(this, addr, notify))
+ continue;
+
+ const bool force_symbol_search = true;
+ const bool set_address_in_target = true;
+ const bool allow_memory_image_last_resort = false;
+ // Second manually load this binary into the Target.
+ DynamicLoader::LoadBinaryWithUUIDAndAddress(
+ this, llvm::StringRef(), uuid, addr, value_is_slide,
+ force_symbol_search, notify, set_address_in_target,
+ allow_memory_image_last_resort);
+ }
+ }
+}
+
+void ProcessGDBRemote::MaybeLoadExecutableModule() {
+ ModuleSP module_sp = GetTarget().GetExecutableModule();
+ if (!module_sp)
+ return;
+
+ std::optional<QOffsets> offsets = m_gdb_comm.GetQOffsets();
+ if (!offsets)
+ return;
+
+ bool is_uniform =
+ size_t(llvm::count(offsets->offsets, offsets->offsets[0])) ==
+ offsets->offsets.size();
+ if (!is_uniform)
+ return; // TODO: Handle non-uniform responses.
+
+ bool changed = false;
+ module_sp->SetLoadAddress(GetTarget(), offsets->offsets[0],
+ /*value_is_offset=*/true, changed);
+ if (changed) {
+ ModuleList list;
+ list.Append(module_sp);
+ m_process->GetTarget().ModulesDidLoad(list);
+ }
+}
+
+void ProcessGDBRemote::DidLaunch() {
+ ArchSpec process_arch;
+ DidLaunchOrAttach(process_arch);
+}
+
+Status ProcessGDBRemote::DoAttachToProcessWithID(
+ lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) {
+ Log *log = GetLog(GDBRLog::Process);
+ Status error;
+
+ LLDB_LOGF(log, "ProcessGDBRemote::%s()", __FUNCTION__);
+
+ // Clear out and clean up from any current state
+ Clear();
+ if (attach_pid != LLDB_INVALID_PROCESS_ID) {
+ error = EstablishConnectionIfNeeded(attach_info);
+ if (error.Success()) {
+ m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
+
+ char packet[64];
+ const int packet_len =
+ ::snprintf(packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid);
+ SetID(attach_pid);
+ auto data_sp =
+ std::make_shared<EventDataBytes>(llvm::StringRef(packet, packet_len));
+ m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue, data_sp);
+ } else
+ SetExitStatus(-1, error.AsCString());
+ }
+
+ return error;
+}
+
+Status ProcessGDBRemote::DoAttachToProcessWithName(
+ const char *process_name, const ProcessAttachInfo &attach_info) {
+ Status error;
+ // Clear out and clean up from any current state
+ Clear();
+
+ if (process_name && process_name[0]) {
+ error = EstablishConnectionIfNeeded(attach_info);
+ if (error.Success()) {
+ StreamString packet;
+
+ m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
+
+ if (attach_info.GetWaitForLaunch()) {
+ if (!m_gdb_comm.GetVAttachOrWaitSupported()) {
+ packet.PutCString("vAttachWait");
+ } else {
+ if (attach_info.GetIgnoreExisting())
+ packet.PutCString("vAttachWait");
+ else
+ packet.PutCString("vAttachOrWait");
+ }
+ } else
+ packet.PutCString("vAttachName");
+ packet.PutChar(';');
+ packet.PutBytesAsRawHex8(process_name, strlen(process_name),
+ endian::InlHostByteOrder(),
+ endian::InlHostByteOrder());
+
+ auto data_sp = std::make_shared<EventDataBytes>(packet.GetString());
+ m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue, data_sp);
+
+ } else
+ SetExitStatus(-1, error.AsCString());
+ }
+ return error;
+}
+
+llvm::Expected<TraceSupportedResponse> ProcessGDBRemote::TraceSupported() {
+ return m_gdb_comm.SendTraceSupported(GetInterruptTimeout());
+}
+
+llvm::Error ProcessGDBRemote::TraceStop(const TraceStopRequest &request) {
+ return m_gdb_comm.SendTraceStop(request, GetInterruptTimeout());
+}
+
+llvm::Error ProcessGDBRemote::TraceStart(const llvm::json::Value &request) {
+ return m_gdb_comm.SendTraceStart(request, GetInterruptTimeout());
+}
+
+llvm::Expected<std::string>
+ProcessGDBRemote::TraceGetState(llvm::StringRef type) {
+ return m_gdb_comm.SendTraceGetState(type, GetInterruptTimeout());
+}
+
+llvm::Expected<std::vector<uint8_t>>
+ProcessGDBRemote::TraceGetBinaryData(const TraceGetBinaryDataRequest &request) {
+ return m_gdb_comm.SendTraceGetBinaryData(request, GetInterruptTimeout());
+}
+
+void ProcessGDBRemote::DidExit() {
+ // When we exit, disconnect from the GDB server communications
+ m_gdb_comm.Disconnect();
+}
+
+void ProcessGDBRemote::DidAttach(ArchSpec &process_arch) {
+ // If you can figure out what the architecture is, fill it in here.
+ process_arch.Clear();
+ DidLaunchOrAttach(process_arch);
+}
+
+Status ProcessGDBRemote::WillResume() {
+ m_continue_c_tids.clear();
+ m_continue_C_tids.clear();
+ m_continue_s_tids.clear();
+ m_continue_S_tids.clear();
+ m_jstopinfo_sp.reset();
+ m_jthreadsinfo_sp.reset();
+ return Status();
+}
+
+Status ProcessGDBRemote::DoResume() {
+ Status error;
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOGF(log, "ProcessGDBRemote::Resume()");
+
+ ListenerSP listener_sp(
+ Listener::MakeListener("gdb-remote.resume-packet-sent"));
+ if (listener_sp->StartListeningForEvents(
+ &m_gdb_comm, GDBRemoteClientBase::eBroadcastBitRunPacketSent)) {
+ listener_sp->StartListeningForEvents(
+ &m_async_broadcaster,
+ ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit);
+
+ const size_t num_threads = GetThreadList().GetSize();
+
+ StreamString continue_packet;
+ bool continue_packet_error = false;
+ if (m_gdb_comm.HasAnyVContSupport()) {
+ std::string pid_prefix;
+ if (m_gdb_comm.GetMultiprocessSupported())
+ pid_prefix = llvm::formatv("p{0:x-}.", GetID());
+
+ if (m_continue_c_tids.size() == num_threads ||
+ (m_continue_c_tids.empty() && m_continue_C_tids.empty() &&
+ m_continue_s_tids.empty() && m_continue_S_tids.empty())) {
+ // All threads are continuing
+ if (m_gdb_comm.GetMultiprocessSupported())
+ continue_packet.Format("vCont;c:{0}-1", pid_prefix);
+ else
+ continue_packet.PutCString("c");
+ } else {
+ continue_packet.PutCString("vCont");
+
+ if (!m_continue_c_tids.empty()) {
+ if (m_gdb_comm.GetVContSupported('c')) {
+ 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.Format(";c:{0}{1:x-}", pid_prefix, *t_pos);
+ } else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_C_tids.empty()) {
+ if (m_gdb_comm.GetVContSupported('C')) {
+ 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.Format(";C{0:x-2}:{1}{2:x-}", s_pos->second,
+ pid_prefix, s_pos->first);
+ } else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_s_tids.empty()) {
+ if (m_gdb_comm.GetVContSupported('s')) {
+ 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.Format(";s:{0}{1:x-}", pid_prefix, *t_pos);
+ } else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_S_tids.empty()) {
+ if (m_gdb_comm.GetVContSupported('S')) {
+ for (tid_sig_collection::const_iterator
+ s_pos = m_continue_S_tids.begin(),
+ s_end = m_continue_S_tids.end();
+ s_pos != s_end; ++s_pos)
+ continue_packet.Format(";S{0:x-2}:{1}{2:x-}", s_pos->second,
+ pid_prefix, s_pos->first);
+ } else
+ continue_packet_error = true;
+ }
+
+ if (continue_packet_error)
+ continue_packet.Clear();
+ }
+ } else
+ continue_packet_error = true;
+
+ if (continue_packet_error) {
+ // Either no vCont support, or we tried to use part of the vCont packet
+ // that wasn't supported by the remote GDB server. We need to try and
+ // make a simple packet that can do our continue
+ const size_t num_continue_c_tids = m_continue_c_tids.size();
+ const size_t num_continue_C_tids = m_continue_C_tids.size();
+ const size_t num_continue_s_tids = m_continue_s_tids.size();
+ const size_t num_continue_S_tids = m_continue_S_tids.size();
+ if (num_continue_c_tids > 0) {
+ if (num_continue_c_tids == num_threads) {
+ // All threads are resuming...
+ m_gdb_comm.SetCurrentThreadForRun(-1);
+ 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_S_tids == 0) {
+ // Only one thread is continuing
+ m_gdb_comm.SetCurrentThreadForRun(m_continue_c_tids.front());
+ 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 &&
+ 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 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 accurately with the current support...
+ if (num_continue_C_tids > 1) {
+ continue_packet_error = false;
+ for (size_t i = 1; i < m_continue_C_tids.size(); ++i) {
+ if (m_continue_C_tids[i].second != continue_signo)
+ continue_packet_error = true;
+ }
+ }
+ if (!continue_packet_error)
+ m_gdb_comm.SetCurrentThreadForRun(-1);
+ } else {
+ // Set the continue thread ID
+ continue_packet_error = false;
+ m_gdb_comm.SetCurrentThreadForRun(m_continue_C_tids.front().first);
+ }
+ if (!continue_packet_error) {
+ // Add threads continuing with the same signo...
+ continue_packet.Printf("C%2.2x", continue_signo);
+ }
+ }
+ }
+
+ if (continue_packet_error && num_continue_s_tids > 0) {
+ if (num_continue_s_tids == num_threads) {
+ // All threads are resuming...
+ m_gdb_comm.SetCurrentThreadForRun(-1);
+
+ continue_packet.PutChar('s');
+
+ continue_packet_error = false;
+ } else if (num_continue_c_tids == 0 && 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_error = false;
+ }
+ }
+
+ if (!continue_packet_error && num_continue_S_tids > 0) {
+ if (num_continue_S_tids == num_threads) {
+ const int step_signo = m_continue_S_tids.front().second;
+ // Are all threads trying to step with the same signal?
+ continue_packet_error = false;
+ if (num_continue_S_tids > 1) {
+ for (size_t i = 1; i < num_threads; ++i) {
+ if (m_continue_S_tids[i].second != step_signo)
+ continue_packet_error = true;
+ }
+ }
+ if (!continue_packet_error) {
+ // Add threads stepping with the same signo...
+ m_gdb_comm.SetCurrentThreadForRun(-1);
+ continue_packet.Printf("S%2.2x", step_signo);
+ }
+ } else if (num_continue_c_tids == 0 && num_continue_C_tids == 0 &&
+ num_continue_s_tids == 0 && num_continue_S_tids == 1) {
+ // Only one thread is stepping with signal
+ m_gdb_comm.SetCurrentThreadForRun(m_continue_S_tids.front().first);
+ continue_packet.Printf("S%2.2x", m_continue_S_tids.front().second);
+ continue_packet_error = false;
+ }
+ }
+ }
+
+ if (continue_packet_error) {
+ error.SetErrorString("can't make continue packet for this resume");
+ } else {
+ EventSP event_sp;
+ if (!m_async_thread.IsJoinable()) {
+ error.SetErrorString("Trying to resume but the async thread is dead.");
+ LLDB_LOGF(log, "ProcessGDBRemote::DoResume: Trying to resume but the "
+ "async thread is dead.");
+ return error;
+ }
+
+ auto data_sp =
+ std::make_shared<EventDataBytes>(continue_packet.GetString());
+ m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue, data_sp);
+
+ if (!listener_sp->GetEvent(event_sp, std::chrono::seconds(5))) {
+ error.SetErrorString("Resume timed out.");
+ LLDB_LOGF(log, "ProcessGDBRemote::DoResume: Resume timed out.");
+ } else if (event_sp->BroadcasterIs(&m_async_broadcaster)) {
+ error.SetErrorString("Broadcast continue, but the async thread was "
+ "killed before we got an ack back.");
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::DoResume: Broadcast continue, but the "
+ "async thread was killed before we got an ack back.");
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+
+void ProcessGDBRemote::ClearThreadIDList() {
+ std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex());
+ m_thread_ids.clear();
+ m_thread_pcs.clear();
+}
+
+size_t ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue(
+ llvm::StringRef value) {
+ m_thread_ids.clear();
+ lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID();
+ StringExtractorGDBRemote thread_ids{value};
+
+ do {
+ auto pid_tid = thread_ids.GetPidTid(pid);
+ if (pid_tid && pid_tid->first == pid) {
+ lldb::tid_t tid = pid_tid->second;
+ if (tid != LLDB_INVALID_THREAD_ID &&
+ tid != StringExtractorGDBRemote::AllProcesses)
+ m_thread_ids.push_back(tid);
+ }
+ } while (thread_ids.GetChar() == ',');
+
+ return m_thread_ids.size();
+}
+
+size_t ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue(
+ llvm::StringRef value) {
+ m_thread_pcs.clear();
+ for (llvm::StringRef x : llvm::split(value, ',')) {
+ lldb::addr_t pc;
+ if (llvm::to_integer(x, pc, 16))
+ m_thread_pcs.push_back(pc);
+ }
+ return m_thread_pcs.size();
+}
+
+bool ProcessGDBRemote::UpdateThreadIDList() {
+ std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex());
+
+ if (m_jthreadsinfo_sp) {
+ // If we have the JSON threads info, we can get the thread list from that
+ StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray();
+ if (thread_infos && thread_infos->GetSize() > 0) {
+ m_thread_ids.clear();
+ m_thread_pcs.clear();
+ thread_infos->ForEach([this](StructuredData::Object *object) -> bool {
+ StructuredData::Dictionary *thread_dict = object->GetAsDictionary();
+ if (thread_dict) {
+ // Set the thread stop info from the JSON dictionary
+ SetThreadStopInfo(thread_dict);
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid))
+ m_thread_ids.push_back(tid);
+ }
+ return true; // Keep iterating through all thread_info objects
+ });
+ }
+ if (!m_thread_ids.empty())
+ return true;
+ } else {
+ // See if we can get the thread IDs from the current stop reply packets
+ // that might contain a "threads" key/value pair
+
+ if (m_last_stop_packet) {
+ // Get the thread stop info
+ StringExtractorGDBRemote &stop_info = *m_last_stop_packet;
+ const std::string &stop_info_str = std::string(stop_info.GetStringRef());
+
+ m_thread_pcs.clear();
+ const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:");
+ if (thread_pcs_pos != std::string::npos) {
+ const size_t start = thread_pcs_pos + strlen(";thread-pcs:");
+ const size_t end = stop_info_str.find(';', start);
+ if (end != std::string::npos) {
+ std::string value = stop_info_str.substr(start, end - start);
+ UpdateThreadPCsFromStopReplyThreadsValue(value);
+ }
+ }
+
+ const size_t threads_pos = stop_info_str.find(";threads:");
+ if (threads_pos != std::string::npos) {
+ const size_t start = threads_pos + strlen(";threads:");
+ const size_t end = stop_info_str.find(';', start);
+ if (end != std::string::npos) {
+ std::string value = stop_info_str.substr(start, end - start);
+ if (UpdateThreadIDsFromStopReplyThreadsValue(value))
+ return true;
+ }
+ }
+ }
+ }
+
+ bool sequence_mutex_unavailable = false;
+ m_gdb_comm.GetCurrentThreadIDs(m_thread_ids, sequence_mutex_unavailable);
+ if (sequence_mutex_unavailable) {
+ return false; // We just didn't get the list
+ }
+ return true;
+}
+
+bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log = GetLog(GDBRLog::Thread);
+ LLDB_LOGV(log, "pid = {0}", 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.
+ if (num_thread_ids == 0) {
+ if (!UpdateThreadIDList())
+ return false;
+ num_thread_ids = m_thread_ids.size();
+ }
+
+ ThreadList old_thread_list_copy(old_thread_list);
+ if (num_thread_ids > 0) {
+ for (size_t i = 0; i < num_thread_ids; ++i) {
+ tid_t tid = m_thread_ids[i];
+ ThreadSP thread_sp(
+ old_thread_list_copy.RemoveThreadByProtocolID(tid, false));
+ if (!thread_sp) {
+ thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid);
+ LLDB_LOGV(log, "Making new thread: {0} for thread ID: {1:x}.",
+ thread_sp.get(), thread_sp->GetID());
+ } else {
+ LLDB_LOGV(log, "Found old thread: {0} for thread ID: {1:x}.",
+ thread_sp.get(), thread_sp->GetID());
+ }
+
+ SetThreadPc(thread_sp, i);
+ new_thread_list.AddThreadSortedByIndexID(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);
+ for (size_t i = 0; i < old_num_thread_ids; i++) {
+ ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false));
+ if (old_thread_sp) {
+ lldb::tid_t old_thread_id = old_thread_sp->GetProtocolID();
+ m_thread_id_to_index_id_map.erase(old_thread_id);
+ }
+ }
+
+ return true;
+}
+
+void ProcessGDBRemote::SetThreadPc(const ThreadSP &thread_sp, uint64_t index) {
+ if (m_thread_ids.size() == m_thread_pcs.size() && thread_sp.get() &&
+ GetByteOrder() != eByteOrderInvalid) {
+ ThreadGDBRemote *gdb_thread =
+ static_cast<ThreadGDBRemote *>(thread_sp.get());
+ RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
+ if (reg_ctx_sp) {
+ uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ if (pc_regnum != LLDB_INVALID_REGNUM) {
+ gdb_thread->PrivateSetRegisterValue(pc_regnum, m_thread_pcs[index]);
+ }
+ }
+ }
+}
+
+bool ProcessGDBRemote::GetThreadStopInfoFromJSON(
+ ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp) {
+ // See if we got thread stop infos for all threads via the "jThreadsInfo"
+ // packet
+ if (thread_infos_sp) {
+ StructuredData::Array *thread_infos = thread_infos_sp->GetAsArray();
+ if (thread_infos) {
+ lldb::tid_t tid;
+ const size_t n = thread_infos->GetSize();
+ for (size_t i = 0; i < n; ++i) {
+ StructuredData::Dictionary *thread_dict =
+ thread_infos->GetItemAtIndex(i)->GetAsDictionary();
+ if (thread_dict) {
+ if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>(
+ "tid", tid, LLDB_INVALID_THREAD_ID)) {
+ if (tid == thread->GetID())
+ return (bool)SetThreadStopInfo(thread_dict);
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool ProcessGDBRemote::CalculateThreadStopInfo(ThreadGDBRemote *thread) {
+ // See if we got thread stop infos for all threads via the "jThreadsInfo"
+ // packet
+ if (GetThreadStopInfoFromJSON(thread, m_jthreadsinfo_sp))
+ return true;
+
+ // See if we got thread stop info for any threads valid stop info reasons
+ // threads via the "jstopinfo" packet stop reply packet key/value pair?
+ if (m_jstopinfo_sp) {
+ // If we have "jstopinfo" then we have stop descriptions for all threads
+ // that have stop reasons, and if there is no entry for a thread, then it
+ // has no stop reason.
+ thread->GetRegisterContext()->InvalidateIfNeeded(true);
+ if (!GetThreadStopInfoFromJSON(thread, m_jstopinfo_sp)) {
+ // If a thread is stopped at a breakpoint site, set that as the stop
+ // reason even if it hasn't executed the breakpoint instruction yet.
+ // We will silently step over the breakpoint when we resume execution
+ // and miss the fact that this thread hit the breakpoint.
+ const size_t num_thread_ids = m_thread_ids.size();
+ for (size_t i = 0; i < num_thread_ids; i++) {
+ if (m_thread_ids[i] == thread->GetID() && m_thread_pcs.size() > i) {
+ addr_t pc = m_thread_pcs[i];
+ lldb::BreakpointSiteSP bp_site_sp =
+ thread->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp) {
+ if (bp_site_sp->ValidForThisThread(*thread)) {
+ thread->SetStopInfo(
+ StopInfo::CreateStopReasonWithBreakpointSiteID(
+ *thread, bp_site_sp->GetID()));
+ return true;
+ }
+ }
+ }
+ }
+ thread->SetStopInfo(StopInfoSP());
+ }
+ return true;
+ }
+
+ // Fall back to using the qThreadStopInfo packet
+ StringExtractorGDBRemote stop_packet;
+ if (GetGDBRemote().GetThreadStopInfo(thread->GetProtocolID(), stop_packet))
+ return SetThreadStopInfo(stop_packet) == eStateStopped;
+ return false;
+}
+
+void ProcessGDBRemote::ParseExpeditedRegisters(
+ ExpeditedRegisterMap &expedited_register_map, ThreadSP thread_sp) {
+ ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread_sp.get());
+ RegisterContextSP gdb_reg_ctx_sp(gdb_thread->GetRegisterContext());
+
+ for (const auto &pair : expedited_register_map) {
+ StringExtractor reg_value_extractor(pair.second);
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(reg_value_extractor.GetStringRef().size() / 2, 0));
+ reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc');
+ uint32_t lldb_regnum = gdb_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(
+ eRegisterKindProcessPlugin, pair.first);
+ gdb_thread->PrivateSetRegisterValue(lldb_regnum, buffer_sp->GetData());
+ }
+}
+
+ThreadSP ProcessGDBRemote::SetThreadStopInfo(
+ lldb::tid_t tid, ExpeditedRegisterMap &expedited_register_map,
+ uint8_t signo, const std::string &thread_name, const std::string &reason,
+ const std::string &description, uint32_t exc_type,
+ const std::vector<addr_t> &exc_data, addr_t thread_dispatch_qaddr,
+ bool queue_vars_valid, // Set to true if queue_name, queue_kind and
+ // queue_serial are valid
+ LazyBool associated_with_dispatch_queue, addr_t dispatch_queue_t,
+ std::string &queue_name, QueueKind queue_kind, uint64_t queue_serial) {
+
+ if (tid == LLDB_INVALID_THREAD_ID)
+ return nullptr;
+
+ ThreadSP thread_sp;
+ // Scope for "locker" below
+ {
+ // m_thread_list_real does have its own mutex, but we need to hold onto the
+ // mutex between the call to m_thread_list_real.FindThreadByID(...) and the
+ // m_thread_list_real.AddThread(...) so it doesn't change on us
+ std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex());
+ thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false);
+
+ if (!thread_sp) {
+ // Create the thread if we need to
+ thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid);
+ m_thread_list_real.AddThread(thread_sp);
+ }
+ }
+
+ ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread_sp.get());
+ RegisterContextSP reg_ctx_sp(gdb_thread->GetRegisterContext());
+
+ reg_ctx_sp->InvalidateIfNeeded(true);
+
+ auto iter = std::find(m_thread_ids.begin(), m_thread_ids.end(), tid);
+ if (iter != m_thread_ids.end())
+ SetThreadPc(thread_sp, iter - m_thread_ids.begin());
+
+ ParseExpeditedRegisters(expedited_register_map, thread_sp);
+
+ if (reg_ctx_sp->ReconfigureRegisterInfo()) {
+ // Now we have changed the offsets of all the registers, so the values
+ // will be corrupted.
+ reg_ctx_sp->InvalidateAllRegisters();
+ // Expedited registers values will never contain registers that would be
+ // resized by a reconfigure. So we are safe to continue using these
+ // values.
+ ParseExpeditedRegisters(expedited_register_map, thread_sp);
+ }
+
+ thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str());
+
+ gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr);
+ // Check if the GDB server was able to provide the queue name, kind and serial
+ // number
+ if (queue_vars_valid)
+ gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial,
+ dispatch_queue_t, associated_with_dispatch_queue);
+ else
+ gdb_thread->ClearQueueInfo();
+
+ gdb_thread->SetAssociatedWithLibdispatchQueue(associated_with_dispatch_queue);
+
+ if (dispatch_queue_t != LLDB_INVALID_ADDRESS)
+ gdb_thread->SetQueueLibdispatchQueueAddress(dispatch_queue_t);
+
+ // Make sure we update our thread stop reason just once, but don't overwrite
+ // the stop info for threads that haven't moved:
+ StopInfoSP current_stop_info_sp = thread_sp->GetPrivateStopInfo(false);
+ if (thread_sp->GetTemporaryResumeState() == eStateSuspended &&
+ current_stop_info_sp) {
+ thread_sp->SetStopInfo(current_stop_info_sp);
+ return thread_sp;
+ }
+
+ if (!thread_sp->StopInfoIsUpToDate()) {
+ thread_sp->SetStopInfo(StopInfoSP());
+ // If there's a memory thread backed by this thread, we need to use it to
+ // calculate StopInfo.
+ if (ThreadSP memory_thread_sp = m_thread_list.GetBackingThread(thread_sp))
+ thread_sp = memory_thread_sp;
+
+ if (exc_type != 0) {
+ const size_t exc_data_size = exc_data.size();
+
+ thread_sp->SetStopInfo(
+ StopInfoMachException::CreateStopReasonWithMachException(
+ *thread_sp, exc_type, exc_data_size,
+ exc_data_size >= 1 ? exc_data[0] : 0,
+ exc_data_size >= 2 ? exc_data[1] : 0,
+ exc_data_size >= 3 ? exc_data[2] : 0));
+ } else {
+ bool handled = false;
+ bool did_exec = false;
+ // debugserver can send reason = "none" which is equivalent
+ // to no reason.
+ if (!reason.empty() && reason != "none") {
+ if (reason == "trace") {
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC();
+ lldb::BreakpointSiteSP bp_site_sp =
+ thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(
+ pc);
+
+ // If the current pc is a breakpoint site then the StopInfo should be
+ // set to Breakpoint Otherwise, it will be set to Trace.
+ if (bp_site_sp && bp_site_sp->ValidForThisThread(*thread_sp)) {
+ thread_sp->SetStopInfo(
+ StopInfo::CreateStopReasonWithBreakpointSiteID(
+ *thread_sp, bp_site_sp->GetID()));
+ } else
+ thread_sp->SetStopInfo(
+ StopInfo::CreateStopReasonToTrace(*thread_sp));
+ handled = true;
+ } else if (reason == "breakpoint") {
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC();
+ lldb::BreakpointSiteSP bp_site_sp =
+ thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(
+ pc);
+ if (bp_site_sp) {
+ // If the breakpoint is for this thread, then we'll report the hit,
+ // but if it is for another thread, we can just report no reason.
+ // We don't need to worry about stepping over the breakpoint here,
+ // that will be taken care of when the thread resumes and notices
+ // that there's a breakpoint under the pc.
+ handled = true;
+ if (bp_site_sp->ValidForThisThread(*thread_sp)) {
+ thread_sp->SetStopInfo(
+ StopInfo::CreateStopReasonWithBreakpointSiteID(
+ *thread_sp, bp_site_sp->GetID()));
+ } else {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo(invalid_stop_info_sp);
+ }
+ }
+ } else if (reason == "trap") {
+ // Let the trap just use the standard signal stop reason below...
+ } else if (reason == "watchpoint") {
+ // We will have between 1 and 3 fields in the description.
+ //
+ // \a wp_addr which is the original start address that
+ // lldb requested be watched, or an address that the
+ // hardware reported. This address should be within the
+ // range of a currently active watchpoint region - lldb
+ // should be able to find a watchpoint with this address.
+ //
+ // \a wp_index is the hardware watchpoint register number.
+ //
+ // \a wp_hit_addr is the actual address reported by the hardware,
+ // which may be outside the range of a region we are watching.
+ //
+ // On MIPS, we may get a false watchpoint exception where an
+ // access to the same 8 byte granule as a watchpoint will trigger,
+ // even if the access was not within the range of the watched
+ // region. When we get a \a wp_hit_addr outside the range of any
+ // set watchpoint, continue execution without making it visible to
+ // the user.
+ //
+ // On ARM, a related issue where a large access that starts
+ // before the watched region (and extends into the watched
+ // region) may report a hit address before the watched region.
+ // lldb will not find the "nearest" watchpoint to
+ // disable/step/re-enable it, so one of the valid watchpoint
+ // addresses should be provided as \a wp_addr.
+ StringExtractor desc_extractor(description.c_str());
+ // FIXME NativeThreadLinux::SetStoppedByWatchpoint sends this
+ // up as
+ // <address within wp range> <wp hw index> <actual accessed addr>
+ // but this is not reading the <wp hw index>. Seems like it
+ // wouldn't work on MIPS, where that third field is important.
+ addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
+ addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
+ watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
+ bool silently_continue = false;
+ WatchpointResourceSP wp_resource_sp;
+ if (wp_hit_addr != LLDB_INVALID_ADDRESS) {
+ wp_resource_sp =
+ m_watchpoint_resource_list.FindByAddress(wp_hit_addr);
+ // On MIPS, \a wp_hit_addr outside the range of a watched
+ // region means we should silently continue, it is a false hit.
+ ArchSpec::Core core = GetTarget().GetArchitecture().GetCore();
+ if (!wp_resource_sp && core >= ArchSpec::kCore_mips_first &&
+ core <= ArchSpec::kCore_mips_last)
+ silently_continue = true;
+ }
+ if (!wp_resource_sp && wp_addr != LLDB_INVALID_ADDRESS)
+ wp_resource_sp = m_watchpoint_resource_list.FindByAddress(wp_addr);
+ if (!wp_resource_sp) {
+ Log *log(GetLog(GDBRLog::Watchpoints));
+ LLDB_LOGF(log, "failed to find watchpoint");
+ watch_id = LLDB_INVALID_SITE_ID;
+ } else {
+ // LWP_TODO: This is hardcoding a single Watchpoint in a
+ // Resource, need to add
+ // StopInfo::CreateStopReasonWithWatchpointResource which
+ // represents all watchpoints that were tripped at this stop.
+ watch_id = wp_resource_sp->GetConstituentAtIndex(0)->GetID();
+ }
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID(
+ *thread_sp, watch_id, silently_continue));
+ handled = true;
+ } else if (reason == "exception") {
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException(
+ *thread_sp, description.c_str()));
+ handled = true;
+ } else if (reason == "exec") {
+ did_exec = true;
+ thread_sp->SetStopInfo(
+ StopInfo::CreateStopReasonWithExec(*thread_sp));
+ handled = true;
+ } else if (reason == "processor trace") {
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonProcessorTrace(
+ *thread_sp, description.c_str()));
+ } else if (reason == "fork") {
+ StringExtractor desc_extractor(description.c_str());
+ lldb::pid_t child_pid =
+ desc_extractor.GetU64(LLDB_INVALID_PROCESS_ID);
+ lldb::tid_t child_tid = desc_extractor.GetU64(LLDB_INVALID_THREAD_ID);
+ thread_sp->SetStopInfo(
+ StopInfo::CreateStopReasonFork(*thread_sp, child_pid, child_tid));
+ handled = true;
+ } else if (reason == "vfork") {
+ StringExtractor desc_extractor(description.c_str());
+ lldb::pid_t child_pid =
+ desc_extractor.GetU64(LLDB_INVALID_PROCESS_ID);
+ lldb::tid_t child_tid = desc_extractor.GetU64(LLDB_INVALID_THREAD_ID);
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonVFork(
+ *thread_sp, child_pid, child_tid));
+ handled = true;
+ } else if (reason == "vforkdone") {
+ thread_sp->SetStopInfo(
+ StopInfo::CreateStopReasonVForkDone(*thread_sp));
+ handled = true;
+ }
+ } else if (!signo) {
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC();
+ lldb::BreakpointSiteSP bp_site_sp =
+ thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+
+ // If a thread is stopped at a breakpoint site, set that as the stop
+ // reason even if it hasn't executed the breakpoint instruction yet.
+ // We will silently step over the breakpoint when we resume execution
+ // and miss the fact that this thread hit the breakpoint.
+ if (bp_site_sp && bp_site_sp->ValidForThisThread(*thread_sp)) {
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(
+ *thread_sp, bp_site_sp->GetID()));
+ handled = true;
+ }
+ }
+
+ if (!handled && signo && !did_exec) {
+ if (signo == SIGTRAP) {
+ // Currently we are going to assume SIGTRAP means we are either
+ // hitting a breakpoint or hardware single stepping.
+ handled = true;
+ addr_t pc =
+ thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset;
+ lldb::BreakpointSiteSP bp_site_sp =
+ thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(
+ pc);
+
+ if (bp_site_sp) {
+ // If the breakpoint is for this thread, then we'll report the hit,
+ // but if it is for another thread, we can just report no reason.
+ // We don't need to worry about stepping over the breakpoint here,
+ // that will be taken care of when the thread resumes and notices
+ // that there's a breakpoint under the pc.
+ if (bp_site_sp->ValidForThisThread(*thread_sp)) {
+ if (m_breakpoint_pc_offset != 0)
+ thread_sp->GetRegisterContext()->SetPC(pc);
+ thread_sp->SetStopInfo(
+ StopInfo::CreateStopReasonWithBreakpointSiteID(
+ *thread_sp, bp_site_sp->GetID()));
+ } else {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo(invalid_stop_info_sp);
+ }
+ } else {
+ // If we were stepping then assume the stop was the result of the
+ // trace. If we were not stepping then report the SIGTRAP.
+ // FIXME: We are still missing the case where we single step over a
+ // trap instruction.
+ if (thread_sp->GetTemporaryResumeState() == eStateStepping)
+ thread_sp->SetStopInfo(
+ StopInfo::CreateStopReasonToTrace(*thread_sp));
+ else
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithSignal(
+ *thread_sp, signo, description.c_str()));
+ }
+ }
+ if (!handled)
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithSignal(
+ *thread_sp, signo, description.c_str()));
+ }
+
+ if (!description.empty()) {
+ lldb::StopInfoSP stop_info_sp(thread_sp->GetStopInfo());
+ if (stop_info_sp) {
+ const char *stop_info_desc = stop_info_sp->GetDescription();
+ if (!stop_info_desc || !stop_info_desc[0])
+ stop_info_sp->SetDescription(description.c_str());
+ } else {
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException(
+ *thread_sp, description.c_str()));
+ }
+ }
+ }
+ }
+ return thread_sp;
+}
+
+lldb::ThreadSP
+ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
+ static constexpr llvm::StringLiteral g_key_tid("tid");
+ static constexpr llvm::StringLiteral g_key_name("name");
+ static constexpr llvm::StringLiteral g_key_reason("reason");
+ static constexpr llvm::StringLiteral g_key_metype("metype");
+ static constexpr llvm::StringLiteral g_key_medata("medata");
+ static constexpr llvm::StringLiteral g_key_qaddr("qaddr");
+ static constexpr llvm::StringLiteral g_key_dispatch_queue_t(
+ "dispatch_queue_t");
+ static constexpr llvm::StringLiteral g_key_associated_with_dispatch_queue(
+ "associated_with_dispatch_queue");
+ static constexpr llvm::StringLiteral g_key_queue_name("qname");
+ static constexpr llvm::StringLiteral g_key_queue_kind("qkind");
+ static constexpr llvm::StringLiteral g_key_queue_serial_number("qserialnum");
+ static constexpr llvm::StringLiteral g_key_registers("registers");
+ static constexpr llvm::StringLiteral g_key_memory("memory");
+ static constexpr llvm::StringLiteral g_key_description("description");
+ static constexpr llvm::StringLiteral g_key_signal("signal");
+
+ // Stop with signal and thread info
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ uint8_t signo = 0;
+ std::string value;
+ std::string thread_name;
+ std::string reason;
+ std::string description;
+ uint32_t exc_type = 0;
+ std::vector<addr_t> exc_data;
+ addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
+ ExpeditedRegisterMap expedited_register_map;
+ bool queue_vars_valid = false;
+ addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS;
+ LazyBool associated_with_dispatch_queue = eLazyBoolCalculate;
+ std::string queue_name;
+ QueueKind queue_kind = eQueueKindUnknown;
+ uint64_t queue_serial_number = 0;
+ // Iterate through all of the thread dictionary key/value pairs from the
+ // structured data dictionary
+
+ // FIXME: we're silently ignoring invalid data here
+ thread_dict->ForEach([this, &tid, &expedited_register_map, &thread_name,
+ &signo, &reason, &description, &exc_type, &exc_data,
+ &thread_dispatch_qaddr, &queue_vars_valid,
+ &associated_with_dispatch_queue, &dispatch_queue_t,
+ &queue_name, &queue_kind, &queue_serial_number](
+ llvm::StringRef key,
+ StructuredData::Object *object) -> bool {
+ if (key == g_key_tid) {
+ // thread in big endian hex
+ tid = object->GetUnsignedIntegerValue(LLDB_INVALID_THREAD_ID);
+ } else if (key == g_key_metype) {
+ // exception type in big endian hex
+ exc_type = object->GetUnsignedIntegerValue(0);
+ } else if (key == g_key_medata) {
+ // exception data in big endian hex
+ StructuredData::Array *array = object->GetAsArray();
+ if (array) {
+ array->ForEach([&exc_data](StructuredData::Object *object) -> bool {
+ exc_data.push_back(object->GetUnsignedIntegerValue());
+ return true; // Keep iterating through all array items
+ });
+ }
+ } else if (key == g_key_name) {
+ thread_name = std::string(object->GetStringValue());
+ } else if (key == g_key_qaddr) {
+ thread_dispatch_qaddr =
+ object->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS);
+ } else if (key == g_key_queue_name) {
+ queue_vars_valid = true;
+ queue_name = std::string(object->GetStringValue());
+ } else if (key == g_key_queue_kind) {
+ std::string queue_kind_str = std::string(object->GetStringValue());
+ if (queue_kind_str == "serial") {
+ queue_vars_valid = true;
+ queue_kind = eQueueKindSerial;
+ } else if (queue_kind_str == "concurrent") {
+ queue_vars_valid = true;
+ queue_kind = eQueueKindConcurrent;
+ }
+ } else if (key == g_key_queue_serial_number) {
+ queue_serial_number = object->GetUnsignedIntegerValue(0);
+ if (queue_serial_number != 0)
+ queue_vars_valid = true;
+ } else if (key == g_key_dispatch_queue_t) {
+ dispatch_queue_t = object->GetUnsignedIntegerValue(0);
+ if (dispatch_queue_t != 0 && dispatch_queue_t != LLDB_INVALID_ADDRESS)
+ queue_vars_valid = true;
+ } else if (key == g_key_associated_with_dispatch_queue) {
+ queue_vars_valid = true;
+ bool associated = object->GetBooleanValue();
+ if (associated)
+ associated_with_dispatch_queue = eLazyBoolYes;
+ else
+ associated_with_dispatch_queue = eLazyBoolNo;
+ } else if (key == g_key_reason) {
+ reason = std::string(object->GetStringValue());
+ } else if (key == g_key_description) {
+ description = std::string(object->GetStringValue());
+ } else if (key == g_key_registers) {
+ StructuredData::Dictionary *registers_dict = object->GetAsDictionary();
+
+ if (registers_dict) {
+ registers_dict->ForEach(
+ [&expedited_register_map](llvm::StringRef key,
+ StructuredData::Object *object) -> bool {
+ uint32_t reg;
+ if (llvm::to_integer(key, reg))
+ expedited_register_map[reg] =
+ std::string(object->GetStringValue());
+ return true; // Keep iterating through all array items
+ });
+ }
+ } else if (key == g_key_memory) {
+ StructuredData::Array *array = object->GetAsArray();
+ if (array) {
+ array->ForEach([this](StructuredData::Object *object) -> bool {
+ StructuredData::Dictionary *mem_cache_dict =
+ object->GetAsDictionary();
+ if (mem_cache_dict) {
+ lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS;
+ if (mem_cache_dict->GetValueForKeyAsInteger<lldb::addr_t>(
+ "address", mem_cache_addr)) {
+ if (mem_cache_addr != LLDB_INVALID_ADDRESS) {
+ llvm::StringRef str;
+ if (mem_cache_dict->GetValueForKeyAsString("bytes", str)) {
+ StringExtractor bytes(str);
+ bytes.SetFilePos(0);
+
+ const size_t byte_size = bytes.GetStringRef().size() / 2;
+ WritableDataBufferSP data_buffer_sp(
+ new DataBufferHeap(byte_size, 0));
+ const size_t bytes_copied =
+ bytes.GetHexBytes(data_buffer_sp->GetData(), 0);
+ if (bytes_copied == byte_size)
+ m_memory_cache.AddL1CacheData(mem_cache_addr,
+ data_buffer_sp);
+ }
+ }
+ }
+ }
+ return true; // Keep iterating through all array items
+ });
+ }
+
+ } else if (key == g_key_signal)
+ signo = object->GetUnsignedIntegerValue(LLDB_INVALID_SIGNAL_NUMBER);
+ return true; // Keep iterating through all dictionary key/value pairs
+ });
+
+ return SetThreadStopInfo(tid, expedited_register_map, signo, thread_name,
+ reason, description, exc_type, exc_data,
+ thread_dispatch_qaddr, queue_vars_valid,
+ associated_with_dispatch_queue, dispatch_queue_t,
+ queue_name, queue_kind, queue_serial_number);
+}
+
+StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
+ lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID();
+ stop_packet.SetFilePos(0);
+ const char stop_type = stop_packet.GetChar();
+ switch (stop_type) {
+ case 'T':
+ case 'S': {
+ // This is a bit of a hack, but it is required. If we did exec, we need to
+ // clear our thread lists and also know to rebuild our dynamic register
+ // info before we lookup and threads and populate the expedited register
+ // values so we need to know this right away so we can cleanup and update
+ // our registers.
+ const uint32_t stop_id = GetStopID();
+ if (stop_id == 0) {
+ // Our first stop, make sure we have a process ID, and also make sure we
+ // know about our registers
+ if (GetID() == LLDB_INVALID_PROCESS_ID && pid != LLDB_INVALID_PROCESS_ID)
+ SetID(pid);
+ BuildDynamicRegisterInfo(true);
+ }
+ // Stop with signal and thread info
+ lldb::pid_t stop_pid = LLDB_INVALID_PROCESS_ID;
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ const uint8_t signo = stop_packet.GetHexU8();
+ llvm::StringRef key;
+ llvm::StringRef value;
+ std::string thread_name;
+ std::string reason;
+ std::string description;
+ uint32_t exc_type = 0;
+ std::vector<addr_t> exc_data;
+ addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
+ bool queue_vars_valid =
+ false; // says if locals below that start with "queue_" are valid
+ addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS;
+ LazyBool associated_with_dispatch_queue = eLazyBoolCalculate;
+ std::string queue_name;
+ QueueKind queue_kind = eQueueKindUnknown;
+ uint64_t queue_serial_number = 0;
+ ExpeditedRegisterMap expedited_register_map;
+ AddressableBits addressable_bits;
+ while (stop_packet.GetNameColonValue(key, value)) {
+ if (key.compare("metype") == 0) {
+ // exception type in big endian hex
+ value.getAsInteger(16, exc_type);
+ } else if (key.compare("medata") == 0) {
+ // exception data in big endian hex
+ uint64_t x;
+ value.getAsInteger(16, x);
+ exc_data.push_back(x);
+ } else if (key.compare("thread") == 0) {
+ // thread-id
+ StringExtractorGDBRemote thread_id{value};
+ auto pid_tid = thread_id.GetPidTid(pid);
+ if (pid_tid) {
+ stop_pid = pid_tid->first;
+ tid = pid_tid->second;
+ } else
+ tid = LLDB_INVALID_THREAD_ID;
+ } else if (key.compare("threads") == 0) {
+ std::lock_guard<std::recursive_mutex> guard(
+ m_thread_list_real.GetMutex());
+ UpdateThreadIDsFromStopReplyThreadsValue(value);
+ } else if (key.compare("thread-pcs") == 0) {
+ m_thread_pcs.clear();
+ // A comma separated list of all threads in the current
+ // process that includes the thread for this stop reply packet
+ lldb::addr_t pc;
+ while (!value.empty()) {
+ llvm::StringRef pc_str;
+ std::tie(pc_str, value) = value.split(',');
+ if (pc_str.getAsInteger(16, pc))
+ pc = LLDB_INVALID_ADDRESS;
+ m_thread_pcs.push_back(pc);
+ }
+ } else if (key.compare("jstopinfo") == 0) {
+ StringExtractor json_extractor(value);
+ std::string json;
+ // Now convert the HEX bytes into a string value
+ json_extractor.GetHexByteString(json);
+
+ // This JSON contains thread IDs and thread stop info for all threads.
+ // It doesn't contain expedited registers, memory or queue info.
+ m_jstopinfo_sp = StructuredData::ParseJSON(json);
+ } else if (key.compare("hexname") == 0) {
+ StringExtractor name_extractor(value);
+ std::string name;
+ // Now convert the HEX bytes into a string value
+ name_extractor.GetHexByteString(thread_name);
+ } else if (key.compare("name") == 0) {
+ thread_name = std::string(value);
+ } else if (key.compare("qaddr") == 0) {
+ value.getAsInteger(16, thread_dispatch_qaddr);
+ } else if (key.compare("dispatch_queue_t") == 0) {
+ queue_vars_valid = true;
+ value.getAsInteger(16, dispatch_queue_t);
+ } else if (key.compare("qname") == 0) {
+ queue_vars_valid = true;
+ StringExtractor name_extractor(value);
+ // Now convert the HEX bytes into a string value
+ name_extractor.GetHexByteString(queue_name);
+ } else if (key.compare("qkind") == 0) {
+ queue_kind = llvm::StringSwitch<QueueKind>(value)
+ .Case("serial", eQueueKindSerial)
+ .Case("concurrent", eQueueKindConcurrent)
+ .Default(eQueueKindUnknown);
+ queue_vars_valid = queue_kind != eQueueKindUnknown;
+ } else if (key.compare("qserialnum") == 0) {
+ if (!value.getAsInteger(0, queue_serial_number))
+ queue_vars_valid = true;
+ } else if (key.compare("reason") == 0) {
+ reason = std::string(value);
+ } else if (key.compare("description") == 0) {
+ StringExtractor desc_extractor(value);
+ // Now convert the HEX bytes into a string value
+ desc_extractor.GetHexByteString(description);
+ } else if (key.compare("memory") == 0) {
+ // Expedited memory. GDB servers can choose to send back expedited
+ // memory that can populate the L1 memory cache in the process so that
+ // things like the frame pointer backchain can be expedited. This will
+ // help stack backtracing be more efficient by not having to send as
+ // many memory read requests down the remote GDB server.
+
+ // Key/value pair format: memory:<addr>=<bytes>;
+ // <addr> is a number whose base will be interpreted by the prefix:
+ // "0x[0-9a-fA-F]+" for hex
+ // "0[0-7]+" for octal
+ // "[1-9]+" for decimal
+ // <bytes> is native endian ASCII hex bytes just like the register
+ // values
+ llvm::StringRef addr_str, bytes_str;
+ std::tie(addr_str, bytes_str) = value.split('=');
+ if (!addr_str.empty() && !bytes_str.empty()) {
+ lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS;
+ if (!addr_str.getAsInteger(0, mem_cache_addr)) {
+ StringExtractor bytes(bytes_str);
+ const size_t byte_size = bytes.GetBytesLeft() / 2;
+ WritableDataBufferSP data_buffer_sp(
+ new DataBufferHeap(byte_size, 0));
+ const size_t bytes_copied =
+ bytes.GetHexBytes(data_buffer_sp->GetData(), 0);
+ if (bytes_copied == byte_size)
+ m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp);
+ }
+ }
+ } else if (key.compare("watch") == 0 || key.compare("rwatch") == 0 ||
+ key.compare("awatch") == 0) {
+ // Support standard GDB remote stop reply packet 'TAAwatch:addr'
+ lldb::addr_t wp_addr = LLDB_INVALID_ADDRESS;
+ value.getAsInteger(16, wp_addr);
+
+ WatchpointResourceSP wp_resource_sp =
+ m_watchpoint_resource_list.FindByAddress(wp_addr);
+
+ // Rewrite gdb standard watch/rwatch/awatch to
+ // "reason:watchpoint" + "description:ADDR",
+ // which is parsed in SetThreadStopInfo.
+ reason = "watchpoint";
+ StreamString ostr;
+ ostr.Printf("%" PRIu64, wp_addr);
+ description = std::string(ostr.GetString());
+ } else if (key.compare("library") == 0) {
+ auto error = LoadModules();
+ if (error) {
+ Log *log(GetLog(GDBRLog::Process));
+ LLDB_LOG_ERROR(log, std::move(error), "Failed to load modules: {0}");
+ }
+ } else if (key.compare("fork") == 0 || key.compare("vfork") == 0) {
+ // fork includes child pid/tid in thread-id format
+ StringExtractorGDBRemote thread_id{value};
+ auto pid_tid = thread_id.GetPidTid(LLDB_INVALID_PROCESS_ID);
+ if (!pid_tid) {
+ Log *log(GetLog(GDBRLog::Process));
+ LLDB_LOG(log, "Invalid PID/TID to fork: {0}", value);
+ pid_tid = {{LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID}};
+ }
+
+ reason = key.str();
+ StreamString ostr;
+ ostr.Printf("%" PRIu64 " %" PRIu64, pid_tid->first, pid_tid->second);
+ description = std::string(ostr.GetString());
+ } else if (key.compare("addressing_bits") == 0) {
+ uint64_t addressing_bits;
+ if (!value.getAsInteger(0, addressing_bits)) {
+ addressable_bits.SetAddressableBits(addressing_bits);
+ }
+ } else if (key.compare("low_mem_addressing_bits") == 0) {
+ uint64_t addressing_bits;
+ if (!value.getAsInteger(0, addressing_bits)) {
+ addressable_bits.SetLowmemAddressableBits(addressing_bits);
+ }
+ } else if (key.compare("high_mem_addressing_bits") == 0) {
+ uint64_t addressing_bits;
+ if (!value.getAsInteger(0, addressing_bits)) {
+ addressable_bits.SetHighmemAddressableBits(addressing_bits);
+ }
+ } else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) {
+ uint32_t reg = UINT32_MAX;
+ if (!key.getAsInteger(16, reg))
+ expedited_register_map[reg] = std::string(std::move(value));
+ }
+ }
+
+ if (stop_pid != LLDB_INVALID_PROCESS_ID && stop_pid != pid) {
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOG(log,
+ "Received stop for incorrect PID = {0} (inferior PID = {1})",
+ stop_pid, pid);
+ return eStateInvalid;
+ }
+
+ 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
+ // thread information. So update the thread list and choose the first
+ // one.
+ UpdateThreadIDList();
+
+ if (!m_thread_ids.empty()) {
+ tid = m_thread_ids.front();
+ }
+ }
+
+ SetAddressableBitMasks(addressable_bits);
+
+ ThreadSP thread_sp = SetThreadStopInfo(
+ tid, expedited_register_map, signo, thread_name, reason, description,
+ exc_type, exc_data, thread_dispatch_qaddr, queue_vars_valid,
+ associated_with_dispatch_queue, dispatch_queue_t, queue_name,
+ queue_kind, queue_serial_number);
+
+ return eStateStopped;
+ } break;
+
+ case 'W':
+ case 'X':
+ // process exited
+ return eStateExited;
+
+ default:
+ break;
+ }
+ return eStateInvalid;
+}
+
+void ProcessGDBRemote::RefreshStateAfterStop() {
+ std::lock_guard<std::recursive_mutex> guard(m_thread_list_real.GetMutex());
+
+ m_thread_ids.clear();
+ m_thread_pcs.clear();
+
+ // Set the thread stop info. It might have a "threads" key whose value is a
+ // list of all thread IDs in the current process, so m_thread_ids might get
+ // set.
+ // Check to see if SetThreadStopInfo() filled in m_thread_ids?
+ if (m_thread_ids.empty()) {
+ // No, we need to fetch the thread list manually
+ UpdateThreadIDList();
+ }
+
+ // We might set some stop info's so make sure the thread list is up to
+ // date before we do that or we might overwrite what was computed here.
+ UpdateThreadListIfNeeded();
+
+ if (m_last_stop_packet)
+ SetThreadStopInfo(*m_last_stop_packet);
+ m_last_stop_packet.reset();
+
+ // If we have queried for a default thread id
+ if (m_initial_tid != LLDB_INVALID_THREAD_ID) {
+ m_thread_list.SetSelectedThreadByID(m_initial_tid);
+ m_initial_tid = LLDB_INVALID_THREAD_ID;
+ }
+
+ // Let all threads recover from stopping and do any clean up based on the
+ // previous thread state (if any).
+ m_thread_list_real.RefreshStateAfterStop();
+}
+
+Status ProcessGDBRemote::DoHalt(bool &caused_stop) {
+ Status error;
+
+ if (m_public_state.GetValue() == eStateAttaching) {
+ // We are being asked to halt during an attach. We used to just close our
+ // file handle and debugserver will go away, but with remote proxies, it
+ // is better to send a positive signal, so let's send the interrupt first...
+ caused_stop = m_gdb_comm.Interrupt(GetInterruptTimeout());
+ m_gdb_comm.Disconnect();
+ } else
+ caused_stop = m_gdb_comm.Interrupt(GetInterruptTimeout());
+ return error;
+}
+
+Status ProcessGDBRemote::DoDetach(bool keep_stopped) {
+ Status error;
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOGF(log, "ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped);
+
+ error = m_gdb_comm.Detach(keep_stopped);
+ if (log) {
+ if (error.Success())
+ log->PutCString(
+ "ProcessGDBRemote::DoDetach() detach packet sent successfully");
+ else
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::DoDetach() detach packet send failed: %s",
+ error.AsCString() ? error.AsCString() : "<unknown error>");
+ }
+
+ if (!error.Success())
+ return error;
+
+ // Sleep for one second to let the process get all detached...
+ StopAsyncThread();
+
+ SetPrivateState(eStateDetached);
+ ResumePrivateStateThread();
+
+ // KillDebugserverProcess ();
+ return error;
+}
+
+Status ProcessGDBRemote::DoDestroy() {
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOGF(log, "ProcessGDBRemote::DoDestroy()");
+
+ // Interrupt if our inferior is running...
+ int exit_status = SIGABRT;
+ std::string exit_string;
+
+ if (m_gdb_comm.IsConnected()) {
+ if (m_public_state.GetValue() != eStateAttaching) {
+ llvm::Expected<int> kill_res = m_gdb_comm.KillProcess(GetID());
+
+ if (kill_res) {
+ exit_status = kill_res.get();
+#if defined(__APPLE__)
+ // For Native processes on Mac OS X, we launch through the Host
+ // Platform, then hand the process off to debugserver, which becomes
+ // the parent process through "PT_ATTACH". Then when we go to kill
+ // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then
+ // we call waitpid which returns with no error and the correct
+ // status. But amusingly enough that doesn't seem to actually reap
+ // the process, but instead it is left around as a Zombie. Probably
+ // the kernel is in the process of switching ownership back to lldb
+ // which was the original parent, and gets confused in the handoff.
+ // Anyway, so call waitpid here to finally reap it.
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+ if (platform_sp && platform_sp->IsHost()) {
+ int status;
+ ::pid_t reap_pid;
+ reap_pid = waitpid(GetID(), &status, WNOHANG);
+ LLDB_LOGF(log, "Reaped pid: %d, status: %d.\n", reap_pid, status);
+ }
+#endif
+ ClearThreadIDList();
+ exit_string.assign("killed");
+ } else {
+ exit_string.assign(llvm::toString(kill_res.takeError()));
+ }
+ } else {
+ exit_string.assign("killed or interrupted while attaching.");
+ }
+ } else {
+ // If we missed setting the exit status on the way out, do it here.
+ // NB set exit status can be called multiple times, the first one sets the
+ // status.
+ exit_string.assign("destroying when not connected to debugserver");
+ }
+
+ SetExitStatus(exit_status, exit_string.c_str());
+
+ StopAsyncThread();
+ KillDebugserverProcess();
+ return Status();
+}
+
+void ProcessGDBRemote::SetLastStopPacket(
+ const StringExtractorGDBRemote &response) {
+ const bool did_exec =
+ response.GetStringRef().find(";reason:exec;") != std::string::npos;
+ if (did_exec) {
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOGF(log, "ProcessGDBRemote::SetLastStopPacket () - detected exec");
+
+ m_thread_list_real.Clear();
+ m_thread_list.Clear();
+ BuildDynamicRegisterInfo(true);
+ m_gdb_comm.ResetDiscoverableSettings(did_exec);
+ }
+
+ m_last_stop_packet = response;
+}
+
+void ProcessGDBRemote::SetUnixSignals(const UnixSignalsSP &signals_sp) {
+ Process::SetUnixSignals(std::make_shared<GDBRemoteSignals>(signals_sp));
+}
+
+// Process Queries
+
+bool ProcessGDBRemote::IsAlive() {
+ return m_gdb_comm.IsConnected() && Process::IsAlive();
+}
+
+addr_t ProcessGDBRemote::GetImageInfoAddress() {
+ // request the link map address via the $qShlibInfoAddr packet
+ lldb::addr_t addr = m_gdb_comm.GetShlibInfoAddr();
+
+ // the loaded module list can also provides a link map address
+ if (addr == LLDB_INVALID_ADDRESS) {
+ llvm::Expected<LoadedModuleInfoList> list = GetLoadedModuleList();
+ if (!list) {
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOG_ERROR(log, list.takeError(), "Failed to read module list: {0}.");
+ } else {
+ addr = list->m_link_map;
+ }
+ }
+
+ return addr;
+}
+
+void ProcessGDBRemote::WillPublicStop() {
+ // See if the GDB remote client supports the JSON threads info. If so, we
+ // gather stop info for all threads, expedited registers, expedited memory,
+ // runtime queue information (iOS and MacOSX only), and more. Expediting
+ // memory will help stack backtracing be much faster. Expediting registers
+ // will make sure we don't have to read the thread registers for GPRs.
+ m_jthreadsinfo_sp = m_gdb_comm.GetThreadsInfo();
+
+ if (m_jthreadsinfo_sp) {
+ // Now set the stop info for each thread and also expedite any registers
+ // and memory that was in the jThreadsInfo response.
+ StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray();
+ if (thread_infos) {
+ const size_t n = thread_infos->GetSize();
+ for (size_t i = 0; i < n; ++i) {
+ StructuredData::Dictionary *thread_dict =
+ thread_infos->GetItemAtIndex(i)->GetAsDictionary();
+ if (thread_dict)
+ SetThreadStopInfo(thread_dict);
+ }
+ }
+ }
+}
+
+// Process Memory
+size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
+ Status &error) {
+ GetMaxMemorySize();
+ bool binary_memory_read = m_gdb_comm.GetxPacketSupported();
+ // M and m packets take 2 bytes for 1 byte of memory
+ size_t max_memory_size =
+ binary_memory_read ? m_max_memory_size : m_max_memory_size / 2;
+ if (size > 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
+ // lldb_private::Process so it is ok to do this.
+ size = max_memory_size;
+ }
+
+ char packet[64];
+ int packet_len;
+ packet_len = ::snprintf(packet, sizeof(packet), "%c%" PRIx64 ",%" PRIx64,
+ binary_memory_read ? 'x' : 'm', (uint64_t)addr,
+ (uint64_t)size);
+ assert(packet_len + 1 < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response,
+ GetInterruptTimeout()) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ error.Clear();
+ if (binary_memory_read) {
+ // The lower level GDBRemoteCommunication packet receive layer has
+ // already de-quoted any 0x7d character escaping that was present in
+ // the packet
+
+ size_t data_received_size = response.GetBytesLeft();
+ if (data_received_size > size) {
+ // Don't write past the end of BUF if the remote debug server gave us
+ // too much data for some reason.
+ data_received_size = size;
+ }
+ memcpy(buf, response.GetStringRef().data(), data_received_size);
+ return data_received_size;
+ } else {
+ return response.GetHexBytes(
+ llvm::MutableArrayRef<uint8_t>((uint8_t *)buf, size), '\xdd');
+ }
+ } else if (response.IsErrorResponse())
+ error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr);
+ else if (response.IsUnsupportedResponse())
+ error.SetErrorStringWithFormat(
+ "GDB server does not support reading memory");
+ else
+ error.SetErrorStringWithFormat(
+ "unexpected response to GDB server memory read packet '%s': '%s'",
+ packet, response.GetStringRef().data());
+ } else {
+ error.SetErrorStringWithFormat("failed to send packet: '%s'", packet);
+ }
+ return 0;
+}
+
+bool ProcessGDBRemote::SupportsMemoryTagging() {
+ return m_gdb_comm.GetMemoryTaggingSupported();
+}
+
+llvm::Expected<std::vector<uint8_t>>
+ProcessGDBRemote::DoReadMemoryTags(lldb::addr_t addr, size_t len,
+ int32_t type) {
+ // By this point ReadMemoryTags has validated that tagging is enabled
+ // for this target/process/address.
+ DataBufferSP buffer_sp = m_gdb_comm.ReadMemoryTags(addr, len, type);
+ if (!buffer_sp) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Error reading memory tags from remote");
+ }
+
+ // Return the raw tag data
+ llvm::ArrayRef<uint8_t> tag_data = buffer_sp->GetData();
+ std::vector<uint8_t> got;
+ got.reserve(tag_data.size());
+ std::copy(tag_data.begin(), tag_data.end(), std::back_inserter(got));
+ return got;
+}
+
+Status ProcessGDBRemote::DoWriteMemoryTags(lldb::addr_t addr, size_t len,
+ int32_t type,
+ const std::vector<uint8_t> &tags) {
+ // By now WriteMemoryTags should have validated that tagging is enabled
+ // for this target/process.
+ return m_gdb_comm.WriteMemoryTags(addr, len, type, tags);
+}
+
+Status ProcessGDBRemote::WriteObjectFile(
+ std::vector<ObjectFile::LoadableData> entries) {
+ Status error;
+ // Sort the entries by address because some writes, like those to flash
+ // memory, must happen in order of increasing address.
+ std::stable_sort(
+ std::begin(entries), std::end(entries),
+ [](const ObjectFile::LoadableData a, const ObjectFile::LoadableData b) {
+ return a.Dest < b.Dest;
+ });
+ m_allow_flash_writes = true;
+ error = Process::WriteObjectFile(entries);
+ if (error.Success())
+ error = FlashDone();
+ else
+ // Even though some of the writing failed, try to send a flash done if some
+ // of the writing succeeded so the flash state is reset to normal, but
+ // don't stomp on the error status that was set in the write failure since
+ // that's the one we want to report back.
+ FlashDone();
+ m_allow_flash_writes = false;
+ return error;
+}
+
+bool ProcessGDBRemote::HasErased(FlashRange range) {
+ auto size = m_erased_flash_ranges.GetSize();
+ for (size_t i = 0; i < size; ++i)
+ if (m_erased_flash_ranges.GetEntryAtIndex(i)->Contains(range))
+ return true;
+ return false;
+}
+
+Status ProcessGDBRemote::FlashErase(lldb::addr_t addr, size_t size) {
+ Status status;
+
+ MemoryRegionInfo region;
+ status = GetMemoryRegionInfo(addr, region);
+ if (!status.Success())
+ return status;
+
+ // The gdb spec doesn't say if erasures are allowed across multiple regions,
+ // but we'll disallow it to be safe and to keep the logic simple by worring
+ // about only one region's block size. DoMemoryWrite is this function's
+ // primary user, and it can easily keep writes within a single memory region
+ if (addr + size > region.GetRange().GetRangeEnd()) {
+ status.SetErrorString("Unable to erase flash in multiple regions");
+ return status;
+ }
+
+ uint64_t blocksize = region.GetBlocksize();
+ if (blocksize == 0) {
+ status.SetErrorString("Unable to erase flash because blocksize is 0");
+ return status;
+ }
+
+ // Erasures can only be done on block boundary adresses, so round down addr
+ // and round up size
+ lldb::addr_t block_start_addr = addr - (addr % blocksize);
+ size += (addr - block_start_addr);
+ if ((size % blocksize) != 0)
+ size += (blocksize - size % blocksize);
+
+ FlashRange range(block_start_addr, size);
+
+ if (HasErased(range))
+ return status;
+
+ // We haven't erased the entire range, but we may have erased part of it.
+ // (e.g., block A is already erased and range starts in A and ends in B). So,
+ // adjust range if necessary to exclude already erased blocks.
+ if (!m_erased_flash_ranges.IsEmpty()) {
+ // Assuming that writes and erasures are done in increasing addr order,
+ // because that is a requirement of the vFlashWrite command. Therefore, we
+ // only need to look at the last range in the list for overlap.
+ const auto &last_range = *m_erased_flash_ranges.Back();
+ if (range.GetRangeBase() < last_range.GetRangeEnd()) {
+ auto overlap = last_range.GetRangeEnd() - range.GetRangeBase();
+ // overlap will be less than range.GetByteSize() or else HasErased()
+ // would have been true
+ range.SetByteSize(range.GetByteSize() - overlap);
+ range.SetRangeBase(range.GetRangeBase() + overlap);
+ }
+ }
+
+ StreamString packet;
+ packet.Printf("vFlashErase:%" PRIx64 ",%" PRIx64, range.GetRangeBase(),
+ (uint64_t)range.GetByteSize());
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response,
+ GetInterruptTimeout()) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ m_erased_flash_ranges.Insert(range, true);
+ } else {
+ if (response.IsErrorResponse())
+ status.SetErrorStringWithFormat("flash erase failed for 0x%" PRIx64,
+ addr);
+ else if (response.IsUnsupportedResponse())
+ status.SetErrorStringWithFormat("GDB server does not support flashing");
+ else
+ status.SetErrorStringWithFormat(
+ "unexpected response to GDB server flash erase packet '%s': '%s'",
+ packet.GetData(), response.GetStringRef().data());
+ }
+ } else {
+ status.SetErrorStringWithFormat("failed to send packet: '%s'",
+ packet.GetData());
+ }
+ return status;
+}
+
+Status ProcessGDBRemote::FlashDone() {
+ Status status;
+ // If we haven't erased any blocks, then we must not have written anything
+ // either, so there is no need to actually send a vFlashDone command
+ if (m_erased_flash_ranges.IsEmpty())
+ return status;
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse("vFlashDone", response,
+ GetInterruptTimeout()) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ m_erased_flash_ranges.Clear();
+ } else {
+ if (response.IsErrorResponse())
+ status.SetErrorStringWithFormat("flash done failed");
+ else if (response.IsUnsupportedResponse())
+ status.SetErrorStringWithFormat("GDB server does not support flashing");
+ else
+ status.SetErrorStringWithFormat(
+ "unexpected response to GDB server flash done packet: '%s'",
+ response.GetStringRef().data());
+ }
+ } else {
+ status.SetErrorStringWithFormat("failed to send flash done packet");
+ }
+ return status;
+}
+
+size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf,
+ size_t size, Status &error) {
+ GetMaxMemorySize();
+ // M and m packets take 2 bytes for 1 byte of memory
+ size_t max_memory_size = m_max_memory_size / 2;
+ if (size > 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
+ // lldb_private::Process so it is ok to do this.
+ size = max_memory_size;
+ }
+
+ StreamGDBRemote packet;
+
+ MemoryRegionInfo region;
+ Status region_status = GetMemoryRegionInfo(addr, region);
+
+ bool is_flash =
+ region_status.Success() && region.GetFlash() == MemoryRegionInfo::eYes;
+
+ if (is_flash) {
+ if (!m_allow_flash_writes) {
+ error.SetErrorString("Writing to flash memory is not allowed");
+ return 0;
+ }
+ // Keep the write within a flash memory region
+ if (addr + size > region.GetRange().GetRangeEnd())
+ size = region.GetRange().GetRangeEnd() - addr;
+ // Flash memory must be erased before it can be written
+ error = FlashErase(addr, size);
+ if (!error.Success())
+ return 0;
+ packet.Printf("vFlashWrite:%" PRIx64 ":", addr);
+ packet.PutEscapedBytes(buf, size);
+ } else {
+ packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size);
+ packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(),
+ endian::InlHostByteOrder());
+ }
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response,
+ GetInterruptTimeout()) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ error.Clear();
+ return size;
+ } else if (response.IsErrorResponse())
+ error.SetErrorStringWithFormat("memory write failed for 0x%" PRIx64,
+ addr);
+ else if (response.IsUnsupportedResponse())
+ error.SetErrorStringWithFormat(
+ "GDB server does not support writing memory");
+ else
+ error.SetErrorStringWithFormat(
+ "unexpected response to GDB server memory write packet '%s': '%s'",
+ packet.GetData(), response.GetStringRef().data());
+ } else {
+ error.SetErrorStringWithFormat("failed to send packet: '%s'",
+ packet.GetData());
+ }
+ return 0;
+}
+
+lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t size,
+ uint32_t permissions,
+ Status &error) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Expressions);
+ addr_t allocated_addr = LLDB_INVALID_ADDRESS;
+
+ if (m_gdb_comm.SupportsAllocDeallocMemory() != eLazyBoolNo) {
+ allocated_addr = m_gdb_comm.AllocateMemory(size, permissions);
+ if (allocated_addr != LLDB_INVALID_ADDRESS ||
+ m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolYes)
+ return allocated_addr;
+ }
+
+ if (m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolNo) {
+ // Call mmap() to create memory in the inferior..
+ unsigned prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ prot |= eMmapProtRead;
+ if (permissions & lldb::ePermissionsWritable)
+ prot |= eMmapProtWrite;
+ if (permissions & lldb::ePermissionsExecutable)
+ prot |= eMmapProtExec;
+
+ if (InferiorCallMmap(this, allocated_addr, 0, size, prot,
+ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0))
+ m_addr_to_mmap_size[allocated_addr] = size;
+ else {
+ allocated_addr = LLDB_INVALID_ADDRESS;
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s no direct stub support for memory "
+ "allocation, and InferiorCallMmap also failed - is stub "
+ "missing register context save/restore capability?",
+ __FUNCTION__);
+ }
+ }
+
+ if (allocated_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat(
+ "unable to allocate %" PRIu64 " bytes of memory with permissions %s",
+ (uint64_t)size, GetPermissionsAsCString(permissions));
+ else
+ error.Clear();
+ return allocated_addr;
+}
+
+Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr,
+ MemoryRegionInfo &region_info) {
+
+ Status error(m_gdb_comm.GetMemoryRegionInfo(load_addr, region_info));
+ return error;
+}
+
+std::optional<uint32_t> ProcessGDBRemote::GetWatchpointSlotCount() {
+ return m_gdb_comm.GetWatchpointSlotCount();
+}
+
+std::optional<bool> ProcessGDBRemote::DoGetWatchpointReportedAfter() {
+ return m_gdb_comm.GetWatchpointReportedAfter();
+}
+
+Status ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) {
+ Status error;
+ LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
+
+ switch (supported) {
+ case eLazyBoolCalculate:
+ // 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;
+
+ case eLazyBoolYes:
+ 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..
+ {
+ MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
+ if (pos != m_addr_to_mmap_size.end() &&
+ InferiorCallMunmap(this, addr, pos->second))
+ m_addr_to_mmap_size.erase(pos);
+ else
+ error.SetErrorStringWithFormat(
+ "unable to deallocate memory at 0x%" PRIx64, addr);
+ }
+ break;
+ }
+
+ return error;
+}
+
+// Process STDIO
+size_t ProcessGDBRemote::PutSTDIN(const char *src, size_t src_len,
+ Status &error) {
+ if (m_stdio_communication.IsConnected()) {
+ ConnectionStatus status;
+ m_stdio_communication.WriteAll(src, src_len, status, nullptr);
+ } else if (m_stdin_forward) {
+ m_gdb_comm.SendStdinNotification(src, src_len);
+ }
+ return 0;
+}
+
+Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) {
+ Status error;
+ assert(bp_site != nullptr);
+
+ // Get logging info
+ Log *log = GetLog(GDBRLog::Breakpoints);
+ user_id_t site_id = bp_site->GetID();
+
+ // Get the breakpoint address
+ const addr_t addr = bp_site->GetLoadAddress();
+
+ // Log that a breakpoint was requested
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64
+ ") address = 0x%" PRIx64,
+ site_id, (uint64_t)addr);
+
+ // Breakpoint already exists and is enabled
+ if (bp_site->IsEnabled()) {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64
+ ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)",
+ site_id, (uint64_t)addr);
+ return error;
+ }
+
+ // Get the software breakpoint trap opcode size
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site);
+
+ // SupportsGDBStoppointPacket() simply checks a boolean, indicating if this
+ // breakpoint type is supported by the remote stub. These are set to true by
+ // default, and later set to false only after we receive an unimplemented
+ // response when sending a breakpoint packet. This means initially that
+ // unless we were specifically instructed to use a hardware breakpoint, LLDB
+ // will attempt to set a software breakpoint. HardwareRequired() also queries
+ // a boolean variable which indicates if the user specifically asked for
+ // hardware breakpoints. If true then we will skip over software
+ // breakpoints.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) &&
+ (!bp_site->HardwareRequired())) {
+ // Try to send off a software breakpoint packet ($Z0)
+ uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket(
+ eBreakpointSoftware, true, addr, bp_op_size, GetInterruptTimeout());
+ if (error_no == 0) {
+ // The breakpoint was placed successfully
+ bp_site->SetEnabled(true);
+ bp_site->SetType(BreakpointSite::eExternal);
+ return error;
+ }
+
+ // SendGDBStoppointTypePacket() will return an error if it was unable to
+ // set this breakpoint. We need to differentiate between a error specific
+ // to placing this breakpoint or if we have learned that this breakpoint
+ // type is unsupported. To do this, we must test the support boolean for
+ // this breakpoint type to see if it now indicates that this breakpoint
+ // type is unsupported. If they are still supported then we should return
+ // with the error code. If they are now unsupported, then we would like to
+ // fall through and try another form of breakpoint.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) {
+ if (error_no != UINT8_MAX)
+ error.SetErrorStringWithFormat(
+ "error: %d sending the breakpoint request", error_no);
+ else
+ error.SetErrorString("error sending the breakpoint request");
+ return error;
+ }
+
+ // We reach here when software breakpoints have been found to be
+ // unsupported. For future calls to set a breakpoint, we will not attempt
+ // to set a breakpoint with a type that is known not to be supported.
+ LLDB_LOGF(log, "Software breakpoints are unsupported");
+
+ // So we will fall through and try a hardware breakpoint
+ }
+
+ // The process of setting a hardware breakpoint is much the same as above.
+ // We check the supported boolean for this breakpoint type, and if it is
+ // thought to be supported then we will try to set this breakpoint with a
+ // hardware breakpoint.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) {
+ // Try to send off a hardware breakpoint packet ($Z1)
+ uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket(
+ eBreakpointHardware, true, addr, bp_op_size, GetInterruptTimeout());
+ if (error_no == 0) {
+ // The breakpoint was placed successfully
+ bp_site->SetEnabled(true);
+ bp_site->SetType(BreakpointSite::eHardware);
+ return error;
+ }
+
+ // Check if the error was something other then an unsupported breakpoint
+ // type
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) {
+ // Unable to set this hardware breakpoint
+ if (error_no != UINT8_MAX)
+ error.SetErrorStringWithFormat(
+ "error: %d sending the hardware breakpoint request "
+ "(hardware breakpoint resources might be exhausted or unavailable)",
+ error_no);
+ else
+ error.SetErrorString("error sending the hardware breakpoint request "
+ "(hardware breakpoint resources "
+ "might be exhausted or unavailable)");
+ return error;
+ }
+
+ // We will reach here when the stub gives an unsupported response to a
+ // hardware breakpoint
+ LLDB_LOGF(log, "Hardware breakpoints are unsupported");
+
+ // Finally we will falling through to a #trap style breakpoint
+ }
+
+ // Don't fall through when hardware breakpoints were specifically requested
+ if (bp_site->HardwareRequired()) {
+ error.SetErrorString("hardware breakpoints are not supported");
+ return error;
+ }
+
+ // As a last resort we want to place a manual breakpoint. An instruction is
+ // placed into the process memory using memory write packets.
+ return EnableSoftwareBreakpoint(bp_site);
+}
+
+Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) {
+ Status error;
+ assert(bp_site != nullptr);
+ addr_t addr = bp_site->GetLoadAddress();
+ user_id_t site_id = bp_site->GetID();
+ Log *log = GetLog(GDBRLog::Breakpoints);
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64
+ ") addr = 0x%8.8" PRIx64,
+ site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled()) {
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site);
+
+ BreakpointSite::Type bp_type = bp_site->GetType();
+ switch (bp_type) {
+ case BreakpointSite::eSoftware:
+ error = DisableSoftwareBreakpoint(bp_site);
+ break;
+
+ case BreakpointSite::eHardware:
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, false,
+ addr, bp_op_size,
+ GetInterruptTimeout()))
+ error.SetErrorToGenericError();
+ break;
+
+ case BreakpointSite::eExternal: {
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false,
+ addr, bp_op_size,
+ GetInterruptTimeout()))
+ error.SetErrorToGenericError();
+ } break;
+ }
+ if (error.Success())
+ bp_site->SetEnabled(false);
+ } else {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)",
+ site_id, (uint64_t)addr);
+ return error;
+ }
+
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+// Pre-requisite: wp != NULL.
+static GDBStoppointType
+GetGDBStoppointType(const WatchpointResourceSP &wp_res_sp) {
+ assert(wp_res_sp);
+ bool read = wp_res_sp->WatchpointResourceRead();
+ bool write = wp_res_sp->WatchpointResourceWrite();
+
+ assert((read || write) &&
+ "WatchpointResource type is neither read nor write");
+ if (read && write)
+ return eWatchpointReadWrite;
+ else if (read)
+ return eWatchpointRead;
+ else
+ return eWatchpointWrite;
+}
+
+Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
+ Status error;
+ if (!wp_sp) {
+ error.SetErrorString("No watchpoint specified");
+ return error;
+ }
+ user_id_t watchID = wp_sp->GetID();
+ addr_t addr = wp_sp->GetLoadAddress();
+ Log *log(GetLog(GDBRLog::Watchpoints));
+ LLDB_LOGF(log, "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (wp_sp->IsEnabled()) {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
+ watchID, (uint64_t)addr);
+ return error;
+ }
+
+ bool read = wp_sp->WatchpointRead();
+ bool write = wp_sp->WatchpointWrite() || wp_sp->WatchpointModify();
+ size_t size = wp_sp->GetByteSize();
+
+ ArchSpec target_arch = GetTarget().GetArchitecture();
+ WatchpointHardwareFeature supported_features =
+ m_gdb_comm.GetSupportedWatchpointTypes();
+
+ std::vector<WatchpointResourceSP> resources =
+ WatchpointAlgorithms::AtomizeWatchpointRequest(
+ addr, size, read, write, supported_features, target_arch);
+
+ // LWP_TODO: Now that we know the WP Resources needed to implement this
+ // Watchpoint, we need to look at currently allocated Resources in the
+ // Process and if they match, or are within the same memory granule, or
+ // overlapping memory ranges, then we need to combine them. e.g. one
+ // Watchpoint watching 1 byte at 0x1002 and a second watchpoint watching 1
+ // byte at 0x1003, they must use the same hardware watchpoint register
+ // (Resource) to watch them.
+
+ // This may mean that an existing resource changes its type (read to
+ // read+write) or address range it is watching, in which case the old
+ // watchpoint needs to be disabled and the new Resource addr/size/type
+ // watchpoint enabled.
+
+ // If we modify a shared Resource to accomodate this newly added Watchpoint,
+ // and we are unable to set all of the Resources for it in the inferior, we
+ // will return an error for this Watchpoint and the shared Resource should
+ // be restored. e.g. this Watchpoint requires three Resources, one which
+ // is shared with another Watchpoint. We extend the shared Resouce to
+ // handle both Watchpoints and we try to set two new ones. But if we don't
+ // have sufficient watchpoint register for all 3, we need to show an error
+ // for creating this Watchpoint and we should reset the shared Resource to
+ // its original configuration because it is no longer shared.
+
+ bool set_all_resources = true;
+ std::vector<WatchpointResourceSP> succesfully_set_resources;
+ for (const auto &wp_res_sp : resources) {
+ addr_t addr = wp_res_sp->GetLoadAddress();
+ size_t size = wp_res_sp->GetByteSize();
+ GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+ if (!m_gdb_comm.SupportsGDBStoppointPacket(type) ||
+ m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
+ GetInterruptTimeout())) {
+ set_all_resources = false;
+ break;
+ } else {
+ succesfully_set_resources.push_back(wp_res_sp);
+ }
+ }
+ if (set_all_resources) {
+ wp_sp->SetEnabled(true, notify);
+ for (const auto &wp_res_sp : resources) {
+ // LWP_TODO: If we expanded/reused an existing Resource,
+ // it's already in the WatchpointResourceList.
+ wp_res_sp->AddConstituent(wp_sp);
+ m_watchpoint_resource_list.Add(wp_res_sp);
+ }
+ return error;
+ } else {
+ // We failed to allocate one of the resources. Unset all
+ // of the new resources we did successfully set in the
+ // process.
+ for (const auto &wp_res_sp : succesfully_set_resources) {
+ addr_t addr = wp_res_sp->GetLoadAddress();
+ size_t size = wp_res_sp->GetByteSize();
+ GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+ m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
+ GetInterruptTimeout());
+ }
+ error.SetErrorString("Setting one of the watchpoint resources failed");
+ }
+ return error;
+}
+
+Status ProcessGDBRemote::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {
+ Status error;
+ if (!wp_sp) {
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+ }
+
+ user_id_t watchID = wp_sp->GetID();
+
+ Log *log(GetLog(GDBRLog::Watchpoints));
+
+ addr_t addr = wp_sp->GetLoadAddress();
+
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64,
+ watchID, (uint64_t)addr);
+
+ if (!wp_sp->IsEnabled()) {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)",
+ watchID, (uint64_t)addr);
+ // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling
+ // attempt might come from the user-supplied actions, we'll route it in
+ // order for the watchpoint object to intelligently process this action.
+ wp_sp->SetEnabled(false, notify);
+ return error;
+ }
+
+ if (wp_sp->IsHardware()) {
+ bool disabled_all = true;
+
+ std::vector<WatchpointResourceSP> unused_resources;
+ for (const auto &wp_res_sp : m_watchpoint_resource_list.Sites()) {
+ if (wp_res_sp->ConstituentsContains(wp_sp)) {
+ GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+ addr_t addr = wp_res_sp->GetLoadAddress();
+ size_t size = wp_res_sp->GetByteSize();
+ if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
+ GetInterruptTimeout())) {
+ disabled_all = false;
+ } else {
+ wp_res_sp->RemoveConstituent(wp_sp);
+ if (wp_res_sp->GetNumberOfConstituents() == 0)
+ unused_resources.push_back(wp_res_sp);
+ }
+ }
+ }
+ for (auto &wp_res_sp : unused_resources)
+ m_watchpoint_resource_list.Remove(wp_res_sp->GetID());
+
+ wp_sp->SetEnabled(false, notify);
+ if (!disabled_all)
+ error.SetErrorString("Failure disabling one of the watchpoint locations");
+ }
+ return error;
+}
+
+void ProcessGDBRemote::Clear() {
+ m_thread_list_real.Clear();
+ m_thread_list.Clear();
+}
+
+Status ProcessGDBRemote::DoSignal(int signo) {
+ Status error;
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOGF(log, "ProcessGDBRemote::DoSignal (signal = %d)", signo);
+
+ if (!m_gdb_comm.SendAsyncSignal(signo, GetInterruptTimeout()))
+ error.SetErrorStringWithFormat("failed to send signal %i", signo);
+ return error;
+}
+
+Status
+ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) {
+ // Make sure we aren't already connected?
+ if (m_gdb_comm.IsConnected())
+ return Status();
+
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+ if (platform_sp && !platform_sp->IsHost())
+ return Status("Lost debug server connection");
+
+ auto error = LaunchAndConnectToDebugserver(process_info);
+ if (error.Fail()) {
+ const char *error_string = error.AsCString();
+ if (error_string == nullptr)
+ error_string = "unable to launch " DEBUGSERVER_BASENAME;
+ }
+ return error;
+}
+#if !defined(_WIN32)
+#define USE_SOCKETPAIR_FOR_LOCAL_CONNECTION 1
+#endif
+
+#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION
+static bool SetCloexecFlag(int fd) {
+#if defined(FD_CLOEXEC)
+ int flags = ::fcntl(fd, F_GETFD);
+ if (flags == -1)
+ return false;
+ return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
+#else
+ return false;
+#endif
+}
+#endif
+
+Status ProcessGDBRemote::LaunchAndConnectToDebugserver(
+ const ProcessInfo &process_info) {
+ using namespace std::placeholders; // For _1, _2, etc.
+
+ Status error;
+ if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) {
+ // If we locate debugserver, keep that located version around
+ static FileSpec g_debugserver_file_spec;
+
+ ProcessLaunchInfo debugserver_launch_info;
+ // Make debugserver run in its own session so signals generated by special
+ // terminal key sequences (^C) don't affect debugserver.
+ debugserver_launch_info.SetLaunchInSeparateProcessGroup(true);
+
+ const std::weak_ptr<ProcessGDBRemote> this_wp =
+ std::static_pointer_cast<ProcessGDBRemote>(shared_from_this());
+ debugserver_launch_info.SetMonitorProcessCallback(
+ std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3));
+ debugserver_launch_info.SetUserID(process_info.GetUserID());
+
+#if defined(__APPLE__)
+ // On macOS 11, we need to support x86_64 applications translated to
+ // arm64. We check whether a binary is translated and spawn the correct
+ // debugserver accordingly.
+ int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
+ static_cast<int>(process_info.GetProcessID()) };
+ struct kinfo_proc processInfo;
+ size_t bufsize = sizeof(processInfo);
+ if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo,
+ &bufsize, NULL, 0) == 0 && bufsize > 0) {
+ if (processInfo.kp_proc.p_flag & P_TRANSLATED) {
+ FileSpec rosetta_debugserver("/Library/Apple/usr/libexec/oah/debugserver");
+ debugserver_launch_info.SetExecutableFile(rosetta_debugserver, false);
+ }
+ }
+#endif
+
+ int communication_fd = -1;
+#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION
+ // Use a socketpair on non-Windows systems for security and performance
+ // reasons.
+ int sockets[2]; /* the pair of socket descriptors */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ int our_socket = sockets[0];
+ int gdb_socket = sockets[1];
+ auto cleanup_our = llvm::make_scope_exit([&]() { close(our_socket); });
+ auto cleanup_gdb = llvm::make_scope_exit([&]() { close(gdb_socket); });
+
+ // Don't let any child processes inherit our communication socket
+ SetCloexecFlag(our_socket);
+ communication_fd = gdb_socket;
+#endif
+
+ error = m_gdb_comm.StartDebugserverProcess(
+ nullptr, GetTarget().GetPlatform().get(), debugserver_launch_info,
+ nullptr, nullptr, communication_fd);
+
+ if (error.Success())
+ m_debugserver_pid = debugserver_launch_info.GetProcessID();
+ else
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) {
+#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION
+ // Our process spawned correctly, we can now set our connection to use
+ // our end of the socket pair
+ cleanup_our.release();
+ m_gdb_comm.SetConnection(
+ std::make_unique<ConnectionFileDescriptor>(our_socket, true));
+#endif
+ StartAsyncThread();
+ }
+
+ if (error.Fail()) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ LLDB_LOGF(log, "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)
+ error = ConnectToDebugserver("");
+ } else {
+ error.SetErrorString("connection failed");
+ }
+ }
+ return error;
+}
+
+void ProcessGDBRemote::MonitorDebugserverProcess(
+ std::weak_ptr<ProcessGDBRemote> process_wp, lldb::pid_t debugserver_pid,
+ int signo, // Zero for no signal
+ int exit_status // Exit value of process if signal is zero
+) {
+ // "debugserver_pid" argument passed in is the process ID for debugserver
+ // that we are tracking...
+ Log *log = GetLog(GDBRLog::Process);
+
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s(process_wp, pid=%" PRIu64
+ ", signo=%i (0x%x), exit_status=%i)",
+ __FUNCTION__, debugserver_pid, signo, signo, exit_status);
+
+ std::shared_ptr<ProcessGDBRemote> process_sp = process_wp.lock();
+ LLDB_LOGF(log, "ProcessGDBRemote::%s(process = %p)", __FUNCTION__,
+ static_cast<void *>(process_sp.get()));
+ if (!process_sp || process_sp->m_debugserver_pid != debugserver_pid)
+ return;
+
+ // Sleep for a half a second to make sure our inferior process has time to
+ // set its exit status before we set it incorrectly when both the debugserver
+ // and the inferior process shut down.
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+ // If our process hasn't yet exited, debugserver might have died. If the
+ // process did exit, then we are reaping it.
+ const StateType state = process_sp->GetState();
+
+ if (state != eStateInvalid && state != eStateUnloaded &&
+ state != eStateExited && state != eStateDetached) {
+ StreamString stream;
+ if (signo == 0)
+ stream.Format(DEBUGSERVER_BASENAME " died with an exit status of {0:x8}",
+ exit_status);
+ else {
+ llvm::StringRef signal_name =
+ process_sp->GetUnixSignals()->GetSignalAsStringRef(signo);
+ const char *format_str = DEBUGSERVER_BASENAME " died with signal {0}";
+ if (!signal_name.empty())
+ stream.Format(format_str, signal_name);
+ else
+ stream.Format(format_str, signo);
+ }
+ process_sp->SetExitStatus(-1, stream.GetString());
+ }
+ // Debugserver has exited we need to let our ProcessGDBRemote know that it no
+ // longer has a debugserver instance
+ process_sp->m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+}
+
+void ProcessGDBRemote::KillDebugserverProcess() {
+ m_gdb_comm.Disconnect();
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) {
+ Host::Kill(m_debugserver_pid, SIGINT);
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ }
+}
+
+void ProcessGDBRemote::Initialize() {
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+ });
+}
+
+void ProcessGDBRemote::DebuggerInitialize(Debugger &debugger) {
+ if (!PluginManager::GetSettingForProcessPlugin(
+ debugger, PluginProperties::GetSettingName())) {
+ const bool is_global_setting = true;
+ PluginManager::CreateSettingForProcessPlugin(
+ debugger, GetGlobalPluginProperties().GetValueProperties(),
+ "Properties for the gdb-remote process plug-in.", is_global_setting);
+ }
+}
+
+bool ProcessGDBRemote::StartAsyncThread() {
+ Log *log = GetLog(GDBRLog::Process);
+
+ LLDB_LOGF(log, "ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
+ if (!m_async_thread.IsJoinable()) {
+ // Create a thread that watches our internal state and controls which
+ // events make it to clients (into the DCProcess event queue).
+
+ llvm::Expected<HostThread> async_thread =
+ ThreadLauncher::LaunchThread("<lldb.process.gdb-remote.async>", [this] {
+ return ProcessGDBRemote::AsyncThread();
+ });
+ if (!async_thread) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Host), async_thread.takeError(),
+ "failed to launch host thread: {0}");
+ return false;
+ }
+ m_async_thread = *async_thread;
+ } else
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s () - Called when Async thread was "
+ "already running.",
+ __FUNCTION__);
+
+ return m_async_thread.IsJoinable();
+}
+
+void ProcessGDBRemote::StopAsyncThread() {
+ Log *log = GetLog(GDBRLog::Process);
+
+ LLDB_LOGF(log, "ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
+ 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.
+
+ // Stop the stdio thread
+ m_async_thread.Join(nullptr);
+ m_async_thread.Reset();
+ } else
+ LLDB_LOGF(
+ log,
+ "ProcessGDBRemote::%s () - Called when Async thread was not running.",
+ __FUNCTION__);
+}
+
+thread_result_t ProcessGDBRemote::AsyncThread() {
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOGF(log, "ProcessGDBRemote::%s(pid = %" PRIu64 ") thread starting...",
+ __FUNCTION__, GetID());
+
+ EventSP event_sp;
+
+ // We need to ignore any packets that come in after we have
+ // have decided the process has exited. There are some
+ // situations, for instance when we try to interrupt a running
+ // process and the interrupt fails, where another packet might
+ // get delivered after we've decided to give up on the process.
+ // But once we've decided we are done with the process we will
+ // not be in a state to do anything useful with new packets.
+ // So it is safer to simply ignore any remaining packets by
+ // explicitly checking for eStateExited before reentering the
+ // fetch loop.
+
+ bool done = false;
+ while (!done && GetPrivateState() != eStateExited) {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s(pid = %" PRIu64
+ ") listener.WaitForEvent (NULL, event_sp)...",
+ __FUNCTION__, GetID());
+
+ if (m_async_listener_sp->GetEvent(event_sp, std::nullopt)) {
+ const uint32_t event_type = event_sp->GetType();
+ if (event_sp->BroadcasterIs(&m_async_broadcaster)) {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s(pid = %" PRIu64
+ ") Got an event of type: %d...",
+ __FUNCTION__, GetID(), event_type);
+
+ switch (event_type) {
+ case eBroadcastBitAsyncContinue: {
+ const EventDataBytes *continue_packet =
+ EventDataBytes::GetEventDataFromEvent(event_sp.get());
+
+ if (continue_packet) {
+ const char *continue_cstr =
+ (const char *)continue_packet->GetBytes();
+ const size_t continue_cstr_len = continue_packet->GetByteSize();
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s(pid = %" PRIu64
+ ") got eBroadcastBitAsyncContinue: %s",
+ __FUNCTION__, GetID(), continue_cstr);
+
+ if (::strstr(continue_cstr, "vAttach") == nullptr)
+ SetPrivateState(eStateRunning);
+ StringExtractorGDBRemote response;
+
+ StateType stop_state =
+ GetGDBRemote().SendContinuePacketAndWaitForResponse(
+ *this, *GetUnixSignals(),
+ llvm::StringRef(continue_cstr, continue_cstr_len),
+ GetInterruptTimeout(), response);
+
+ // We need to immediately clear the thread ID list so we are sure
+ // to get a valid list of threads. The thread ID list might be
+ // contained within the "response", or the stop reply packet that
+ // caused the stop. So clear it now before we give the stop reply
+ // packet to the process using the
+ // SetLastStopPacket()...
+ ClearThreadIDList();
+
+ switch (stop_state) {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ SetLastStopPacket(response);
+ SetPrivateState(stop_state);
+ break;
+
+ case eStateExited: {
+ SetLastStopPacket(response);
+ ClearThreadIDList();
+ response.SetFilePos(1);
+
+ int exit_status = response.GetHexU8();
+ std::string desc_string;
+ if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') {
+ llvm::StringRef desc_str;
+ llvm::StringRef desc_token;
+ while (response.GetNameColonValue(desc_token, desc_str)) {
+ if (desc_token != "description")
+ continue;
+ StringExtractor extractor(desc_str);
+ extractor.GetHexByteString(desc_string);
+ }
+ }
+ SetExitStatus(exit_status, desc_string.c_str());
+ done = true;
+ break;
+ }
+ case eStateInvalid: {
+ // Check to see if we were trying to attach and if we got back
+ // the "E87" error code from debugserver -- this indicates that
+ // the process is not debuggable. Return a slightly more
+ // helpful error message about why the attach failed.
+ if (::strstr(continue_cstr, "vAttach") != nullptr &&
+ response.GetError() == 0x87) {
+ SetExitStatus(-1, "cannot attach to process due to "
+ "System Integrity Protection");
+ } else if (::strstr(continue_cstr, "vAttach") != nullptr &&
+ response.GetStatus().Fail()) {
+ SetExitStatus(-1, response.GetStatus().AsCString());
+ } else {
+ SetExitStatus(-1, "lost connection");
+ }
+ done = true;
+ break;
+ }
+
+ default:
+ SetPrivateState(stop_state);
+ break;
+ } // switch(stop_state)
+ } // if (continue_packet)
+ } // case eBroadcastBitAsyncContinue
+ break;
+
+ case eBroadcastBitAsyncThreadShouldExit:
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s(pid = %" PRIu64
+ ") got eBroadcastBitAsyncThreadShouldExit...",
+ __FUNCTION__, GetID());
+ done = true;
+ break;
+
+ default:
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s(pid = %" PRIu64
+ ") got unknown event 0x%8.8x",
+ __FUNCTION__, GetID(), event_type);
+ done = true;
+ break;
+ }
+ }
+ } else {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s(pid = %" PRIu64
+ ") listener.WaitForEvent (NULL, event_sp) => false",
+ __FUNCTION__, GetID());
+ done = true;
+ }
+ }
+
+ LLDB_LOGF(log, "ProcessGDBRemote::%s(pid = %" PRIu64 ") thread exiting...",
+ __FUNCTION__, GetID());
+
+ return {};
+}
+
+// uint32_t
+// ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList
+// &matches, std::vector<lldb::pid_t> &pids)
+//{
+// // If we are planning to launch the debugserver remotely, then we need to
+// fire up a debugserver
+// // process and ask it for the list of processes. But if we are local, we
+// can let the Host do it.
+// if (m_local_debugserver)
+// {
+// return Host::ListProcessesMatchingName (name, matches, pids);
+// }
+// else
+// {
+// // FIXME: Implement talking to the remote debugserver.
+// return 0;
+// }
+//
+//}
+//
+bool ProcessGDBRemote::NewThreadNotifyBreakpointHit(
+ void *baton, StoppointCallbackContext *context, 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
+ // run so I can stop it if that's what I want to do.
+ Log *log = GetLog(LLDBLog::Step);
+ LLDB_LOGF(log, "Hit New Thread Notification breakpoint.");
+ return false;
+}
+
+Status ProcessGDBRemote::UpdateAutomaticSignalFiltering() {
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOG(log, "Check if need to update ignored signals");
+
+ // QPassSignals package is not supported by the server, there is no way we
+ // can ignore any signals on server side.
+ if (!m_gdb_comm.GetQPassSignalsSupported())
+ return Status();
+
+ // No signals, nothing to send.
+ if (m_unix_signals_sp == nullptr)
+ return Status();
+
+ // Signals' version hasn't changed, no need to send anything.
+ uint64_t new_signals_version = m_unix_signals_sp->GetVersion();
+ if (new_signals_version == m_last_signals_version) {
+ LLDB_LOG(log, "Signals' version hasn't changed. version={0}",
+ m_last_signals_version);
+ return Status();
+ }
+
+ auto signals_to_ignore =
+ m_unix_signals_sp->GetFilteredSignals(false, false, false);
+ Status error = m_gdb_comm.SendSignalsToIgnore(signals_to_ignore);
+
+ LLDB_LOG(log,
+ "Signals' version changed. old version={0}, new version={1}, "
+ "signals ignored={2}, update result={3}",
+ m_last_signals_version, new_signals_version,
+ signals_to_ignore.size(), error);
+
+ if (error.Success())
+ m_last_signals_version = new_signals_version;
+
+ return error;
+}
+
+bool ProcessGDBRemote::StartNoticingNewThreads() {
+ Log *log = GetLog(LLDBLog::Step);
+ if (m_thread_create_bp_sp) {
+ if (log && log->GetVerbose())
+ LLDB_LOGF(log, "Enabled noticing new thread breakpoint.");
+ m_thread_create_bp_sp->SetEnabled(true);
+ } else {
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+ if (platform_sp) {
+ m_thread_create_bp_sp =
+ platform_sp->SetThreadCreationBreakpoint(GetTarget());
+ if (m_thread_create_bp_sp) {
+ if (log && log->GetVerbose())
+ LLDB_LOGF(
+ log, "Successfully created new thread notification breakpoint %i",
+ m_thread_create_bp_sp->GetID());
+ m_thread_create_bp_sp->SetCallback(
+ ProcessGDBRemote::NewThreadNotifyBreakpointHit, this, true);
+ } else {
+ LLDB_LOGF(log, "Failed to create new thread notification breakpoint.");
+ }
+ }
+ }
+ return m_thread_create_bp_sp.get() != nullptr;
+}
+
+bool ProcessGDBRemote::StopNoticingNewThreads() {
+ Log *log = GetLog(LLDBLog::Step);
+ if (log && log->GetVerbose())
+ LLDB_LOGF(log, "Disabling new thread notification breakpoint.");
+
+ if (m_thread_create_bp_sp)
+ m_thread_create_bp_sp->SetEnabled(false);
+
+ return true;
+}
+
+DynamicLoader *ProcessGDBRemote::GetDynamicLoader() {
+ if (m_dyld_up.get() == nullptr)
+ m_dyld_up.reset(DynamicLoader::FindPlugin(this, ""));
+ return m_dyld_up.get();
+}
+
+Status ProcessGDBRemote::SendEventData(const char *data) {
+ int return_value;
+ bool was_supported;
+
+ Status error;
+
+ return_value = m_gdb_comm.SendLaunchEventDataPacket(data, &was_supported);
+ if (return_value != 0) {
+ if (!was_supported)
+ error.SetErrorString("Sending events is not supported for this process.");
+ else
+ error.SetErrorStringWithFormat("Error sending event data: %d.",
+ return_value);
+ }
+ return error;
+}
+
+DataExtractor ProcessGDBRemote::GetAuxvData() {
+ DataBufferSP buf;
+ if (m_gdb_comm.GetQXferAuxvReadSupported()) {
+ llvm::Expected<std::string> response = m_gdb_comm.ReadExtFeature("auxv", "");
+ if (response)
+ buf = std::make_shared<DataBufferHeap>(response->c_str(),
+ response->length());
+ else
+ LLDB_LOG_ERROR(GetLog(GDBRLog::Process), response.takeError(), "{0}");
+ }
+ return DataExtractor(buf, GetByteOrder(), GetAddressByteSize());
+}
+
+StructuredData::ObjectSP
+ProcessGDBRemote::GetExtendedInfoForThread(lldb::tid_t tid) {
+ StructuredData::ObjectSP object_sp;
+
+ if (m_gdb_comm.GetThreadExtendedInfoSupported()) {
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+ SystemRuntime *runtime = GetSystemRuntime();
+ if (runtime) {
+ runtime->AddThreadExtendedInfoPacketHints(args_dict);
+ }
+ args_dict->GetAsDictionary()->AddIntegerItem("thread", tid);
+
+ StreamString packet;
+ packet << "jThreadExtendedInfo:";
+ args_dict->Dump(packet, false);
+
+ // FIXME the final character of a JSON dictionary, '}', is the escape
+ // character in gdb-remote binary mode. lldb currently doesn't escape
+ // these characters in its packet output -- so we add the quoted version of
+ // the } character here manually in case we talk to a debugserver which un-
+ // escapes the characters at packet read time.
+ packet << (char)(0x7d ^ 0x20);
+
+ StringExtractorGDBRemote response;
+ response.SetResponseValidatorToJSON();
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ StringExtractorGDBRemote::ResponseType response_type =
+ response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse) {
+ if (!response.Empty()) {
+ object_sp = StructuredData::ParseJSON(response.GetStringRef());
+ }
+ }
+ }
+ }
+ return object_sp;
+}
+
+StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos(
+ lldb::addr_t image_list_address, lldb::addr_t image_count) {
+
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+ args_dict->GetAsDictionary()->AddIntegerItem("image_list_address",
+ image_list_address);
+ args_dict->GetAsDictionary()->AddIntegerItem("image_count", image_count);
+
+ return GetLoadedDynamicLibrariesInfos_sender(args_dict);
+}
+
+StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos() {
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+
+ args_dict->GetAsDictionary()->AddBooleanItem("fetch_all_solibs", true);
+
+ return GetLoadedDynamicLibrariesInfos_sender(args_dict);
+}
+
+StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos(
+ const std::vector<lldb::addr_t> &load_addresses) {
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+ StructuredData::ArraySP addresses(new StructuredData::Array);
+
+ for (auto addr : load_addresses)
+ addresses->AddIntegerItem(addr);
+
+ args_dict->GetAsDictionary()->AddItem("solib_addresses", addresses);
+
+ return GetLoadedDynamicLibrariesInfos_sender(args_dict);
+}
+
+StructuredData::ObjectSP
+ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender(
+ StructuredData::ObjectSP args_dict) {
+ StructuredData::ObjectSP object_sp;
+
+ if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported()) {
+ // Scope for the scoped timeout object
+ GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm,
+ std::chrono::seconds(10));
+
+ StreamString packet;
+ packet << "jGetLoadedDynamicLibrariesInfos:";
+ args_dict->Dump(packet, false);
+
+ // FIXME the final character of a JSON dictionary, '}', is the escape
+ // character in gdb-remote binary mode. lldb currently doesn't escape
+ // these characters in its packet output -- so we add the quoted version of
+ // the } character here manually in case we talk to a debugserver which un-
+ // escapes the characters at packet read time.
+ packet << (char)(0x7d ^ 0x20);
+
+ StringExtractorGDBRemote response;
+ response.SetResponseValidatorToJSON();
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ StringExtractorGDBRemote::ResponseType response_type =
+ response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse) {
+ if (!response.Empty()) {
+ object_sp = StructuredData::ParseJSON(response.GetStringRef());
+ }
+ }
+ }
+ }
+ return object_sp;
+}
+
+StructuredData::ObjectSP ProcessGDBRemote::GetDynamicLoaderProcessState() {
+ StructuredData::ObjectSP object_sp;
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+
+ if (m_gdb_comm.GetDynamicLoaderProcessStateSupported()) {
+ StringExtractorGDBRemote response;
+ response.SetResponseValidatorToJSON();
+ if (m_gdb_comm.SendPacketAndWaitForResponse("jGetDyldProcessState",
+ response) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ StringExtractorGDBRemote::ResponseType response_type =
+ response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse) {
+ if (!response.Empty()) {
+ object_sp = StructuredData::ParseJSON(response.GetStringRef());
+ }
+ }
+ }
+ }
+ return object_sp;
+}
+
+StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() {
+ StructuredData::ObjectSP object_sp;
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+
+ if (m_gdb_comm.GetSharedCacheInfoSupported()) {
+ StreamString packet;
+ packet << "jGetSharedCacheInfo:";
+ args_dict->Dump(packet, false);
+
+ // FIXME the final character of a JSON dictionary, '}', is the escape
+ // character in gdb-remote binary mode. lldb currently doesn't escape
+ // these characters in its packet output -- so we add the quoted version of
+ // the } character here manually in case we talk to a debugserver which un-
+ // escapes the characters at packet read time.
+ packet << (char)(0x7d ^ 0x20);
+
+ StringExtractorGDBRemote response;
+ response.SetResponseValidatorToJSON();
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ StringExtractorGDBRemote::ResponseType response_type =
+ response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse) {
+ if (!response.Empty()) {
+ object_sp = StructuredData::ParseJSON(response.GetStringRef());
+ }
+ }
+ }
+ }
+ return object_sp;
+}
+
+Status ProcessGDBRemote::ConfigureStructuredData(
+ llvm::StringRef type_name, const StructuredData::ObjectSP &config_sp) {
+ return m_gdb_comm.ConfigureRemoteStructuredData(type_name, config_sp);
+}
+
+// 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 reasonable
+// largeish default.
+//
+// If the remote stub doesn't advertise a max packet size, use a conservative
+// default.
+
+void ProcessGDBRemote::GetMaxMemorySize() {
+ const uint64_t reasonable_largeish_default = 128 * 1024;
+ const uint64_t conservative_default = 512;
+
+ if (m_max_memory_size == 0) {
+ uint64_t stub_max_size = m_gdb_comm.GetRemoteMaxPacketSize();
+ if (stub_max_size != UINT64_MAX && stub_max_size != 0) {
+ // Save the stub's claimed maximum packet size
+ m_remote_stub_max_memory_size = stub_max_size;
+
+ // Even if the stub says it can support ginormous packets, don't exceed
+ // our reasonable largeish default packet size.
+ if (stub_max_size > reasonable_largeish_default) {
+ stub_max_size = reasonable_largeish_default;
+ }
+
+ // Memory packet have other overheads too like Maddr,size:#NN Instead of
+ // calculating the bytes taken by size and addr every time, we take a
+ // maximum guess here.
+ if (stub_max_size > 70)
+ stub_max_size -= 32 + 32 + 6;
+ else {
+ // In unlikely scenario that max packet size is less then 70, we will
+ // hope that data being written is small enough to fit.
+ Log *log(GetLog(GDBRLog::Comm | GDBRLog::Memory));
+ if (log)
+ log->Warning("Packet size is too small. "
+ "LLDB may face problems while writing memory");
+ }
+
+ m_max_memory_size = stub_max_size;
+ } else {
+ m_max_memory_size = conservative_default;
+ }
+ }
+}
+
+void ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize(
+ uint64_t user_specified_max) {
+ if (user_specified_max != 0) {
+ GetMaxMemorySize();
+
+ if (m_remote_stub_max_memory_size != 0) {
+ if (m_remote_stub_max_memory_size < user_specified_max) {
+ m_max_memory_size = m_remote_stub_max_memory_size; // user specified a
+ // packet size too
+ // big, go as big
+ // as the remote stub says we can go.
+ } else {
+ m_max_memory_size = user_specified_max; // user's packet size is good
+ }
+ } else {
+ m_max_memory_size =
+ user_specified_max; // user's packet size is probably fine
+ }
+ }
+}
+
+bool ProcessGDBRemote::GetModuleSpec(const FileSpec &module_file_spec,
+ const ArchSpec &arch,
+ ModuleSpec &module_spec) {
+ Log *log = GetLog(LLDBLog::Platform);
+
+ const ModuleCacheKey key(module_file_spec.GetPath(),
+ arch.GetTriple().getTriple());
+ auto cached = m_cached_module_specs.find(key);
+ if (cached != m_cached_module_specs.end()) {
+ module_spec = cached->second;
+ return bool(module_spec);
+ }
+
+ if (!m_gdb_comm.GetModuleInfo(module_file_spec, arch, module_spec)) {
+ LLDB_LOGF(log, "ProcessGDBRemote::%s - failed to get module info for %s:%s",
+ __FUNCTION__, module_file_spec.GetPath().c_str(),
+ arch.GetTriple().getTriple().c_str());
+ return false;
+ }
+
+ if (log) {
+ StreamString stream;
+ module_spec.Dump(stream);
+ LLDB_LOGF(log, "ProcessGDBRemote::%s - got module info for (%s:%s) : %s",
+ __FUNCTION__, module_file_spec.GetPath().c_str(),
+ arch.GetTriple().getTriple().c_str(), stream.GetData());
+ }
+
+ m_cached_module_specs[key] = module_spec;
+ return true;
+}
+
+void ProcessGDBRemote::PrefetchModuleSpecs(
+ llvm::ArrayRef<FileSpec> module_file_specs, const llvm::Triple &triple) {
+ auto module_specs = m_gdb_comm.GetModulesInfo(module_file_specs, triple);
+ if (module_specs) {
+ for (const FileSpec &spec : module_file_specs)
+ m_cached_module_specs[ModuleCacheKey(spec.GetPath(),
+ triple.getTriple())] = ModuleSpec();
+ for (const ModuleSpec &spec : *module_specs)
+ m_cached_module_specs[ModuleCacheKey(spec.GetFileSpec().GetPath(),
+ triple.getTriple())] = spec;
+ }
+}
+
+llvm::VersionTuple ProcessGDBRemote::GetHostOSVersion() {
+ return m_gdb_comm.GetOSVersion();
+}
+
+llvm::VersionTuple ProcessGDBRemote::GetHostMacCatalystVersion() {
+ return m_gdb_comm.GetMacCatalystVersion();
+}
+
+namespace {
+
+typedef std::vector<std::string> stringVec;
+
+typedef std::vector<struct GdbServerRegisterInfo> GDBServerRegisterVec;
+struct RegisterSetInfo {
+ ConstString name;
+};
+
+typedef std::map<uint32_t, RegisterSetInfo> RegisterSetMap;
+
+struct GdbServerTargetInfo {
+ std::string arch;
+ std::string osabi;
+ stringVec includes;
+ RegisterSetMap reg_set_map;
+};
+
+static FieldEnum::Enumerators ParseEnumEvalues(const XMLNode &enum_node) {
+ Log *log(GetLog(GDBRLog::Process));
+ // We will use the last instance of each value. Also we preserve the order
+ // of declaration in the XML, as it may not be numerical.
+ // For example, hardware may intially release with two states that softwware
+ // can read from a register field:
+ // 0 = startup, 1 = running
+ // If in a future hardware release, the designers added a pre-startup state:
+ // 0 = startup, 1 = running, 2 = pre-startup
+ // Now it makes more sense to list them in this logical order as opposed to
+ // numerical order:
+ // 2 = pre-startup, 1 = startup, 0 = startup
+ // This only matters for "register info" but let's trust what the server
+ // chose regardless.
+ std::map<uint64_t, FieldEnum::Enumerator> enumerators;
+
+ enum_node.ForEachChildElementWithName(
+ "evalue", [&enumerators, &log](const XMLNode &enumerator_node) {
+ std::optional<llvm::StringRef> name;
+ std::optional<uint64_t> value;
+
+ enumerator_node.ForEachAttribute(
+ [&name, &value, &log](const llvm::StringRef &attr_name,
+ const llvm::StringRef &attr_value) {
+ if (attr_name == "name") {
+ if (attr_value.size())
+ name = attr_value;
+ else
+ LLDB_LOG(log, "ProcessGDBRemote::ParseEnumEvalues "
+ "Ignoring empty name in evalue");
+ } else if (attr_name == "value") {
+ uint64_t parsed_value = 0;
+ if (llvm::to_integer(attr_value, parsed_value))
+ value = parsed_value;
+ else
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseEnumEvalues "
+ "Invalid value \"{0}\" in "
+ "evalue",
+ attr_value.data());
+ } else
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseEnumEvalues Ignoring "
+ "unknown attribute "
+ "\"{0}\" in evalue",
+ attr_name.data());
+
+ // Keep walking attributes.
+ return true;
+ });
+
+ if (value && name)
+ enumerators.insert_or_assign(
+ *value, FieldEnum::Enumerator(*value, name->str()));
+
+ // Find all evalue elements.
+ return true;
+ });
+
+ FieldEnum::Enumerators final_enumerators;
+ for (auto [_, enumerator] : enumerators)
+ final_enumerators.push_back(enumerator);
+
+ return final_enumerators;
+}
+
+static void
+ParseEnums(XMLNode feature_node,
+ llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {
+ Log *log(GetLog(GDBRLog::Process));
+
+ // The top level element is "<enum...".
+ feature_node.ForEachChildElementWithName(
+ "enum", [log, &registers_enum_types](const XMLNode &enum_node) {
+ std::string id;
+
+ enum_node.ForEachAttribute([&id](const llvm::StringRef &attr_name,
+ const llvm::StringRef &attr_value) {
+ if (attr_name == "id")
+ id = attr_value;
+
+ // There is also a "size" attribute that is supposed to be the size in
+ // bytes of the register this applies to. However:
+ // * LLDB doesn't need this information.
+ // * It is difficult to verify because you have to wait until the
+ // enum is applied to a field.
+ //
+ // So we will emit this attribute in XML for GDB's sake, but will not
+ // bother ingesting it.
+
+ // Walk all attributes.
+ return true;
+ });
+
+ if (!id.empty()) {
+ FieldEnum::Enumerators enumerators = ParseEnumEvalues(enum_node);
+ if (!enumerators.empty()) {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseEnums Found enum type \"{0}\"",
+ id);
+ registers_enum_types.insert_or_assign(
+ id, std::make_unique<FieldEnum>(id, enumerators));
+ }
+ }
+
+ // Find all <enum> elements.
+ return true;
+ });
+}
+
+static std::vector<RegisterFlags::Field> ParseFlagsFields(
+ XMLNode flags_node, unsigned size,
+ const llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {
+ Log *log(GetLog(GDBRLog::Process));
+ const unsigned max_start_bit = size * 8 - 1;
+
+ // Process the fields of this set of flags.
+ std::vector<RegisterFlags::Field> fields;
+ flags_node.ForEachChildElementWithName("field", [&fields, max_start_bit, &log,
+ &registers_enum_types](
+ const XMLNode
+ &field_node) {
+ std::optional<llvm::StringRef> name;
+ std::optional<unsigned> start;
+ std::optional<unsigned> end;
+ std::optional<llvm::StringRef> type;
+
+ field_node.ForEachAttribute([&name, &start, &end, &type, max_start_bit,
+ &log](const llvm::StringRef &attr_name,
+ const llvm::StringRef &attr_value) {
+ // Note that XML in general requires that each of these attributes only
+ // appears once, so we don't have to handle that here.
+ if (attr_name == "name") {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlagsFields Found field node name \"{0}\"",
+ attr_value.data());
+ name = attr_value;
+ } else if (attr_name == "start") {
+ unsigned parsed_start = 0;
+ if (llvm::to_integer(attr_value, parsed_start)) {
+ if (parsed_start > max_start_bit) {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlagsFields Invalid start {0} in "
+ "field node, "
+ "cannot be > {1}",
+ parsed_start, max_start_bit);
+ } else
+ start = parsed_start;
+ } else {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlagsFields Invalid start \"{0}\" in "
+ "field node",
+ attr_value.data());
+ }
+ } else if (attr_name == "end") {
+ unsigned parsed_end = 0;
+ if (llvm::to_integer(attr_value, parsed_end))
+ if (parsed_end > max_start_bit) {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlagsFields Invalid end {0} in "
+ "field node, "
+ "cannot be > {1}",
+ parsed_end, max_start_bit);
+ } else
+ end = parsed_end;
+ else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlagsFields Invalid end \"{0}\" in "
+ "field node",
+ attr_value.data());
+ }
+ } else if (attr_name == "type") {
+ type = attr_value;
+ } else {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlagsFields Ignoring unknown attribute "
+ "\"{0}\" in field node",
+ attr_name.data());
+ }
+
+ return true; // Walk all attributes of the field.
+ });
+
+ if (name && start && end) {
+ if (*start > *end)
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlagsFields Start {0} > end {1} in field "
+ "\"{2}\", ignoring",
+ *start, *end, name->data());
+ else {
+ if (RegisterFlags::Field::GetSizeInBits(*start, *end) > 64)
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlagsFields Ignoring field \"{2}\" "
+ "that has "
+ "size > 64 bits, this is not supported",
+ name->data());
+ else {
+ // A field's type may be set to the name of an enum type.
+ const FieldEnum *enum_type = nullptr;
+ if (type && !type->empty()) {
+ auto found = registers_enum_types.find(*type);
+ if (found != registers_enum_types.end()) {
+ enum_type = found->second.get();
+
+ // No enumerator can exceed the range of the field itself.
+ uint64_t max_value =
+ RegisterFlags::Field::GetMaxValue(*start, *end);
+ for (const auto &enumerator : enum_type->GetEnumerators()) {
+ if (enumerator.m_value > max_value) {
+ enum_type = nullptr;
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlagsFields In enum \"{0}\" "
+ "evalue \"{1}\" with value {2} exceeds the maximum value "
+ "of field \"{3}\" ({4}), ignoring enum",
+ type->data(), enumerator.m_name, enumerator.m_value,
+ name->data(), max_value);
+ break;
+ }
+ }
+ } else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlagsFields Could not find type "
+ "\"{0}\" "
+ "for field \"{1}\", ignoring",
+ type->data(), name->data());
+ }
+ }
+
+ fields.push_back(
+ RegisterFlags::Field(name->str(), *start, *end, enum_type));
+ }
+ }
+ }
+
+ return true; // Iterate all "field" nodes.
+ });
+ return fields;
+}
+
+void ParseFlags(
+ XMLNode feature_node,
+ llvm::StringMap<std::unique_ptr<RegisterFlags>> &registers_flags_types,
+ const llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {
+ Log *log(GetLog(GDBRLog::Process));
+
+ feature_node.ForEachChildElementWithName(
+ "flags",
+ [&log, &registers_flags_types,
+ &registers_enum_types](const XMLNode &flags_node) -> bool {
+ LLDB_LOG(log, "ProcessGDBRemote::ParseFlags Found flags node \"{0}\"",
+ flags_node.GetAttributeValue("id").c_str());
+
+ std::optional<llvm::StringRef> id;
+ std::optional<unsigned> size;
+ flags_node.ForEachAttribute(
+ [&id, &size, &log](const llvm::StringRef &name,
+ const llvm::StringRef &value) {
+ if (name == "id") {
+ id = value;
+ } else if (name == "size") {
+ unsigned parsed_size = 0;
+ if (llvm::to_integer(value, parsed_size))
+ size = parsed_size;
+ else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlags Invalid size \"{0}\" "
+ "in flags node",
+ value.data());
+ }
+ } else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlags Ignoring unknown "
+ "attribute \"{0}\" in flags node",
+ name.data());
+ }
+ return true; // Walk all attributes.
+ });
+
+ if (id && size) {
+ // Process the fields of this set of flags.
+ std::vector<RegisterFlags::Field> fields =
+ ParseFlagsFields(flags_node, *size, registers_enum_types);
+ if (fields.size()) {
+ // Sort so that the fields with the MSBs are first.
+ std::sort(fields.rbegin(), fields.rend());
+ std::vector<RegisterFlags::Field>::const_iterator overlap =
+ std::adjacent_find(fields.begin(), fields.end(),
+ [](const RegisterFlags::Field &lhs,
+ const RegisterFlags::Field &rhs) {
+ return lhs.Overlaps(rhs);
+ });
+
+ // If no fields overlap, use them.
+ if (overlap == fields.end()) {
+ if (registers_flags_types.contains(*id)) {
+ // In theory you could define some flag set, use it with a
+ // register then redefine it. We do not know if anyone does
+ // that, or what they would expect to happen in that case.
+ //
+ // LLDB chooses to take the first definition and ignore the rest
+ // as waiting until everything has been processed is more
+ // expensive and difficult. This means that pointers to flag
+ // sets in the register info remain valid if later the flag set
+ // is redefined. If we allowed redefinitions, LLDB would crash
+ // when you tried to print a register that used the original
+ // definition.
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlags Definition of flags "
+ "\"{0}\" shadows "
+ "previous definition, using original definition instead.",
+ id->data());
+ } else {
+ registers_flags_types.insert_or_assign(
+ *id, std::make_unique<RegisterFlags>(id->str(), *size,
+ std::move(fields)));
+ }
+ } else {
+ // If any fields overlap, ignore the whole set of flags.
+ std::vector<RegisterFlags::Field>::const_iterator next =
+ std::next(overlap);
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlags Ignoring flags because fields "
+ "{0} (start: {1} end: {2}) and {3} (start: {4} end: {5}) "
+ "overlap.",
+ overlap->GetName().c_str(), overlap->GetStart(),
+ overlap->GetEnd(), next->GetName().c_str(), next->GetStart(),
+ next->GetEnd());
+ }
+ } else {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlags Ignoring definition of flags "
+ "\"{0}\" because it contains no fields.",
+ id->data());
+ }
+ }
+
+ return true; // Keep iterating through all "flags" elements.
+ });
+}
+
+bool ParseRegisters(
+ XMLNode feature_node, GdbServerTargetInfo &target_info,
+ std::vector<DynamicRegisterInfo::Register> &registers,
+ llvm::StringMap<std::unique_ptr<RegisterFlags>> &registers_flags_types,
+ llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {
+ if (!feature_node)
+ return false;
+
+ Log *log(GetLog(GDBRLog::Process));
+
+ // Enums first because they are referenced by fields in the flags.
+ ParseEnums(feature_node, registers_enum_types);
+ for (const auto &enum_type : registers_enum_types)
+ enum_type.second->DumpToLog(log);
+
+ ParseFlags(feature_node, registers_flags_types, registers_enum_types);
+ for (const auto &flags : registers_flags_types)
+ flags.second->DumpToLog(log);
+
+ feature_node.ForEachChildElementWithName(
+ "reg",
+ [&target_info, &registers, &registers_flags_types,
+ log](const XMLNode &reg_node) -> bool {
+ std::string gdb_group;
+ std::string gdb_type;
+ DynamicRegisterInfo::Register reg_info;
+ bool encoding_set = false;
+ bool format_set = false;
+
+ // FIXME: we're silently ignoring invalid data here
+ reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type,
+ &encoding_set, &format_set, &reg_info,
+ log](const llvm::StringRef &name,
+ const llvm::StringRef &value) -> bool {
+ if (name == "name") {
+ reg_info.name.SetString(value);
+ } else if (name == "bitsize") {
+ if (llvm::to_integer(value, reg_info.byte_size))
+ reg_info.byte_size =
+ llvm::divideCeil(reg_info.byte_size, CHAR_BIT);
+ } else if (name == "type") {
+ gdb_type = value.str();
+ } else if (name == "group") {
+ gdb_group = value.str();
+ } else if (name == "regnum") {
+ llvm::to_integer(value, reg_info.regnum_remote);
+ } else if (name == "offset") {
+ llvm::to_integer(value, reg_info.byte_offset);
+ } else if (name == "altname") {
+ reg_info.alt_name.SetString(value);
+ } else if (name == "encoding") {
+ encoding_set = true;
+ reg_info.encoding = Args::StringToEncoding(value, eEncodingUint);
+ } else if (name == "format") {
+ format_set = true;
+ if (!OptionArgParser::ToFormat(value.data(), reg_info.format,
+ nullptr)
+ .Success())
+ reg_info.format =
+ llvm::StringSwitch<lldb::Format>(value)
+ .Case("vector-sint8", eFormatVectorOfSInt8)
+ .Case("vector-uint8", eFormatVectorOfUInt8)
+ .Case("vector-sint16", eFormatVectorOfSInt16)
+ .Case("vector-uint16", eFormatVectorOfUInt16)
+ .Case("vector-sint32", eFormatVectorOfSInt32)
+ .Case("vector-uint32", eFormatVectorOfUInt32)
+ .Case("vector-float32", eFormatVectorOfFloat32)
+ .Case("vector-uint64", eFormatVectorOfUInt64)
+ .Case("vector-uint128", eFormatVectorOfUInt128)
+ .Default(eFormatInvalid);
+ } else if (name == "group_id") {
+ uint32_t set_id = UINT32_MAX;
+ llvm::to_integer(value, set_id);
+ RegisterSetMap::const_iterator pos =
+ target_info.reg_set_map.find(set_id);
+ if (pos != target_info.reg_set_map.end())
+ reg_info.set_name = pos->second.name;
+ } else if (name == "gcc_regnum" || name == "ehframe_regnum") {
+ llvm::to_integer(value, reg_info.regnum_ehframe);
+ } else if (name == "dwarf_regnum") {
+ llvm::to_integer(value, reg_info.regnum_dwarf);
+ } else if (name == "generic") {
+ reg_info.regnum_generic = Args::StringToGenericRegister(value);
+ } else if (name == "value_regnums") {
+ SplitCommaSeparatedRegisterNumberString(value, reg_info.value_regs,
+ 0);
+ } else if (name == "invalidate_regnums") {
+ SplitCommaSeparatedRegisterNumberString(
+ value, reg_info.invalidate_regs, 0);
+ } else {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::ParseRegisters unhandled reg "
+ "attribute %s = %s",
+ name.data(), value.data());
+ }
+ return true; // Keep iterating through all attributes
+ });
+
+ if (!gdb_type.empty()) {
+ // gdb_type could reference some flags type defined in XML.
+ llvm::StringMap<std::unique_ptr<RegisterFlags>>::iterator it =
+ registers_flags_types.find(gdb_type);
+ if (it != registers_flags_types.end()) {
+ auto flags_type = it->second.get();
+ if (reg_info.byte_size == flags_type->GetSize())
+ reg_info.flags_type = flags_type;
+ else
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::ParseRegisters Size of register "
+ "flags %s (%d bytes) for "
+ "register %s does not match the register size (%d "
+ "bytes). Ignoring this set of flags.",
+ flags_type->GetID().c_str(), flags_type->GetSize(),
+ reg_info.name.AsCString(), reg_info.byte_size);
+ }
+
+ // There's a slim chance that the gdb_type name is both a flags type
+ // and a simple type. Just in case, look for that too (setting both
+ // does no harm).
+ if (!gdb_type.empty() && !(encoding_set || format_set)) {
+ if (llvm::StringRef(gdb_type).starts_with("int")) {
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ } else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") {
+ reg_info.format = eFormatAddressInfo;
+ reg_info.encoding = eEncodingUint;
+ } else if (gdb_type == "float") {
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ } else if (gdb_type == "aarch64v" ||
+ llvm::StringRef(gdb_type).starts_with("vec") ||
+ gdb_type == "i387_ext" || gdb_type == "uint128") {
+ // lldb doesn't handle 128-bit uints correctly (for ymm*h), so
+ // treat them as vector (similarly to xmm/ymm)
+ reg_info.format = eFormatVectorOfUInt8;
+ reg_info.encoding = eEncodingVector;
+ } else {
+ LLDB_LOGF(
+ log,
+ "ProcessGDBRemote::ParseRegisters Could not determine lldb"
+ "format and encoding for gdb type %s",
+ gdb_type.c_str());
+ }
+ }
+ }
+
+ // 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 (!reg_info.set_name) {
+ if (!gdb_group.empty()) {
+ reg_info.set_name.SetCString(gdb_group.c_str());
+ } else {
+ // If no register group name provided anywhere,
+ // we'll create a 'general' register set
+ reg_info.set_name.SetCString("general");
+ }
+ }
+
+ if (reg_info.byte_size == 0) {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s Skipping zero bitsize register %s",
+ __FUNCTION__, reg_info.name.AsCString());
+ } else
+ registers.push_back(reg_info);
+
+ return true; // Keep iterating through all "reg" elements
+ });
+ return true;
+}
+
+} // namespace
+
+// This method fetches a register description feature xml file from
+// the remote stub and adds registers/register groupsets/architecture
+// information to the current process. It will call itself recursively
+// for nested register definition files. It returns true if it was able
+// to fetch and parse an xml file.
+bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
+ ArchSpec &arch_to_use, std::string xml_filename,
+ std::vector<DynamicRegisterInfo::Register> &registers) {
+ // request the target xml file
+ llvm::Expected<std::string> raw = m_gdb_comm.ReadExtFeature("features", xml_filename);
+ if (errorToBool(raw.takeError()))
+ return false;
+
+ XMLDocument xml_document;
+
+ if (xml_document.ParseMemory(raw->c_str(), raw->size(),
+ xml_filename.c_str())) {
+ GdbServerTargetInfo target_info;
+ std::vector<XMLNode> feature_nodes;
+
+ // The top level feature XML file will start with a <target> tag.
+ XMLNode target_node = xml_document.GetRootElement("target");
+ if (target_node) {
+ target_node.ForEachChildElement([&target_info, &feature_nodes](
+ const XMLNode &node) -> bool {
+ llvm::StringRef name = node.GetName();
+ if (name == "architecture") {
+ node.GetElementText(target_info.arch);
+ } else if (name == "osabi") {
+ node.GetElementText(target_info.osabi);
+ } else if (name == "xi:include" || name == "include") {
+ std::string href = node.GetAttributeValue("href");
+ if (!href.empty())
+ target_info.includes.push_back(href);
+ } else if (name == "feature") {
+ feature_nodes.push_back(node);
+ } else if (name == "groups") {
+ 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 {
+ // FIXME: we're silently ignoring invalid data here
+ if (name == "id")
+ llvm::to_integer(value, set_id);
+ if (name == "name")
+ 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
+ });
+ }
+ return true; // Keep iterating through all children of the target_node
+ });
+ } else {
+ // In an included XML feature file, we're already "inside" the <target>
+ // tag of the initial XML file; this included file will likely only have
+ // a <feature> tag. Need to check for any more included files in this
+ // <feature> element.
+ XMLNode feature_node = xml_document.GetRootElement("feature");
+ if (feature_node) {
+ feature_nodes.push_back(feature_node);
+ feature_node.ForEachChildElement([&target_info](
+ const XMLNode &node) -> bool {
+ llvm::StringRef name = node.GetName();
+ if (name == "xi:include" || name == "include") {
+ std::string href = node.GetAttributeValue("href");
+ if (!href.empty())
+ target_info.includes.push_back(href);
+ }
+ return true;
+ });
+ }
+ }
+
+ // gdbserver does not implement the LLDB packets used to determine host
+ // or process architecture. If that is the case, attempt to use
+ // the <architecture/> field from target.xml, e.g.:
+ //
+ // <architecture>i386:x86-64</architecture> (seen from VMWare ESXi)
+ // <architecture>arm</architecture> (seen from Segger JLink on unspecified
+ // arm board)
+ if (!arch_to_use.IsValid() && !target_info.arch.empty()) {
+ // We don't have any information about vendor or OS.
+ arch_to_use.SetTriple(llvm::StringSwitch<std::string>(target_info.arch)
+ .Case("i386:x86-64", "x86_64")
+ .Case("riscv:rv64", "riscv64")
+ .Case("riscv:rv32", "riscv32")
+ .Default(target_info.arch) +
+ "--");
+
+ if (arch_to_use.IsValid())
+ GetTarget().MergeArchitecture(arch_to_use);
+ }
+
+ if (arch_to_use.IsValid()) {
+ for (auto &feature_node : feature_nodes) {
+ ParseRegisters(feature_node, target_info, registers,
+ m_registers_flags_types, m_registers_enum_types);
+ }
+
+ for (const auto &include : target_info.includes) {
+ GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include,
+ registers);
+ }
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+void ProcessGDBRemote::AddRemoteRegisters(
+ std::vector<DynamicRegisterInfo::Register> &registers,
+ const ArchSpec &arch_to_use) {
+ std::map<uint32_t, uint32_t> remote_to_local_map;
+ uint32_t remote_regnum = 0;
+ for (auto it : llvm::enumerate(registers)) {
+ DynamicRegisterInfo::Register &remote_reg_info = it.value();
+
+ // Assign successive remote regnums if missing.
+ if (remote_reg_info.regnum_remote == LLDB_INVALID_REGNUM)
+ remote_reg_info.regnum_remote = remote_regnum;
+
+ // Create a mapping from remote to local regnos.
+ remote_to_local_map[remote_reg_info.regnum_remote] = it.index();
+
+ remote_regnum = remote_reg_info.regnum_remote + 1;
+ }
+
+ for (DynamicRegisterInfo::Register &remote_reg_info : registers) {
+ auto proc_to_lldb = [&remote_to_local_map](uint32_t process_regnum) {
+ auto lldb_regit = remote_to_local_map.find(process_regnum);
+ return lldb_regit != remote_to_local_map.end() ? lldb_regit->second
+ : LLDB_INVALID_REGNUM;
+ };
+
+ llvm::transform(remote_reg_info.value_regs,
+ remote_reg_info.value_regs.begin(), proc_to_lldb);
+ llvm::transform(remote_reg_info.invalidate_regs,
+ remote_reg_info.invalidate_regs.begin(), proc_to_lldb);
+ }
+
+ // Don't use Process::GetABI, this code gets called from DidAttach, and
+ // in that context we haven't set the Target's architecture yet, so the
+ // ABI is also potentially incorrect.
+ if (ABISP abi_sp = ABI::FindPlugin(shared_from_this(), arch_to_use))
+ abi_sp->AugmentRegisterInfo(registers);
+
+ m_register_info_sp->SetRegisterInfo(std::move(registers), arch_to_use);
+}
+
+// query the target of gdb-remote for extended target information returns
+// true on success (got register definitions), false on failure (did not).
+bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
+ // Make sure LLDB has an XML parser it can use first
+ if (!XMLDocument::XMLEnabled())
+ return false;
+
+ // check that we have extended feature read support
+ if (!m_gdb_comm.GetQXferFeaturesReadSupported())
+ return false;
+
+ // These hold register type information for the whole of target.xml.
+ // target.xml may include further documents that
+ // GetGDBServerRegisterInfoXMLAndProcess will recurse to fetch and process.
+ // That's why we clear the cache here, and not in
+ // GetGDBServerRegisterInfoXMLAndProcess. To prevent it being cleared on every
+ // include read.
+ m_registers_flags_types.clear();
+ m_registers_enum_types.clear();
+ std::vector<DynamicRegisterInfo::Register> registers;
+ if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml",
+ registers) &&
+ // Target XML is not required to include register information.
+ !registers.empty())
+ AddRemoteRegisters(registers, arch_to_use);
+
+ return m_register_info_sp->GetNumRegisters() > 0;
+}
+
+llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {
+ // Make sure LLDB has an XML parser it can use first
+ if (!XMLDocument::XMLEnabled())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "XML parsing not available");
+
+ Log *log = GetLog(LLDBLog::Process);
+ LLDB_LOGF(log, "ProcessGDBRemote::%s", __FUNCTION__);
+
+ LoadedModuleInfoList list;
+ GDBRemoteCommunicationClient &comm = m_gdb_comm;
+ bool can_use_svr4 = GetGlobalPluginProperties().GetUseSVR4();
+
+ // check that we have extended feature read support
+ if (can_use_svr4 && comm.GetQXferLibrariesSVR4ReadSupported()) {
+ // request the loaded library list
+ llvm::Expected<std::string> raw = comm.ReadExtFeature("libraries-svr4", "");
+ if (!raw)
+ return raw.takeError();
+
+ // parse the xml file in memory
+ LLDB_LOGF(log, "parsing: %s", raw->c_str());
+ XMLDocument doc;
+
+ if (!doc.ParseMemory(raw->c_str(), raw->size(), "noname.xml"))
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Error reading noname.xml");
+
+ XMLNode root_element = doc.GetRootElement("library-list-svr4");
+ if (!root_element)
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Error finding library-list-svr4 xml element");
+
+ // main link map structure
+ std::string main_lm = root_element.GetAttributeValue("main-lm");
+ // FIXME: we're silently ignoring invalid data here
+ if (!main_lm.empty())
+ llvm::to_integer(main_lm, list.m_link_map);
+
+ root_element.ForEachChildElementWithName(
+ "library", [log, &list](const XMLNode &library) -> bool {
+ LoadedModuleInfoList::LoadedModuleInfo module;
+
+ // FIXME: we're silently ignoring invalid data here
+ library.ForEachAttribute(
+ [&module](const llvm::StringRef &name,
+ const llvm::StringRef &value) -> bool {
+ uint64_t uint_value = LLDB_INVALID_ADDRESS;
+ if (name == "name")
+ module.set_name(value.str());
+ else if (name == "lm") {
+ // the address of the link_map struct.
+ llvm::to_integer(value, uint_value);
+ module.set_link_map(uint_value);
+ } else if (name == "l_addr") {
+ // the displacement as read from the field 'l_addr' of the
+ // link_map struct.
+ llvm::to_integer(value, uint_value);
+ module.set_base(uint_value);
+ // base address is always a displacement, not an absolute
+ // value.
+ module.set_base_is_offset(true);
+ } else if (name == "l_ld") {
+ // the memory address of the libraries PT_DYNAMIC section.
+ llvm::to_integer(value, uint_value);
+ module.set_dynamic(uint_value);
+ }
+
+ return true; // Keep iterating over all properties of "library"
+ });
+
+ if (log) {
+ std::string name;
+ lldb::addr_t lm = 0, base = 0, ld = 0;
+ bool base_is_offset;
+
+ module.get_name(name);
+ module.get_link_map(lm);
+ module.get_base(base);
+ module.get_base_is_offset(base_is_offset);
+ module.get_dynamic(ld);
+
+ LLDB_LOGF(log,
+ "found (link_map:0x%08" PRIx64 ", base:0x%08" PRIx64
+ "[%s], ld:0x%08" PRIx64 ", name:'%s')",
+ lm, base, (base_is_offset ? "offset" : "absolute"), ld,
+ name.c_str());
+ }
+
+ list.add(module);
+ return true; // Keep iterating over all "library" elements in the root
+ // node
+ });
+
+ if (log)
+ LLDB_LOGF(log, "found %" PRId32 " modules in total",
+ (int)list.m_list.size());
+ return list;
+ } else if (comm.GetQXferLibrariesReadSupported()) {
+ // request the loaded library list
+ llvm::Expected<std::string> raw = comm.ReadExtFeature("libraries", "");
+
+ if (!raw)
+ return raw.takeError();
+
+ LLDB_LOGF(log, "parsing: %s", raw->c_str());
+ XMLDocument doc;
+
+ if (!doc.ParseMemory(raw->c_str(), raw->size(), "noname.xml"))
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Error reading noname.xml");
+
+ XMLNode root_element = doc.GetRootElement("library-list");
+ if (!root_element)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Error finding library-list xml element");
+
+ // FIXME: we're silently ignoring invalid data here
+ root_element.ForEachChildElementWithName(
+ "library", [log, &list](const XMLNode &library) -> bool {
+ LoadedModuleInfoList::LoadedModuleInfo module;
+
+ std::string name = library.GetAttributeValue("name");
+ module.set_name(name);
+
+ // The base address of a given library will be the address of its
+ // first section. Most remotes send only one section for Windows
+ // targets for example.
+ const XMLNode &section =
+ library.FindFirstChildElementWithName("section");
+ std::string address = section.GetAttributeValue("address");
+ uint64_t address_value = LLDB_INVALID_ADDRESS;
+ llvm::to_integer(address, address_value);
+ module.set_base(address_value);
+ // These addresses are absolute values.
+ module.set_base_is_offset(false);
+
+ if (log) {
+ std::string name;
+ lldb::addr_t base = 0;
+ bool base_is_offset;
+ module.get_name(name);
+ module.get_base(base);
+ module.get_base_is_offset(base_is_offset);
+
+ LLDB_LOGF(log, "found (base:0x%08" PRIx64 "[%s], name:'%s')", base,
+ (base_is_offset ? "offset" : "absolute"), name.c_str());
+ }
+
+ list.add(module);
+ return true; // Keep iterating over all "library" elements in the root
+ // node
+ });
+
+ if (log)
+ LLDB_LOGF(log, "found %" PRId32 " modules in total",
+ (int)list.m_list.size());
+ return list;
+ } else {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Remote libraries not supported");
+ }
+}
+
+lldb::ModuleSP ProcessGDBRemote::LoadModuleAtAddress(const FileSpec &file,
+ lldb::addr_t link_map,
+ lldb::addr_t base_addr,
+ bool value_is_offset) {
+ DynamicLoader *loader = GetDynamicLoader();
+ if (!loader)
+ return nullptr;
+
+ return loader->LoadModuleAtAddress(file, link_map, base_addr,
+ value_is_offset);
+}
+
+llvm::Error ProcessGDBRemote::LoadModules() {
+ using lldb_private::process_gdb_remote::ProcessGDBRemote;
+
+ // request a list of loaded libraries from GDBServer
+ llvm::Expected<LoadedModuleInfoList> module_list = GetLoadedModuleList();
+ if (!module_list)
+ return module_list.takeError();
+
+ // get a list of all the modules
+ ModuleList new_modules;
+
+ for (LoadedModuleInfoList::LoadedModuleInfo &modInfo : module_list->m_list) {
+ std::string mod_name;
+ lldb::addr_t mod_base;
+ lldb::addr_t link_map;
+ bool mod_base_is_offset;
+
+ bool valid = true;
+ valid &= modInfo.get_name(mod_name);
+ valid &= modInfo.get_base(mod_base);
+ valid &= modInfo.get_base_is_offset(mod_base_is_offset);
+ if (!valid)
+ continue;
+
+ if (!modInfo.get_link_map(link_map))
+ link_map = LLDB_INVALID_ADDRESS;
+
+ FileSpec file(mod_name);
+ FileSystem::Instance().Resolve(file);
+ lldb::ModuleSP module_sp =
+ LoadModuleAtAddress(file, link_map, mod_base, mod_base_is_offset);
+
+ if (module_sp.get())
+ new_modules.Append(module_sp);
+ }
+
+ if (new_modules.GetSize() > 0) {
+ ModuleList removed_modules;
+ Target &target = GetTarget();
+ ModuleList &loaded_modules = m_process->GetTarget().GetImages();
+
+ for (size_t i = 0; i < loaded_modules.GetSize(); ++i) {
+ const lldb::ModuleSP loaded_module = loaded_modules.GetModuleAtIndex(i);
+
+ bool found = false;
+ for (size_t j = 0; j < new_modules.GetSize(); ++j) {
+ if (new_modules.GetModuleAtIndex(j).get() == loaded_module.get())
+ found = true;
+ }
+
+ // The main executable will never be included in libraries-svr4, don't
+ // remove it
+ if (!found &&
+ loaded_module.get() != target.GetExecutableModulePointer()) {
+ removed_modules.Append(loaded_module);
+ }
+ }
+
+ loaded_modules.Remove(removed_modules);
+ m_process->GetTarget().ModulesDidUnload(removed_modules, false);
+
+ new_modules.ForEach([&target](const lldb::ModuleSP module_sp) -> bool {
+ lldb_private::ObjectFile *obj = module_sp->GetObjectFile();
+ if (!obj)
+ return true;
+
+ if (obj->GetType() != ObjectFile::Type::eTypeExecutable)
+ return true;
+
+ lldb::ModuleSP module_copy_sp = module_sp;
+ target.SetExecutableModule(module_copy_sp, eLoadDependentsNo);
+ return false;
+ });
+
+ loaded_modules.AppendIfNeeded(new_modules);
+ m_process->GetTarget().ModulesDidLoad(new_modules);
+ }
+
+ return llvm::ErrorSuccess();
+}
+
+Status ProcessGDBRemote::GetFileLoadAddress(const FileSpec &file,
+ bool &is_loaded,
+ lldb::addr_t &load_addr) {
+ is_loaded = false;
+ load_addr = LLDB_INVALID_ADDRESS;
+
+ std::string file_path = file.GetPath(false);
+ if (file_path.empty())
+ return Status("Empty file name specified");
+
+ StreamString packet;
+ packet.PutCString("qFileLoadAddress:");
+ packet.PutStringAsRawHex8(file_path);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success)
+ return Status("Sending qFileLoadAddress packet failed");
+
+ if (response.IsErrorResponse()) {
+ if (response.GetError() == 1) {
+ // The file is not loaded into the inferior
+ is_loaded = false;
+ load_addr = LLDB_INVALID_ADDRESS;
+ return Status();
+ }
+
+ return Status(
+ "Fetching file load address from remote server returned an error");
+ }
+
+ if (response.IsNormalResponse()) {
+ is_loaded = true;
+ load_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ return Status();
+ }
+
+ return Status(
+ "Unknown error happened during sending the load address packet");
+}
+
+void ProcessGDBRemote::ModulesDidLoad(ModuleList &module_list) {
+ // We must call the lldb_private::Process::ModulesDidLoad () first before we
+ // do anything
+ Process::ModulesDidLoad(module_list);
+
+ // After loading shared libraries, we can ask our remote GDB server if it
+ // needs any symbols.
+ m_gdb_comm.ServeSymbolLookups(this);
+}
+
+void ProcessGDBRemote::HandleAsyncStdout(llvm::StringRef out) {
+ AppendSTDOUT(out.data(), out.size());
+}
+
+static const char *end_delimiter = "--end--;";
+static const int end_delimiter_len = 8;
+
+void ProcessGDBRemote::HandleAsyncMisc(llvm::StringRef data) {
+ std::string input = data.str(); // '1' to move beyond 'A'
+ if (m_partial_profile_data.length() > 0) {
+ m_partial_profile_data.append(input);
+ input = m_partial_profile_data;
+ m_partial_profile_data.clear();
+ }
+
+ size_t found, pos = 0, len = input.length();
+ while ((found = input.find(end_delimiter, pos)) != std::string::npos) {
+ StringExtractorGDBRemote profileDataExtractor(
+ input.substr(pos, found).c_str());
+ std::string profile_data =
+ HarmonizeThreadIdsForProfileData(profileDataExtractor);
+ BroadcastAsyncProfileData(profile_data);
+
+ pos = found + end_delimiter_len;
+ }
+
+ if (pos < len) {
+ // Last incomplete chunk.
+ m_partial_profile_data = input.substr(pos);
+ }
+}
+
+std::string ProcessGDBRemote::HarmonizeThreadIdsForProfileData(
+ StringExtractorGDBRemote &profileDataExtractor) {
+ std::map<uint64_t, uint32_t> new_thread_id_to_used_usec_map;
+ std::string output;
+ llvm::raw_string_ostream output_stream(output);
+ llvm::StringRef name, value;
+
+ // Going to assuming thread_used_usec comes first, else bail out.
+ while (profileDataExtractor.GetNameColonValue(name, value)) {
+ if (name.compare("thread_used_id") == 0) {
+ StringExtractor threadIDHexExtractor(value);
+ uint64_t thread_id = threadIDHexExtractor.GetHexMaxU64(false, 0);
+
+ bool has_used_usec = false;
+ uint32_t curr_used_usec = 0;
+ llvm::StringRef usec_name, usec_value;
+ uint32_t input_file_pos = profileDataExtractor.GetFilePos();
+ if (profileDataExtractor.GetNameColonValue(usec_name, usec_value)) {
+ if (usec_name == "thread_used_usec") {
+ has_used_usec = true;
+ usec_value.getAsInteger(0, curr_used_usec);
+ } else {
+ // We didn't find what we want, it is probably an older version. Bail
+ // out.
+ profileDataExtractor.SetFilePos(input_file_pos);
+ }
+ }
+
+ if (has_used_usec) {
+ uint32_t prev_used_usec = 0;
+ std::map<uint64_t, uint32_t>::iterator iterator =
+ m_thread_id_to_used_usec_map.find(thread_id);
+ if (iterator != m_thread_id_to_used_usec_map.end()) {
+ prev_used_usec = m_thread_id_to_used_usec_map[thread_id];
+ }
+
+ uint32_t real_used_usec = curr_used_usec - prev_used_usec;
+ // A good first time record is one that runs for at least 0.25 sec
+ bool good_first_time =
+ (prev_used_usec == 0) && (real_used_usec > 250000);
+ bool good_subsequent_time =
+ (prev_used_usec > 0) &&
+ ((real_used_usec > 0) || (HasAssignedIndexIDToThread(thread_id)));
+
+ if (good_first_time || good_subsequent_time) {
+ // We try to avoid doing too many index id reservation, resulting in
+ // fast increase of index ids.
+
+ output_stream << name << ":";
+ int32_t index_id = AssignIndexIDToThread(thread_id);
+ output_stream << index_id << ";";
+
+ output_stream << usec_name << ":" << usec_value << ";";
+ } else {
+ // Skip past 'thread_used_name'.
+ llvm::StringRef local_name, local_value;
+ profileDataExtractor.GetNameColonValue(local_name, local_value);
+ }
+
+ // Store current time as previous time so that they can be compared
+ // later.
+ new_thread_id_to_used_usec_map[thread_id] = curr_used_usec;
+ } else {
+ // Bail out and use old string.
+ output_stream << name << ":" << value << ";";
+ }
+ } else {
+ output_stream << name << ":" << value << ";";
+ }
+ }
+ output_stream << end_delimiter;
+ m_thread_id_to_used_usec_map = new_thread_id_to_used_usec_map;
+
+ return output_stream.str();
+}
+
+void ProcessGDBRemote::HandleStopReply() {
+ if (GetStopID() != 0)
+ return;
+
+ if (GetID() == LLDB_INVALID_PROCESS_ID) {
+ lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ SetID(pid);
+ }
+ BuildDynamicRegisterInfo(true);
+}
+
+llvm::Expected<bool> ProcessGDBRemote::SaveCore(llvm::StringRef outfile) {
+ if (!m_gdb_comm.GetSaveCoreSupported())
+ return false;
+
+ StreamString packet;
+ packet.PutCString("qSaveCore;path-hint:");
+ packet.PutStringAsRawHex8(outfile);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ // TODO: grab error message from the packet? StringExtractor seems to
+ // be missing a method for that
+ if (response.IsErrorResponse())
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ llvm::formatv("qSaveCore returned an error"));
+
+ std::string path;
+
+ // process the response
+ for (auto x : llvm::split(response.GetStringRef(), ';')) {
+ if (x.consume_front("core-path:"))
+ StringExtractor(x).GetHexByteString(path);
+ }
+
+ // verify that we've gotten what we need
+ if (path.empty())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "qSaveCore returned no core path");
+
+ // now transfer the core file
+ FileSpec remote_core{llvm::StringRef(path)};
+ Platform &platform = *GetTarget().GetPlatform();
+ Status error = platform.GetFile(remote_core, FileSpec(outfile));
+
+ if (platform.IsRemote()) {
+ // NB: we unlink the file on error too
+ platform.Unlink(remote_core);
+ if (error.Fail())
+ return error.ToError();
+ }
+
+ return true;
+ }
+
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Unable to send qSaveCore");
+}
+
+static const char *const s_async_json_packet_prefix = "JSON-async:";
+
+static StructuredData::ObjectSP
+ParseStructuredDataPacket(llvm::StringRef packet) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ if (!packet.consume_front(s_async_json_packet_prefix)) {
+ if (log) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationClientBase::%s() received $J packet "
+ "but was not a StructuredData packet: packet starts with "
+ "%s",
+ __FUNCTION__,
+ packet.slice(0, strlen(s_async_json_packet_prefix)).str().c_str());
+ }
+ return StructuredData::ObjectSP();
+ }
+
+ // This is an asynchronous JSON packet, destined for a StructuredDataPlugin.
+ StructuredData::ObjectSP json_sp = StructuredData::ParseJSON(packet);
+ if (log) {
+ if (json_sp) {
+ StreamString json_str;
+ json_sp->Dump(json_str, true);
+ json_str.Flush();
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s() "
+ "received Async StructuredData packet: %s",
+ __FUNCTION__, json_str.GetData());
+ } else {
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s"
+ "() received StructuredData packet:"
+ " parse failure",
+ __FUNCTION__);
+ }
+ }
+ return json_sp;
+}
+
+void ProcessGDBRemote::HandleAsyncStructuredDataPacket(llvm::StringRef data) {
+ auto structured_data_sp = ParseStructuredDataPacket(data);
+ if (structured_data_sp)
+ RouteAsyncStructuredData(structured_data_sp);
+}
+
+class CommandObjectProcessGDBRemoteSpeedTest : public CommandObjectParsed {
+public:
+ CommandObjectProcessGDBRemoteSpeedTest(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "process plugin packet speed-test",
+ "Tests packet speeds of various sizes to determine "
+ "the performance characteristics of the GDB remote "
+ "connection. ",
+ nullptr),
+ m_option_group(),
+ m_num_packets(LLDB_OPT_SET_1, false, "count", 'c', 0, eArgTypeCount,
+ "The number of packets to send of each varying size "
+ "(default is 1000).",
+ 1000),
+ m_max_send(LLDB_OPT_SET_1, false, "max-send", 's', 0, eArgTypeCount,
+ "The maximum number of bytes to send in a packet. Sizes "
+ "increase in powers of 2 while the size is less than or "
+ "equal to this option value. (default 1024).",
+ 1024),
+ m_max_recv(LLDB_OPT_SET_1, false, "max-receive", 'r', 0, eArgTypeCount,
+ "The maximum number of bytes to receive in a packet. Sizes "
+ "increase in powers of 2 while the size is less than or "
+ "equal to this option value. (default 1024).",
+ 1024),
+ m_json(LLDB_OPT_SET_1, false, "json", 'j',
+ "Print the output as JSON data for easy parsing.", false, true) {
+ m_option_group.Append(&m_num_packets, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append(&m_max_send, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append(&m_max_recv, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append(&m_json, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectProcessGDBRemoteSpeedTest() override = default;
+
+ Options *GetOptions() override { return &m_option_group; }
+
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0) {
+ ProcessGDBRemote *process =
+ (ProcessGDBRemote *)m_interpreter.GetExecutionContext()
+ .GetProcessPtr();
+ if (process) {
+ StreamSP output_stream_sp = result.GetImmediateOutputStream();
+ if (!output_stream_sp)
+ output_stream_sp =
+ StreamSP(m_interpreter.GetDebugger().GetAsyncOutputStream());
+ result.SetImmediateOutputStream(output_stream_sp);
+
+ const uint32_t num_packets =
+ (uint32_t)m_num_packets.GetOptionValue().GetCurrentValue();
+ const uint64_t max_send = m_max_send.GetOptionValue().GetCurrentValue();
+ const uint64_t max_recv = m_max_recv.GetOptionValue().GetCurrentValue();
+ const bool json = m_json.GetOptionValue().GetCurrentValue();
+ const uint64_t k_recv_amount =
+ 4 * 1024 * 1024; // Receive amount in bytes
+ process->GetGDBRemote().TestPacketSpeed(
+ num_packets, max_send, max_recv, k_recv_amount, json,
+ output_stream_sp ? *output_stream_sp : result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return;
+ }
+ } else {
+ result.AppendErrorWithFormat("'%s' takes no arguments",
+ m_cmd_name.c_str());
+ }
+ result.SetStatus(eReturnStatusFailed);
+ }
+
+protected:
+ OptionGroupOptions m_option_group;
+ OptionGroupUInt64 m_num_packets;
+ OptionGroupUInt64 m_max_send;
+ OptionGroupUInt64 m_max_recv;
+ OptionGroupBoolean m_json;
+};
+
+class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed {
+private:
+public:
+ CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "process plugin packet history",
+ "Dumps the packet history buffer. ", nullptr) {}
+
+ ~CommandObjectProcessGDBRemotePacketHistory() override = default;
+
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ ProcessGDBRemote *process =
+ (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process) {
+ process->DumpPluginHistory(result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return;
+ }
+ result.SetStatus(eReturnStatusFailed);
+ }
+};
+
+class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed {
+private:
+public:
+ CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "process plugin packet xfer-size",
+ "Maximum size that lldb will try to read/write one one chunk.",
+ nullptr) {
+ AddSimpleArgumentList(eArgTypeUnsignedInteger);
+ }
+
+ ~CommandObjectProcessGDBRemotePacketXferSize() override = default;
+
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0) {
+ result.AppendErrorWithFormat("'%s' takes an argument to specify the max "
+ "amount to be transferred when "
+ "reading/writing",
+ m_cmd_name.c_str());
+ return;
+ }
+
+ ProcessGDBRemote *process =
+ (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process) {
+ const char *packet_size = command.GetArgumentAtIndex(0);
+ errno = 0;
+ uint64_t user_specified_max = strtoul(packet_size, nullptr, 10);
+ if (errno == 0 && user_specified_max != 0) {
+ process->SetUserSpecifiedMaxMemoryTransferSize(user_specified_max);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return;
+ }
+ }
+ result.SetStatus(eReturnStatusFailed);
+ }
+};
+
+class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed {
+private:
+public:
+ CommandObjectProcessGDBRemotePacketSend(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "process plugin packet send",
+ "Send a custom packet through the GDB remote "
+ "protocol and print the answer. "
+ "The packet header and footer will automatically "
+ "be added to the packet prior to sending and "
+ "stripped from the result.",
+ nullptr) {
+ AddSimpleArgumentList(eArgTypeNone, eArgRepeatStar);
+ }
+
+ ~CommandObjectProcessGDBRemotePacketSend() override = default;
+
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0) {
+ result.AppendErrorWithFormat(
+ "'%s' takes a one or more packet content arguments",
+ m_cmd_name.c_str());
+ return;
+ }
+
+ ProcessGDBRemote *process =
+ (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process) {
+ for (size_t i = 0; i < argc; ++i) {
+ const char *packet_cstr = command.GetArgumentAtIndex(0);
+ StringExtractorGDBRemote response;
+ process->GetGDBRemote().SendPacketAndWaitForResponse(
+ packet_cstr, response, process->GetInterruptTimeout());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ Stream &output_strm = result.GetOutputStream();
+ output_strm.Printf(" packet: %s\n", packet_cstr);
+ std::string response_str = std::string(response.GetStringRef());
+
+ if (strstr(packet_cstr, "qGetProfileData") != nullptr) {
+ response_str = process->HarmonizeThreadIdsForProfileData(response);
+ }
+
+ if (response_str.empty())
+ output_strm.PutCString("response: \nerror: UNIMPLEMENTED\n");
+ else
+ output_strm.Printf("response: %s\n", response.GetStringRef().data());
+ }
+ }
+ }
+};
+
+class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw {
+private:
+public:
+ CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter)
+ : CommandObjectRaw(interpreter, "process plugin packet monitor",
+ "Send a qRcmd packet through the GDB remote protocol "
+ "and print the response."
+ "The argument passed to this command will be hex "
+ "encoded into a valid 'qRcmd' packet, sent and the "
+ "response will be printed.") {}
+
+ ~CommandObjectProcessGDBRemotePacketMonitor() override = default;
+
+ void DoExecute(llvm::StringRef command,
+ CommandReturnObject &result) override {
+ if (command.empty()) {
+ result.AppendErrorWithFormat("'%s' takes a command string argument",
+ m_cmd_name.c_str());
+ return;
+ }
+
+ ProcessGDBRemote *process =
+ (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process) {
+ StreamString packet;
+ packet.PutCString("qRcmd,");
+ packet.PutBytesAsRawHex8(command.data(), command.size());
+
+ StringExtractorGDBRemote response;
+ Stream &output_strm = result.GetOutputStream();
+ process->GetGDBRemote().SendPacketAndReceiveResponseWithOutputSupport(
+ packet.GetString(), response, process->GetInterruptTimeout(),
+ [&output_strm](llvm::StringRef output) { output_strm << output; });
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ output_strm.Printf(" packet: %s\n", packet.GetData());
+ const std::string &response_str = std::string(response.GetStringRef());
+
+ if (response_str.empty())
+ output_strm.PutCString("response: \nerror: UNIMPLEMENTED\n");
+ else
+ output_strm.Printf("response: %s\n", response.GetStringRef().data());
+ }
+ }
+};
+
+class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword {
+private:
+public:
+ CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "process plugin packet",
+ "Commands that deal with GDB remote packets.",
+ nullptr) {
+ LoadSubCommand(
+ "history",
+ CommandObjectSP(
+ new CommandObjectProcessGDBRemotePacketHistory(interpreter)));
+ LoadSubCommand(
+ "send", CommandObjectSP(
+ new CommandObjectProcessGDBRemotePacketSend(interpreter)));
+ LoadSubCommand(
+ "monitor",
+ CommandObjectSP(
+ new CommandObjectProcessGDBRemotePacketMonitor(interpreter)));
+ LoadSubCommand(
+ "xfer-size",
+ CommandObjectSP(
+ new CommandObjectProcessGDBRemotePacketXferSize(interpreter)));
+ LoadSubCommand("speed-test",
+ CommandObjectSP(new CommandObjectProcessGDBRemoteSpeedTest(
+ interpreter)));
+ }
+
+ ~CommandObjectProcessGDBRemotePacket() override = default;
+};
+
+class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword {
+public:
+ CommandObjectMultiwordProcessGDBRemote(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(
+ interpreter, "process plugin",
+ "Commands for operating on a ProcessGDBRemote process.",
+ "process plugin <subcommand> [<subcommand-options>]") {
+ LoadSubCommand(
+ "packet",
+ CommandObjectSP(new CommandObjectProcessGDBRemotePacket(interpreter)));
+ }
+
+ ~CommandObjectMultiwordProcessGDBRemote() override = default;
+};
+
+CommandObject *ProcessGDBRemote::GetPluginCommandObject() {
+ if (!m_command_sp)
+ m_command_sp = std::make_shared<CommandObjectMultiwordProcessGDBRemote>(
+ GetTarget().GetDebugger().GetCommandInterpreter());
+ return m_command_sp.get();
+}
+
+void ProcessGDBRemote::DidForkSwitchSoftwareBreakpoints(bool enable) {
+ GetBreakpointSiteList().ForEach([this, enable](BreakpointSite *bp_site) {
+ if (bp_site->IsEnabled() &&
+ (bp_site->GetType() == BreakpointSite::eSoftware ||
+ bp_site->GetType() == BreakpointSite::eExternal)) {
+ m_gdb_comm.SendGDBStoppointTypePacket(
+ eBreakpointSoftware, enable, bp_site->GetLoadAddress(),
+ GetSoftwareBreakpointTrapOpcode(bp_site), GetInterruptTimeout());
+ }
+ });
+}
+
+void ProcessGDBRemote::DidForkSwitchHardwareTraps(bool enable) {
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) {
+ GetBreakpointSiteList().ForEach([this, enable](BreakpointSite *bp_site) {
+ if (bp_site->IsEnabled() &&
+ bp_site->GetType() == BreakpointSite::eHardware) {
+ m_gdb_comm.SendGDBStoppointTypePacket(
+ eBreakpointHardware, enable, bp_site->GetLoadAddress(),
+ GetSoftwareBreakpointTrapOpcode(bp_site), GetInterruptTimeout());
+ }
+ });
+ }
+
+ for (const auto &wp_res_sp : m_watchpoint_resource_list.Sites()) {
+ addr_t addr = wp_res_sp->GetLoadAddress();
+ size_t size = wp_res_sp->GetByteSize();
+ GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+ m_gdb_comm.SendGDBStoppointTypePacket(type, enable, addr, size,
+ GetInterruptTimeout());
+ }
+}
+
+void ProcessGDBRemote::DidFork(lldb::pid_t child_pid, lldb::tid_t child_tid) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ lldb::pid_t parent_pid = m_gdb_comm.GetCurrentProcessID();
+ // Any valid TID will suffice, thread-relevant actions will set a proper TID
+ // anyway.
+ lldb::tid_t parent_tid = m_thread_ids.front();
+
+ lldb::pid_t follow_pid, detach_pid;
+ lldb::tid_t follow_tid, detach_tid;
+
+ switch (GetFollowForkMode()) {
+ case eFollowParent:
+ follow_pid = parent_pid;
+ follow_tid = parent_tid;
+ detach_pid = child_pid;
+ detach_tid = child_tid;
+ break;
+ case eFollowChild:
+ follow_pid = child_pid;
+ follow_tid = child_tid;
+ detach_pid = parent_pid;
+ detach_tid = parent_tid;
+ break;
+ }
+
+ // Switch to the process that is going to be detached.
+ if (!m_gdb_comm.SetCurrentThread(detach_tid, detach_pid)) {
+ LLDB_LOG(log, "ProcessGDBRemote::DidFork() unable to set pid/tid");
+ return;
+ }
+
+ // Disable all software breakpoints in the forked process.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware))
+ DidForkSwitchSoftwareBreakpoints(false);
+
+ // Remove hardware breakpoints / watchpoints from parent process if we're
+ // following child.
+ if (GetFollowForkMode() == eFollowChild)
+ DidForkSwitchHardwareTraps(false);
+
+ // Switch to the process that is going to be followed
+ if (!m_gdb_comm.SetCurrentThread(follow_tid, follow_pid) ||
+ !m_gdb_comm.SetCurrentThreadForRun(follow_tid, follow_pid)) {
+ LLDB_LOG(log, "ProcessGDBRemote::DidFork() unable to reset pid/tid");
+ return;
+ }
+
+ LLDB_LOG(log, "Detaching process {0}", detach_pid);
+ Status error = m_gdb_comm.Detach(false, detach_pid);
+ if (error.Fail()) {
+ LLDB_LOG(log, "ProcessGDBRemote::DidFork() detach packet send failed: {0}",
+ error.AsCString() ? error.AsCString() : "<unknown error>");
+ return;
+ }
+
+ // Hardware breakpoints/watchpoints are not inherited implicitly,
+ // so we need to readd them if we're following child.
+ if (GetFollowForkMode() == eFollowChild) {
+ DidForkSwitchHardwareTraps(true);
+ // Update our PID
+ SetID(child_pid);
+ }
+}
+
+void ProcessGDBRemote::DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::DidFork() called for child_pid: {0}, child_tid {1}",
+ child_pid, child_tid);
+ ++m_vfork_in_progress_count;
+
+ // Disable all software breakpoints for the duration of vfork.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware))
+ DidForkSwitchSoftwareBreakpoints(false);
+
+ lldb::pid_t detach_pid;
+ lldb::tid_t detach_tid;
+
+ switch (GetFollowForkMode()) {
+ case eFollowParent:
+ detach_pid = child_pid;
+ detach_tid = child_tid;
+ break;
+ case eFollowChild:
+ detach_pid = m_gdb_comm.GetCurrentProcessID();
+ // Any valid TID will suffice, thread-relevant actions will set a proper TID
+ // anyway.
+ detach_tid = m_thread_ids.front();
+
+ // Switch to the parent process before detaching it.
+ if (!m_gdb_comm.SetCurrentThread(detach_tid, detach_pid)) {
+ LLDB_LOG(log, "ProcessGDBRemote::DidFork() unable to set pid/tid");
+ return;
+ }
+
+ // Remove hardware breakpoints / watchpoints from the parent process.
+ DidForkSwitchHardwareTraps(false);
+
+ // Switch to the child process.
+ if (!m_gdb_comm.SetCurrentThread(child_tid, child_pid) ||
+ !m_gdb_comm.SetCurrentThreadForRun(child_tid, child_pid)) {
+ LLDB_LOG(log, "ProcessGDBRemote::DidFork() unable to reset pid/tid");
+ return;
+ }
+ break;
+ }
+
+ LLDB_LOG(log, "Detaching process {0}", detach_pid);
+ Status error = m_gdb_comm.Detach(false, detach_pid);
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::DidFork() detach packet send failed: {0}",
+ error.AsCString() ? error.AsCString() : "<unknown error>");
+ return;
+ }
+
+ if (GetFollowForkMode() == eFollowChild) {
+ // Update our PID
+ SetID(child_pid);
+ }
+}
+
+void ProcessGDBRemote::DidVForkDone() {
+ assert(m_vfork_in_progress_count > 0);
+ --m_vfork_in_progress_count;
+
+ // Reenable all software breakpoints that were enabled before vfork.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware))
+ DidForkSwitchSoftwareBreakpoints(true);
+}
+
+void ProcessGDBRemote::DidExec() {
+ // If we are following children, vfork is finished by exec (rather than
+ // vforkdone that is submitted for parent).
+ if (GetFollowForkMode() == eFollowChild) {
+ if (m_vfork_in_progress_count > 0)
+ --m_vfork_in_progress_count;
+ }
+ Process::DidExec();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
new file mode 100644
index 000000000000..b44ffefcd0d3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -0,0 +1,497 @@
+//===-- ProcessGDBRemote.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTE_H
+
+#include <atomic>
+#include <map>
+#include <mutex>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "lldb/Core/LoadedModuleInfoList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Target/DynamicRegisterInfo.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/Broadcaster.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/GDBRemote.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StringExtractor.h"
+#include "lldb/Utility/StringList.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-private-forward.h"
+
+#include "GDBRemoteCommunicationClient.h"
+#include "GDBRemoteRegisterContext.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace lldb_private {
+namespace repro {
+class Loader;
+}
+namespace process_gdb_remote {
+
+class ThreadGDBRemote;
+
+class ProcessGDBRemote : public Process,
+ private GDBRemoteClientBase::ContinueDelegate {
+public:
+ ~ProcessGDBRemote() override;
+
+ static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file_path,
+ bool can_connect);
+
+ static void Initialize();
+
+ static void DebuggerInitialize(Debugger &debugger);
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "gdb-remote"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static std::chrono::seconds GetPacketTimeout();
+
+ ArchSpec GetSystemArchitecture() override;
+
+ // Check if a given Process
+ bool CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) override;
+
+ CommandObject *GetPluginCommandObject() override;
+
+ void DumpPluginHistory(Stream &s) override;
+
+ // Creating a new process, or attaching to an existing one
+ Status DoWillLaunch(Module *module) override;
+
+ Status DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override;
+
+ void DidLaunch() override;
+
+ Status DoWillAttachToProcessWithID(lldb::pid_t pid) override;
+
+ Status DoWillAttachToProcessWithName(const char *process_name,
+ bool wait_for_launch) override;
+
+ Status DoConnectRemote(llvm::StringRef remote_url) override;
+
+ Status WillLaunchOrAttach();
+
+ Status DoAttachToProcessWithID(lldb::pid_t pid,
+ const ProcessAttachInfo &attach_info) override;
+
+ Status
+ DoAttachToProcessWithName(const char *process_name,
+ const ProcessAttachInfo &attach_info) override;
+
+ void DidAttach(ArchSpec &process_arch) override;
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ // Process Control
+ Status WillResume() override;
+
+ Status DoResume() override;
+
+ Status DoHalt(bool &caused_stop) override;
+
+ Status DoDetach(bool keep_stopped) override;
+
+ bool DetachRequiresHalt() override { return true; }
+
+ Status DoSignal(int signal) override;
+
+ Status DoDestroy() override;
+
+ void RefreshStateAfterStop() override;
+
+ void SetUnixSignals(const lldb::UnixSignalsSP &signals_sp);
+
+ // Process Queries
+ bool IsAlive() override;
+
+ lldb::addr_t GetImageInfoAddress() override;
+
+ void WillPublicStop() override;
+
+ // Process Memory
+ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) override;
+
+ Status
+ WriteObjectFile(std::vector<ObjectFile::LoadableData> entries) override;
+
+ size_t DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+ Status &error) override;
+
+ lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions,
+ Status &error) override;
+
+ Status DoDeallocateMemory(lldb::addr_t ptr) override;
+
+ // Process STDIO
+ size_t PutSTDIN(const char *buf, size_t buf_size, Status &error) override;
+
+ // Process Breakpoints
+ Status EnableBreakpointSite(BreakpointSite *bp_site) override;
+
+ Status DisableBreakpointSite(BreakpointSite *bp_site) override;
+
+ // Process Watchpoints
+ Status EnableWatchpoint(lldb::WatchpointSP wp_sp,
+ bool notify = true) override;
+
+ Status DisableWatchpoint(lldb::WatchpointSP wp_sp,
+ bool notify = true) override;
+
+ std::optional<uint32_t> GetWatchpointSlotCount() override;
+
+ llvm::Expected<TraceSupportedResponse> TraceSupported() override;
+
+ llvm::Error TraceStop(const TraceStopRequest &request) override;
+
+ llvm::Error TraceStart(const llvm::json::Value &request) override;
+
+ llvm::Expected<std::string> TraceGetState(llvm::StringRef type) override;
+
+ llvm::Expected<std::vector<uint8_t>>
+ TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override;
+
+ std::optional<bool> DoGetWatchpointReportedAfter() override;
+
+ bool StartNoticingNewThreads() override;
+
+ bool StopNoticingNewThreads() override;
+
+ GDBRemoteCommunicationClient &GetGDBRemote() { return m_gdb_comm; }
+
+ Status SendEventData(const char *data) override;
+
+ // Override DidExit so we can disconnect from the remote GDB server
+ void DidExit() override;
+
+ void SetUserSpecifiedMaxMemoryTransferSize(uint64_t user_specified_max);
+
+ bool GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch,
+ ModuleSpec &module_spec) override;
+
+ void PrefetchModuleSpecs(llvm::ArrayRef<FileSpec> module_file_specs,
+ const llvm::Triple &triple) override;
+
+ llvm::VersionTuple GetHostOSVersion() override;
+ llvm::VersionTuple GetHostMacCatalystVersion() override;
+
+ llvm::Error LoadModules() override;
+
+ llvm::Expected<LoadedModuleInfoList> GetLoadedModuleList() override;
+
+ Status GetFileLoadAddress(const FileSpec &file, bool &is_loaded,
+ lldb::addr_t &load_addr) override;
+
+ void ModulesDidLoad(ModuleList &module_list) override;
+
+ StructuredData::ObjectSP
+ GetLoadedDynamicLibrariesInfos(lldb::addr_t image_list_address,
+ lldb::addr_t image_count) override;
+
+ Status
+ ConfigureStructuredData(llvm::StringRef type_name,
+ const StructuredData::ObjectSP &config_sp) override;
+
+ StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos() override;
+
+ StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos(
+ const std::vector<lldb::addr_t> &load_addresses) override;
+
+ StructuredData::ObjectSP
+ GetLoadedDynamicLibrariesInfos_sender(StructuredData::ObjectSP args);
+
+ StructuredData::ObjectSP GetSharedCacheInfo() override;
+
+ StructuredData::ObjectSP GetDynamicLoaderProcessState() override;
+
+ std::string HarmonizeThreadIdsForProfileData(
+ StringExtractorGDBRemote &inputStringExtractor);
+
+ void DidFork(lldb::pid_t child_pid, lldb::tid_t child_tid) override;
+ void DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) override;
+ void DidVForkDone() override;
+ void DidExec() override;
+
+ llvm::Expected<bool> SaveCore(llvm::StringRef outfile) override;
+
+protected:
+ friend class ThreadGDBRemote;
+ friend class GDBRemoteCommunicationClient;
+ friend class GDBRemoteRegisterContext;
+
+ ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp);
+
+ bool SupportsMemoryTagging() override;
+
+ /// Broadcaster event bits definitions.
+ enum {
+ eBroadcastBitAsyncContinue = (1 << 0),
+ eBroadcastBitAsyncThreadShouldExit = (1 << 1),
+ eBroadcastBitAsyncThreadDidExit = (1 << 2)
+ };
+
+ GDBRemoteCommunicationClient m_gdb_comm;
+ std::atomic<lldb::pid_t> m_debugserver_pid;
+
+ std::optional<StringExtractorGDBRemote> m_last_stop_packet;
+ std::recursive_mutex m_last_stop_packet_mutex;
+
+ GDBRemoteDynamicRegisterInfoSP m_register_info_sp;
+ Broadcaster m_async_broadcaster;
+ lldb::ListenerSP m_async_listener_sp;
+ HostThread m_async_thread;
+ std::recursive_mutex m_async_thread_state_mutex;
+ typedef std::vector<lldb::tid_t> tid_collection;
+ typedef std::vector<std::pair<lldb::tid_t, int>> tid_sig_collection;
+ typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
+ typedef std::map<uint32_t, std::string> ExpeditedRegisterMap;
+ tid_collection m_thread_ids; // Thread IDs for all threads. This list gets
+ // updated after stopping
+ std::vector<lldb::addr_t> m_thread_pcs; // PC values for all the threads.
+ StructuredData::ObjectSP m_jstopinfo_sp; // Stop info only for any threads
+ // that have valid stop infos
+ StructuredData::ObjectSP m_jthreadsinfo_sp; // Full stop info, expedited
+ // registers and memory for all
+ // threads if "jThreadsInfo"
+ // packet is supported
+ tid_collection m_continue_c_tids; // 'c' for continue
+ tid_sig_collection m_continue_C_tids; // 'C' for continue with signal
+ tid_collection m_continue_s_tids; // 's' for step
+ tid_sig_collection m_continue_S_tids; // 'S' for step with signal
+ uint64_t m_max_memory_size; // The maximum number of bytes to read/write when
+ // reading and writing memory
+ uint64_t m_remote_stub_max_memory_size; // The maximum memory size the remote
+ // gdb stub can handle
+ MMapMap m_addr_to_mmap_size;
+ lldb::BreakpointSP m_thread_create_bp_sp;
+ bool m_waiting_for_attach;
+ lldb::CommandObjectSP m_command_sp;
+ int64_t m_breakpoint_pc_offset;
+ lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach
+ bool m_use_g_packet_for_reading;
+
+ bool m_allow_flash_writes;
+ using FlashRangeVector = lldb_private::RangeVector<lldb::addr_t, size_t>;
+ using FlashRange = FlashRangeVector::Entry;
+ FlashRangeVector m_erased_flash_ranges;
+
+ // Number of vfork() operations being handled.
+ uint32_t m_vfork_in_progress_count;
+
+ // 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; }
+
+ void Clear();
+
+ bool DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override;
+
+ Status EstablishConnectionIfNeeded(const ProcessInfo &process_info);
+
+ Status LaunchAndConnectToDebugserver(const ProcessInfo &process_info);
+
+ void KillDebugserverProcess();
+
+ void BuildDynamicRegisterInfo(bool force);
+
+ void SetLastStopPacket(const StringExtractorGDBRemote &response);
+
+ bool ParsePythonTargetDefinition(const FileSpec &target_definition_fspec);
+
+ DataExtractor GetAuxvData() override;
+
+ StructuredData::ObjectSP GetExtendedInfoForThread(lldb::tid_t tid);
+
+ void GetMaxMemorySize();
+
+ bool CalculateThreadStopInfo(ThreadGDBRemote *thread);
+
+ size_t UpdateThreadPCsFromStopReplyThreadsValue(llvm::StringRef value);
+
+ size_t UpdateThreadIDsFromStopReplyThreadsValue(llvm::StringRef value);
+
+ bool StartAsyncThread();
+
+ void StopAsyncThread();
+
+ lldb::thread_result_t AsyncThread();
+
+ static void
+ MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp,
+ lldb::pid_t pid, int signo, int exit_status);
+
+ lldb::StateType SetThreadStopInfo(StringExtractor &stop_packet);
+
+ bool
+ GetThreadStopInfoFromJSON(ThreadGDBRemote *thread,
+ const StructuredData::ObjectSP &thread_infos_sp);
+
+ lldb::ThreadSP SetThreadStopInfo(StructuredData::Dictionary *thread_dict);
+
+ lldb::ThreadSP
+ SetThreadStopInfo(lldb::tid_t tid,
+ ExpeditedRegisterMap &expedited_register_map, uint8_t signo,
+ const std::string &thread_name, const std::string &reason,
+ const std::string &description, uint32_t exc_type,
+ const std::vector<lldb::addr_t> &exc_data,
+ lldb::addr_t thread_dispatch_qaddr, bool queue_vars_valid,
+ lldb_private::LazyBool associated_with_libdispatch_queue,
+ lldb::addr_t dispatch_queue_t, std::string &queue_name,
+ lldb::QueueKind queue_kind, uint64_t queue_serial);
+
+ void ClearThreadIDList();
+
+ bool UpdateThreadIDList();
+
+ void DidLaunchOrAttach(ArchSpec &process_arch);
+ void LoadStubBinaries();
+ void MaybeLoadExecutableModule();
+
+ Status ConnectToDebugserver(llvm::StringRef host_port);
+
+ const char *GetDispatchQueueNameForThread(lldb::addr_t thread_dispatch_qaddr,
+ std::string &dispatch_queue_name);
+
+ DynamicLoader *GetDynamicLoader() override;
+
+ bool GetGDBServerRegisterInfoXMLAndProcess(
+ ArchSpec &arch_to_use, std::string xml_filename,
+ std::vector<DynamicRegisterInfo::Register> &registers);
+
+ // Convert DynamicRegisterInfo::Registers into RegisterInfos and add
+ // to the dynamic register list.
+ void AddRemoteRegisters(std::vector<DynamicRegisterInfo::Register> &registers,
+ const ArchSpec &arch_to_use);
+ // Query remote GDBServer for register information
+ bool GetGDBServerRegisterInfo(ArchSpec &arch);
+
+ lldb::ModuleSP LoadModuleAtAddress(const FileSpec &file,
+ lldb::addr_t link_map,
+ lldb::addr_t base_addr,
+ bool value_is_offset);
+
+ Status UpdateAutomaticSignalFiltering() override;
+
+ Status FlashErase(lldb::addr_t addr, size_t size);
+
+ Status FlashDone();
+
+ bool HasErased(FlashRange range);
+
+ llvm::Expected<std::vector<uint8_t>>
+ DoReadMemoryTags(lldb::addr_t addr, size_t len, int32_t type) override;
+
+ Status DoWriteMemoryTags(lldb::addr_t addr, size_t len, int32_t type,
+ const std::vector<uint8_t> &tags) override;
+
+ Status DoGetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &region_info) override;
+
+private:
+ // For ProcessGDBRemote only
+ std::string m_partial_profile_data;
+ std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
+ uint64_t m_last_signals_version = 0;
+
+ static bool NewThreadNotifyBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ // ContinueDelegate interface
+ void HandleAsyncStdout(llvm::StringRef out) override;
+ void HandleAsyncMisc(llvm::StringRef data) override;
+ void HandleStopReply() override;
+ void HandleAsyncStructuredDataPacket(llvm::StringRef data) override;
+
+ void SetThreadPc(const lldb::ThreadSP &thread_sp, uint64_t index);
+ using ModuleCacheKey = std::pair<std::string, std::string>;
+ // KeyInfo for the cached module spec DenseMap.
+ // The invariant is that all real keys will have the file and architecture
+ // set.
+ // The empty key has an empty file and an empty arch.
+ // The tombstone key has an invalid arch and an empty file.
+ // The comparison and hash functions take the file name and architecture
+ // triple into account.
+ struct ModuleCacheInfo {
+ static ModuleCacheKey getEmptyKey() { return ModuleCacheKey(); }
+
+ static ModuleCacheKey getTombstoneKey() { return ModuleCacheKey("", "T"); }
+
+ static unsigned getHashValue(const ModuleCacheKey &key) {
+ return llvm::hash_combine(key.first, key.second);
+ }
+
+ static bool isEqual(const ModuleCacheKey &LHS, const ModuleCacheKey &RHS) {
+ return LHS == RHS;
+ }
+ };
+
+ llvm::DenseMap<ModuleCacheKey, ModuleSpec, ModuleCacheInfo>
+ m_cached_module_specs;
+
+ ProcessGDBRemote(const ProcessGDBRemote &) = delete;
+ const ProcessGDBRemote &operator=(const ProcessGDBRemote &) = delete;
+
+ // fork helpers
+ void DidForkSwitchSoftwareBreakpoints(bool enable);
+ void DidForkSwitchHardwareTraps(bool enable);
+
+ void ParseExpeditedRegisters(ExpeditedRegisterMap &expedited_register_map,
+ lldb::ThreadSP thread_sp);
+
+ // Lists of register fields generated from the remote's target XML.
+ // Pointers to these RegisterFlags will be set in the register info passed
+ // back to the upper levels of lldb. Doing so is safe because this class will
+ // live at least as long as the debug session. We therefore do not store the
+ // data directly in the map because the map may reallocate it's storage as new
+ // entries are added. Which would invalidate any pointers set in the register
+ // info up to that point.
+ llvm::StringMap<std::unique_ptr<RegisterFlags>> m_registers_flags_types;
+
+ // Enum types are referenced by register fields. This does not store the data
+ // directly because the map may reallocate. Pointers to these are contained
+ // within instances of RegisterFlags.
+ llvm::StringMap<std::unique_ptr<FieldEnum>> m_registers_enum_types;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
new file mode 100644
index 000000000000..3322f6b8048a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
@@ -0,0 +1,47 @@
+//===-- ProcessGDBRemoteLog.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessGDBRemoteLog.h"
+#include "ProcessGDBRemote.h"
+#include "llvm/Support/Threading.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+static constexpr Log::Category g_categories[] = {
+ {{"async"}, {"log asynchronous activity"}, GDBRLog::Async},
+ {{"break"}, {"log breakpoints"}, GDBRLog::Breakpoints},
+ {{"comm"}, {"log communication activity"}, GDBRLog::Comm},
+ {{"packets"}, {"log gdb remote packets"}, GDBRLog::Packets},
+ {{"memory"}, {"log memory reads and writes"}, GDBRLog::Memory},
+ {{"data-short"},
+ {"log memory bytes for memory reads and writes for short transactions "
+ "only"},
+ GDBRLog::MemoryDataShort},
+ {{"data-long"},
+ {"log memory bytes for memory reads and writes for all transactions"},
+ GDBRLog::MemoryDataLong},
+ {{"process"}, {"log process events and activities"}, GDBRLog::Process},
+ {{"step"}, {"log step related activities"}, GDBRLog::Step},
+ {{"thread"}, {"log thread events and activities"}, GDBRLog::Thread},
+ {{"watch"}, {"log watchpoint related activities"}, GDBRLog::Watchpoints},
+};
+
+static Log::Channel g_channel(g_categories, GDBRLog::Packets);
+
+template <> Log::Channel &lldb_private::LogChannelFor<GDBRLog>() {
+ return g_channel;
+}
+
+void ProcessGDBRemoteLog::Initialize() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
+ Log::Register("gdb-remote", g_channel);
+ });
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
new file mode 100644
index 000000000000..66b2f00f1ea9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
@@ -0,0 +1,45 @@
+//===-- ProcessGDBRemoteLog.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTELOG_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTELOG_H
+
+#include "lldb/Utility/Log.h"
+#include "llvm/ADT/BitmaskEnum.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+enum class GDBRLog : Log::MaskType {
+ Async = Log::ChannelFlag<0>,
+ Breakpoints = Log::ChannelFlag<1>,
+ Comm = Log::ChannelFlag<2>,
+ Memory = Log::ChannelFlag<3>, // Log memory reads/writes calls
+ MemoryDataLong = Log::ChannelFlag<4>, // Log all memory reads/writes bytes
+ MemoryDataShort = Log::ChannelFlag<5>, // Log short memory reads/writes bytes
+ Packets = Log::ChannelFlag<6>,
+ Process = Log::ChannelFlag<7>,
+ Step = Log::ChannelFlag<8>,
+ Thread = Log::ChannelFlag<9>,
+ Watchpoints = Log::ChannelFlag<10>,
+ LLVM_MARK_AS_BITMASK_ENUM(Watchpoints)
+};
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+class ProcessGDBRemoteLog {
+public:
+ static void Initialize();
+};
+
+} // namespace process_gdb_remote
+
+template <> Log::Channel &LogChannelFor<process_gdb_remote::GDBRLog>();
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTELOG_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td
new file mode 100644
index 000000000000..520dad062e09
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td
@@ -0,0 +1,24 @@
+include "../../../../include/lldb/Core/PropertiesBase.td"
+
+let Definition = "processgdbremote" in {
+ def PacketTimeout: Property<"packet-timeout", "UInt64">,
+ Global,
+#ifdef LLDB_SANITIZED
+ DefaultUnsignedValue<60>,
+#else
+ DefaultUnsignedValue<5>,
+#endif
+ Desc<"Specify the default packet timeout in seconds.">;
+ def TargetDefinitionFile: Property<"target-definition-file", "FileSpec">,
+ Global,
+ DefaultStringValue<"">,
+ Desc<"The file that provides the description for remote target registers.">;
+ def UseSVR4: Property<"use-libraries-svr4", "Boolean">,
+ Global,
+ DefaultTrue,
+ Desc<"If true, the libraries-svr4 feature will be used to get a hold of the process's loaded modules. This setting is only effective if lldb was build with xml support.">;
+ def UseGPacketForReading: Property<"use-g-packet-for-reading", "Boolean">,
+ Global,
+ DefaultFalse,
+ Desc<"Specify if the server should use 'g' packets to read registers.">;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
new file mode 100644
index 000000000000..3d23c074c1be
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -0,0 +1,368 @@
+//===-- ThreadGDBRemote.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThreadGDBRemote.h"
+
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/SystemRuntime.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/State.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StringExtractorGDBRemote.h"
+
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+// Thread Registers
+
+ThreadGDBRemote::ThreadGDBRemote(Process &process, lldb::tid_t tid)
+ : Thread(process, tid), m_thread_name(), m_dispatch_queue_name(),
+ m_thread_dispatch_qaddr(LLDB_INVALID_ADDRESS),
+ m_dispatch_queue_t(LLDB_INVALID_ADDRESS), m_queue_kind(eQueueKindUnknown),
+ m_queue_serial_number(LLDB_INVALID_QUEUE_ID),
+ m_associated_with_libdispatch_queue(eLazyBoolCalculate) {
+ Log *log = GetLog(GDBRLog::Thread);
+ LLDB_LOG(log, "this = {0}, pid = {1}, tid = {2}", this, process.GetID(),
+ GetID());
+ // At this point we can clone reg_info for architectures supporting
+ // run-time update to register sizes and offsets..
+ auto &gdb_process = static_cast<ProcessGDBRemote &>(process);
+ if (!gdb_process.m_register_info_sp->IsReconfigurable())
+ m_reg_info_sp = gdb_process.m_register_info_sp;
+ else
+ m_reg_info_sp = std::make_shared<GDBRemoteDynamicRegisterInfo>(
+ *gdb_process.m_register_info_sp);
+}
+
+ThreadGDBRemote::~ThreadGDBRemote() {
+ ProcessSP process_sp(GetProcess());
+ Log *log = GetLog(GDBRLog::Thread);
+ LLDB_LOG(log, "this = {0}, pid = {1}, tid = {2}", this,
+ process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID, GetID());
+ DestroyThread();
+}
+
+const char *ThreadGDBRemote::GetName() {
+ if (m_thread_name.empty())
+ return nullptr;
+ return m_thread_name.c_str();
+}
+
+void ThreadGDBRemote::ClearQueueInfo() {
+ m_dispatch_queue_name.clear();
+ m_queue_kind = eQueueKindUnknown;
+ m_queue_serial_number = 0;
+ m_dispatch_queue_t = LLDB_INVALID_ADDRESS;
+ m_associated_with_libdispatch_queue = eLazyBoolCalculate;
+}
+
+void ThreadGDBRemote::SetQueueInfo(std::string &&queue_name,
+ QueueKind queue_kind, uint64_t queue_serial,
+ addr_t dispatch_queue_t,
+ LazyBool associated_with_libdispatch_queue) {
+ m_dispatch_queue_name = queue_name;
+ m_queue_kind = queue_kind;
+ m_queue_serial_number = queue_serial;
+ m_dispatch_queue_t = dispatch_queue_t;
+ m_associated_with_libdispatch_queue = associated_with_libdispatch_queue;
+}
+
+const char *ThreadGDBRemote::GetQueueName() {
+ // If our cached queue info is valid, then someone called
+ // ThreadGDBRemote::SetQueueInfo(...) with valid information that was gleaned
+ // from the stop reply packet. In this case we trust that the info is valid
+ // in m_dispatch_queue_name without refetching it
+ if (CachedQueueInfoIsValid()) {
+ if (m_dispatch_queue_name.empty())
+ return nullptr;
+ else
+ return m_dispatch_queue_name.c_str();
+ }
+ // Always re-fetch the dispatch queue name since it can change
+
+ if (m_associated_with_libdispatch_queue == eLazyBoolNo)
+ return nullptr;
+
+ if (m_thread_dispatch_qaddr != 0 &&
+ m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) {
+ ProcessSP process_sp(GetProcess());
+ if (process_sp) {
+ SystemRuntime *runtime = process_sp->GetSystemRuntime();
+ if (runtime)
+ m_dispatch_queue_name =
+ runtime->GetQueueNameFromThreadQAddress(m_thread_dispatch_qaddr);
+ else
+ m_dispatch_queue_name.clear();
+
+ if (!m_dispatch_queue_name.empty())
+ return m_dispatch_queue_name.c_str();
+ }
+ }
+ return nullptr;
+}
+
+QueueKind ThreadGDBRemote::GetQueueKind() {
+ // If our cached queue info is valid, then someone called
+ // ThreadGDBRemote::SetQueueInfo(...) with valid information that was gleaned
+ // from the stop reply packet. In this case we trust that the info is valid
+ // in m_dispatch_queue_name without refetching it
+ if (CachedQueueInfoIsValid()) {
+ return m_queue_kind;
+ }
+
+ if (m_associated_with_libdispatch_queue == eLazyBoolNo)
+ return eQueueKindUnknown;
+
+ if (m_thread_dispatch_qaddr != 0 &&
+ m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) {
+ ProcessSP process_sp(GetProcess());
+ if (process_sp) {
+ SystemRuntime *runtime = process_sp->GetSystemRuntime();
+ if (runtime)
+ m_queue_kind = runtime->GetQueueKind(m_thread_dispatch_qaddr);
+ return m_queue_kind;
+ }
+ }
+ return eQueueKindUnknown;
+}
+
+queue_id_t ThreadGDBRemote::GetQueueID() {
+ // If our cached queue info is valid, then someone called
+ // ThreadGDBRemote::SetQueueInfo(...) with valid information that was gleaned
+ // from the stop reply packet. In this case we trust that the info is valid
+ // in m_dispatch_queue_name without refetching it
+ if (CachedQueueInfoIsValid())
+ return m_queue_serial_number;
+
+ if (m_associated_with_libdispatch_queue == eLazyBoolNo)
+ return LLDB_INVALID_QUEUE_ID;
+
+ if (m_thread_dispatch_qaddr != 0 &&
+ m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) {
+ ProcessSP process_sp(GetProcess());
+ if (process_sp) {
+ SystemRuntime *runtime = process_sp->GetSystemRuntime();
+ if (runtime) {
+ return runtime->GetQueueIDFromThreadQAddress(m_thread_dispatch_qaddr);
+ }
+ }
+ }
+ return LLDB_INVALID_QUEUE_ID;
+}
+
+QueueSP ThreadGDBRemote::GetQueue() {
+ queue_id_t queue_id = GetQueueID();
+ QueueSP queue;
+ if (queue_id != LLDB_INVALID_QUEUE_ID) {
+ ProcessSP process_sp(GetProcess());
+ if (process_sp) {
+ queue = process_sp->GetQueueList().FindQueueByID(queue_id);
+ }
+ }
+ return queue;
+}
+
+addr_t ThreadGDBRemote::GetQueueLibdispatchQueueAddress() {
+ if (m_dispatch_queue_t == LLDB_INVALID_ADDRESS) {
+ if (m_thread_dispatch_qaddr != 0 &&
+ m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) {
+ ProcessSP process_sp(GetProcess());
+ if (process_sp) {
+ SystemRuntime *runtime = process_sp->GetSystemRuntime();
+ if (runtime) {
+ m_dispatch_queue_t =
+ runtime->GetLibdispatchQueueAddressFromThreadQAddress(
+ m_thread_dispatch_qaddr);
+ }
+ }
+ }
+ }
+ return m_dispatch_queue_t;
+}
+
+void ThreadGDBRemote::SetQueueLibdispatchQueueAddress(
+ lldb::addr_t dispatch_queue_t) {
+ m_dispatch_queue_t = dispatch_queue_t;
+}
+
+bool ThreadGDBRemote::ThreadHasQueueInformation() const {
+ return m_thread_dispatch_qaddr != 0 &&
+ m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS &&
+ m_dispatch_queue_t != LLDB_INVALID_ADDRESS &&
+ m_queue_kind != eQueueKindUnknown && m_queue_serial_number != 0;
+}
+
+LazyBool ThreadGDBRemote::GetAssociatedWithLibdispatchQueue() {
+ return m_associated_with_libdispatch_queue;
+}
+
+void ThreadGDBRemote::SetAssociatedWithLibdispatchQueue(
+ LazyBool associated_with_libdispatch_queue) {
+ m_associated_with_libdispatch_queue = associated_with_libdispatch_queue;
+}
+
+StructuredData::ObjectSP ThreadGDBRemote::FetchThreadExtendedInfo() {
+ StructuredData::ObjectSP object_sp;
+ const lldb::user_id_t tid = GetProtocolID();
+ Log *log = GetLog(GDBRLog::Thread);
+ LLDB_LOGF(log, "Fetching extended information for thread %4.4" PRIx64, tid);
+ ProcessSP process_sp(GetProcess());
+ if (process_sp) {
+ ProcessGDBRemote *gdb_process =
+ static_cast<ProcessGDBRemote *>(process_sp.get());
+ object_sp = gdb_process->GetExtendedInfoForThread(tid);
+ }
+ return object_sp;
+}
+
+void ThreadGDBRemote::WillResume(StateType resume_state) {
+ int signo = GetResumeSignal();
+ const lldb::user_id_t tid = GetProtocolID();
+ Log *log = GetLog(GDBRLog::Thread);
+ LLDB_LOGF(log, "Resuming thread: %4.4" PRIx64 " with state: %s.", tid,
+ StateAsCString(resume_state));
+
+ ProcessSP process_sp(GetProcess());
+ if (process_sp) {
+ ProcessGDBRemote *gdb_process =
+ static_cast<ProcessGDBRemote *>(process_sp.get());
+ switch (resume_state) {
+ case eStateSuspended:
+ case eStateStopped:
+ // Don't append anything for threads that should stay stopped.
+ break;
+
+ case eStateRunning:
+ if (gdb_process->GetUnixSignals()->SignalIsValid(signo))
+ gdb_process->m_continue_C_tids.push_back(std::make_pair(tid, signo));
+ else
+ gdb_process->m_continue_c_tids.push_back(tid);
+ break;
+
+ case eStateStepping:
+ if (gdb_process->GetUnixSignals()->SignalIsValid(signo))
+ gdb_process->m_continue_S_tids.push_back(std::make_pair(tid, signo));
+ else
+ gdb_process->m_continue_s_tids.push_back(tid);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void ThreadGDBRemote::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
+ // GDBRemoteRegisterContext 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 ThreadGDBRemote::ThreadIDIsValid(lldb::tid_t thread) {
+ return thread != 0;
+}
+
+void ThreadGDBRemote::Dump(Log *log, uint32_t index) {}
+
+bool ThreadGDBRemote::ShouldStop(bool &step_more) { return true; }
+lldb::RegisterContextSP ThreadGDBRemote::GetRegisterContext() {
+ if (!m_reg_context_sp)
+ m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadGDBRemote::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(GetProcess());
+ if (process_sp) {
+ ProcessGDBRemote *gdb_process =
+ static_cast<ProcessGDBRemote *>(process_sp.get());
+ bool pSupported =
+ gdb_process->GetGDBRemote().GetpPacketSupported(GetID());
+ bool read_all_registers_at_once =
+ !pSupported || gdb_process->m_use_g_packet_for_reading;
+ bool write_all_registers_at_once = !pSupported;
+ reg_ctx_sp = std::make_shared<GDBRemoteRegisterContext>(
+ *this, concrete_frame_idx, m_reg_info_sp, read_all_registers_at_once,
+ write_all_registers_at_once);
+ }
+ } else {
+ reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool ThreadGDBRemote::PrivateSetRegisterValue(uint32_t reg,
+ llvm::ArrayRef<uint8_t> data) {
+ GDBRemoteRegisterContext *gdb_reg_ctx =
+ static_cast<GDBRemoteRegisterContext *>(GetRegisterContext().get());
+ assert(gdb_reg_ctx);
+ return gdb_reg_ctx->PrivateSetRegisterValue(reg, data);
+}
+
+bool ThreadGDBRemote::PrivateSetRegisterValue(uint32_t reg, uint64_t regval) {
+ GDBRemoteRegisterContext *gdb_reg_ctx =
+ static_cast<GDBRemoteRegisterContext *>(GetRegisterContext().get());
+ assert(gdb_reg_ctx);
+ return gdb_reg_ctx->PrivateSetRegisterValue(reg, regval);
+}
+
+bool ThreadGDBRemote::CalculateStopInfo() {
+ ProcessSP process_sp(GetProcess());
+ if (process_sp)
+ return static_cast<ProcessGDBRemote *>(process_sp.get())
+ ->CalculateThreadStopInfo(this);
+ return false;
+}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+ThreadGDBRemote::GetSiginfo(size_t max_size) const {
+ ProcessSP process_sp(GetProcess());
+ if (!process_sp)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "no process");
+ ProcessGDBRemote *gdb_process =
+ static_cast<ProcessGDBRemote *>(process_sp.get());
+ if (!gdb_process->m_gdb_comm.GetQXferSigInfoReadSupported())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "qXfer:siginfo:read not supported");
+
+ llvm::Expected<std::string> response =
+ gdb_process->m_gdb_comm.ReadExtFeature("siginfo", "");
+ if (!response)
+ return response.takeError();
+
+ return llvm::MemoryBuffer::getMemBufferCopy(response.get());
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
new file mode 100644
index 000000000000..5bc90a3dedce
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -0,0 +1,126 @@
+//===-- ThreadGDBRemote.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_THREADGDBREMOTE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_THREADGDBREMOTE_H
+
+#include <string>
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/StructuredData.h"
+
+#include "GDBRemoteRegisterContext.h"
+
+class StringExtractor;
+
+namespace lldb_private {
+class Process;
+
+namespace process_gdb_remote {
+
+class ProcessGDBRemote;
+
+class ThreadGDBRemote : public Thread {
+public:
+ ThreadGDBRemote(Process &process, lldb::tid_t tid);
+
+ ~ThreadGDBRemote() override;
+
+ void WillResume(lldb::StateType resume_state) override;
+
+ void RefreshStateAfterStop() override;
+
+ const char *GetName() override;
+
+ const char *GetQueueName() override;
+
+ lldb::QueueKind GetQueueKind() override;
+
+ lldb::queue_id_t GetQueueID() override;
+
+ lldb::QueueSP GetQueue() override;
+
+ lldb::addr_t GetQueueLibdispatchQueueAddress() override;
+
+ void SetQueueLibdispatchQueueAddress(lldb::addr_t dispatch_queue_t) override;
+
+ bool ThreadHasQueueInformation() const override;
+
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(StackFrame *frame) override;
+
+ void Dump(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) 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;
+ }
+
+ void ClearQueueInfo();
+
+ void SetQueueInfo(std::string &&queue_name, lldb::QueueKind queue_kind,
+ uint64_t queue_serial, lldb::addr_t dispatch_queue_t,
+ lldb_private::LazyBool associated_with_libdispatch_queue);
+
+ lldb_private::LazyBool GetAssociatedWithLibdispatchQueue() override;
+
+ void SetAssociatedWithLibdispatchQueue(
+ lldb_private::LazyBool associated_with_libdispatch_queue) override;
+
+ StructuredData::ObjectSP FetchThreadExtendedInfo() override;
+
+protected:
+ friend class ProcessGDBRemote;
+
+ std::string m_thread_name;
+ std::string m_dispatch_queue_name;
+ lldb::addr_t m_thread_dispatch_qaddr;
+ lldb::addr_t m_dispatch_queue_t;
+ lldb::QueueKind
+ m_queue_kind; // Queue info from stop reply/stop info for thread
+ uint64_t
+ m_queue_serial_number; // Queue info from stop reply/stop info for thread
+ lldb_private::LazyBool m_associated_with_libdispatch_queue;
+
+ GDBRemoteDynamicRegisterInfoSP m_reg_info_sp;
+
+ bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data);
+
+ bool PrivateSetRegisterValue(uint32_t reg, uint64_t regval);
+
+ bool CachedQueueInfoIsValid() const {
+ return m_queue_kind != lldb::eQueueKindUnknown;
+ }
+ void SetStopInfoFromPacket(StringExtractor &stop_packet, uint32_t stop_id);
+
+ bool CalculateStopInfo() override;
+
+ llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+ GetSiginfo(size_t max_size) const override;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_THREADGDBREMOTE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
new file mode 100644
index 000000000000..be9fae938e22
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -0,0 +1,711 @@
+//===-- MinidumpParser.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinidumpParser.h"
+#include "NtStructures.h"
+#include "RegisterContextMinidump_x86_32.h"
+
+#include "Plugins/Process/Utility/LinuxProcMaps.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+// C includes
+// C++ includes
+#include <algorithm>
+#include <map>
+#include <optional>
+#include <vector>
+#include <utility>
+
+using namespace lldb_private;
+using namespace minidump;
+
+llvm::Expected<MinidumpParser>
+MinidumpParser::Create(const lldb::DataBufferSP &data_sp) {
+ auto ExpectedFile = llvm::object::MinidumpFile::create(
+ llvm::MemoryBufferRef(toStringRef(data_sp->GetData()), "minidump"));
+ if (!ExpectedFile)
+ return ExpectedFile.takeError();
+
+ return MinidumpParser(data_sp, std::move(*ExpectedFile));
+}
+
+MinidumpParser::MinidumpParser(lldb::DataBufferSP data_sp,
+ std::unique_ptr<llvm::object::MinidumpFile> file)
+ : m_data_sp(std::move(data_sp)), m_file(std::move(file)) {}
+
+llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {
+ return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),
+ m_data_sp->GetByteSize());
+}
+
+llvm::ArrayRef<uint8_t> MinidumpParser::GetStream(StreamType stream_type) {
+ return m_file->getRawStream(stream_type).value_or(llvm::ArrayRef<uint8_t>());
+}
+
+UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) {
+ auto cv_record =
+ GetData().slice(module->CvRecord.RVA, module->CvRecord.DataSize);
+
+ // Read the CV record signature
+ const llvm::support::ulittle32_t *signature = nullptr;
+ Status error = consumeObject(cv_record, signature);
+ if (error.Fail())
+ return UUID();
+
+ const CvSignature cv_signature =
+ static_cast<CvSignature>(static_cast<uint32_t>(*signature));
+
+ if (cv_signature == CvSignature::Pdb70) {
+ const UUID::CvRecordPdb70 *pdb70_uuid = nullptr;
+ Status error = consumeObject(cv_record, pdb70_uuid);
+ if (error.Fail())
+ return UUID();
+ if (GetArchitecture().GetTriple().isOSBinFormatELF()) {
+ if (pdb70_uuid->Age != 0)
+ return UUID(pdb70_uuid, sizeof(*pdb70_uuid));
+ return UUID(&pdb70_uuid->Uuid,
+ sizeof(pdb70_uuid->Uuid));
+ }
+ return UUID(*pdb70_uuid);
+ } else if (cv_signature == CvSignature::ElfBuildId)
+ return UUID(cv_record);
+
+ return UUID();
+}
+
+llvm::ArrayRef<minidump::Thread> MinidumpParser::GetThreads() {
+ auto ExpectedThreads = GetMinidumpFile().getThreadList();
+ if (ExpectedThreads)
+ return *ExpectedThreads;
+
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), ExpectedThreads.takeError(),
+ "Failed to read thread list: {0}");
+ return {};
+}
+
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetThreadContext(const LocationDescriptor &location) {
+ if (location.RVA + location.DataSize > GetData().size())
+ return {};
+ return GetData().slice(location.RVA, location.DataSize);
+}
+
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetThreadContext(const minidump::Thread &td) {
+ return GetThreadContext(td.Context);
+}
+
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetThreadContextWow64(const minidump::Thread &td) {
+ // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If
+ // the minidump was captured with a 64-bit debugger, then the CONTEXT we just
+ // grabbed from the mini_dump_thread is the one for the 64-bit "native"
+ // process rather than the 32-bit "guest" process we care about. In this
+ // case, we can get the 32-bit CONTEXT from the TEB (Thread Environment
+ // Block) of the 64-bit process.
+ auto teb_mem = GetMemory(td.EnvironmentBlock, sizeof(TEB64));
+ if (teb_mem.empty())
+ return {};
+
+ const TEB64 *wow64teb;
+ Status error = consumeObject(teb_mem, wow64teb);
+ if (error.Fail())
+ return {};
+
+ // Slot 1 of the thread-local storage in the 64-bit TEB points to a structure
+ // that includes the 32-bit CONTEXT (after a ULONG). See:
+ // https://msdn.microsoft.com/en-us/library/ms681670.aspx
+ auto context =
+ GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));
+ if (context.size() < sizeof(MinidumpContext_x86_32))
+ return {};
+
+ return context;
+ // NOTE: We don't currently use the TEB for anything else. If we
+ // need it in the future, the 32-bit TEB is located according to the address
+ // stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).
+}
+
+ArchSpec MinidumpParser::GetArchitecture() {
+ if (m_arch.IsValid())
+ return m_arch;
+
+ // Set the architecture in m_arch
+ llvm::Expected<const SystemInfo &> system_info = m_file->getSystemInfo();
+
+ if (!system_info) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Process), system_info.takeError(),
+ "Failed to read SystemInfo stream: {0}");
+ return m_arch;
+ }
+
+ // TODO what to do about big endiand flavors of arm ?
+ // TODO set the arm subarch stuff if the minidump has info about it
+
+ llvm::Triple triple;
+ triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
+
+ switch (system_info->ProcessorArch) {
+ case ProcessorArchitecture::X86:
+ triple.setArch(llvm::Triple::ArchType::x86);
+ break;
+ case ProcessorArchitecture::AMD64:
+ triple.setArch(llvm::Triple::ArchType::x86_64);
+ break;
+ case ProcessorArchitecture::ARM:
+ triple.setArch(llvm::Triple::ArchType::arm);
+ break;
+ case ProcessorArchitecture::ARM64:
+ case ProcessorArchitecture::BP_ARM64:
+ triple.setArch(llvm::Triple::ArchType::aarch64);
+ break;
+ default:
+ triple.setArch(llvm::Triple::ArchType::UnknownArch);
+ break;
+ }
+
+ // TODO add all of the OSes that Minidump/breakpad distinguishes?
+ switch (system_info->PlatformId) {
+ case OSPlatform::Win32S:
+ case OSPlatform::Win32Windows:
+ case OSPlatform::Win32NT:
+ case OSPlatform::Win32CE:
+ triple.setOS(llvm::Triple::OSType::Win32);
+ triple.setVendor(llvm::Triple::VendorType::PC);
+ break;
+ case OSPlatform::Linux:
+ triple.setOS(llvm::Triple::OSType::Linux);
+ break;
+ case OSPlatform::MacOSX:
+ triple.setOS(llvm::Triple::OSType::MacOSX);
+ triple.setVendor(llvm::Triple::Apple);
+ break;
+ case OSPlatform::IOS:
+ triple.setOS(llvm::Triple::OSType::IOS);
+ triple.setVendor(llvm::Triple::Apple);
+ break;
+ case OSPlatform::Android:
+ triple.setOS(llvm::Triple::OSType::Linux);
+ triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
+ break;
+ default: {
+ triple.setOS(llvm::Triple::OSType::UnknownOS);
+ auto ExpectedCSD = m_file->getString(system_info->CSDVersionRVA);
+ if (!ExpectedCSD) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Process), ExpectedCSD.takeError(),
+ "Failed to CSD Version string: {0}");
+ } else {
+ if (ExpectedCSD->find("Linux") != std::string::npos)
+ triple.setOS(llvm::Triple::OSType::Linux);
+ }
+ break;
+ }
+ }
+ m_arch.SetTriple(triple);
+ return m_arch;
+}
+
+const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
+ llvm::ArrayRef<uint8_t> data = GetStream(StreamType::MiscInfo);
+
+ if (data.size() == 0)
+ return nullptr;
+
+ return MinidumpMiscInfo::Parse(data);
+}
+
+std::optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {
+ llvm::ArrayRef<uint8_t> data = GetStream(StreamType::LinuxProcStatus);
+
+ if (data.size() == 0)
+ return std::nullopt;
+
+ return LinuxProcStatus::Parse(data);
+}
+
+std::optional<lldb::pid_t> MinidumpParser::GetPid() {
+ const MinidumpMiscInfo *misc_info = GetMiscInfo();
+ if (misc_info != nullptr) {
+ return misc_info->GetPid();
+ }
+
+ std::optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();
+ if (proc_status) {
+ return proc_status->GetPid();
+ }
+
+ return std::nullopt;
+}
+
+llvm::ArrayRef<minidump::Module> MinidumpParser::GetModuleList() {
+ auto ExpectedModules = GetMinidumpFile().getModuleList();
+ if (ExpectedModules)
+ return *ExpectedModules;
+
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Modules), ExpectedModules.takeError(),
+ "Failed to read module list: {0}");
+ return {};
+}
+
+static bool
+CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> &regions) {
+ auto data = parser.GetStream(StreamType::LinuxMaps);
+ if (data.empty())
+ return false;
+
+ Log *log = GetLog(LLDBLog::Expressions);
+ ParseLinuxMapRegions(
+ llvm::toStringRef(data),
+ [&regions, &log](llvm::Expected<MemoryRegionInfo> region) -> bool {
+ if (region)
+ regions.push_back(*region);
+ else
+ LLDB_LOG_ERROR(log, region.takeError(),
+ "Reading memory region from minidump failed: {0}");
+ return true;
+ });
+ return !regions.empty();
+}
+
+/// Check for the memory regions starting at \a load_addr for a contiguous
+/// section that has execute permissions that matches the module path.
+///
+/// When we load a breakpad generated minidump file, we might have the
+/// /proc/<pid>/maps text for a process that details the memory map of the
+/// process that the minidump is describing. This checks the sorted memory
+/// regions for a section that has execute permissions. A sample maps files
+/// might look like:
+///
+/// 00400000-00401000 r--p 00000000 fd:01 2838574 /tmp/a.out
+/// 00401000-00402000 r-xp 00001000 fd:01 2838574 /tmp/a.out
+/// 00402000-00403000 r--p 00002000 fd:01 2838574 /tmp/a.out
+/// 00403000-00404000 r--p 00002000 fd:01 2838574 /tmp/a.out
+/// 00404000-00405000 rw-p 00003000 fd:01 2838574 /tmp/a.out
+/// ...
+///
+/// This function should return true when given 0x00400000 and "/tmp/a.out"
+/// is passed in as the path since it has a consecutive memory region for
+/// "/tmp/a.out" that has execute permissions at 0x00401000. This will help us
+/// differentiate if a file has been memory mapped into a process for reading
+/// and breakpad ends up saving a minidump file that has two module entries for
+/// a given file: one that is read only for the entire file, and then one that
+/// is the real executable that is loaded into memory for execution. For memory
+/// mapped files they will typically show up and r--p permissions and a range
+/// matcning the entire range of the file on disk:
+///
+/// 00800000-00805000 r--p 00000000 fd:01 2838574 /tmp/a.out
+/// 00805000-00806000 r-xp 00001000 fd:01 1234567 /usr/lib/libc.so
+///
+/// This function should return false when asked about 0x00800000 with
+/// "/tmp/a.out" as the path.
+///
+/// \param[in] path
+/// The path to the module to check for in the memory regions. Only sequential
+/// memory regions whose paths match this path will be considered when looking
+/// for execute permissions.
+///
+/// \param[in] regions
+/// A sorted list of memory regions obtained from a call to
+/// CreateRegionsCacheFromLinuxMaps.
+///
+/// \param[in] base_of_image
+/// The load address of this module from BaseOfImage in the modules list.
+///
+/// \return
+/// True if a contiguous region of memory belonging to the module with a
+/// matching path exists that has executable permissions. Returns false if
+/// \a regions is empty or if there are no regions with execute permissions
+/// that match \a path.
+
+static bool CheckForLinuxExecutable(ConstString path,
+ const MemoryRegionInfos &regions,
+ lldb::addr_t base_of_image) {
+ if (regions.empty())
+ return false;
+ lldb::addr_t addr = base_of_image;
+ MemoryRegionInfo region = MinidumpParser::GetMemoryRegionInfo(regions, addr);
+ while (region.GetName() == path) {
+ if (region.GetExecutable() == MemoryRegionInfo::eYes)
+ return true;
+ addr += region.GetRange().GetByteSize();
+ region = MinidumpParser::GetMemoryRegionInfo(regions, addr);
+ }
+ return false;
+}
+
+std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() {
+ Log *log = GetLog(LLDBLog::Modules);
+ auto ExpectedModules = GetMinidumpFile().getModuleList();
+ if (!ExpectedModules) {
+ LLDB_LOG_ERROR(log, ExpectedModules.takeError(),
+ "Failed to read module list: {0}");
+ return {};
+ }
+
+ // Create memory regions from the linux maps only. We do this to avoid issues
+ // with breakpad generated minidumps where if someone has mmap'ed a shared
+ // library into memory to access its data in the object file, we can get a
+ // minidump with two mappings for a binary: one whose base image points to a
+ // memory region that is read + execute and one that is read only.
+ MemoryRegionInfos linux_regions;
+ if (CreateRegionsCacheFromLinuxMaps(*this, linux_regions))
+ llvm::sort(linux_regions);
+
+ // map module_name -> filtered_modules index
+ typedef llvm::StringMap<size_t> MapType;
+ MapType module_name_to_filtered_index;
+
+ std::vector<const minidump::Module *> filtered_modules;
+
+ for (const auto &module : *ExpectedModules) {
+ auto ExpectedName = m_file->getString(module.ModuleNameRVA);
+ if (!ExpectedName) {
+ LLDB_LOG_ERROR(log, ExpectedName.takeError(),
+ "Failed to get module name: {0}");
+ continue;
+ }
+
+ MapType::iterator iter;
+ bool inserted;
+ // See if we have inserted this module aready into filtered_modules. If we
+ // haven't insert an entry into module_name_to_filtered_index with the
+ // index where we will insert it if it isn't in the vector already.
+ std::tie(iter, inserted) = module_name_to_filtered_index.try_emplace(
+ *ExpectedName, filtered_modules.size());
+
+ if (inserted) {
+ // This module has not been seen yet, insert it into filtered_modules at
+ // the index that was inserted into module_name_to_filtered_index using
+ // "filtered_modules.size()" above.
+ filtered_modules.push_back(&module);
+ } else {
+ // We have a duplicate module entry. Check the linux regions to see if
+ // either module is not really a mapped executable. If one but not the
+ // other is a real mapped executable, prefer the executable one. This
+ // can happen when a process mmap's in the file for an executable in
+ // order to read bytes from the executable file. A memory region mapping
+ // will exist for the mmap'ed version and for the loaded executable, but
+ // only one will have a consecutive region that is executable in the
+ // memory regions.
+ auto dup_module = filtered_modules[iter->second];
+ ConstString name(*ExpectedName);
+ bool is_executable =
+ CheckForLinuxExecutable(name, linux_regions, module.BaseOfImage);
+ bool dup_is_executable =
+ CheckForLinuxExecutable(name, linux_regions, dup_module->BaseOfImage);
+
+ if (is_executable != dup_is_executable) {
+ if (is_executable)
+ filtered_modules[iter->second] = &module;
+ continue;
+ }
+ // This module has been seen. Modules are sometimes mentioned multiple
+ // times when they are mapped discontiguously, so find the module with
+ // the lowest "base_of_image" and use that as the filtered module.
+ if (module.BaseOfImage < dup_module->BaseOfImage)
+ filtered_modules[iter->second] = &module;
+ }
+ }
+ return filtered_modules;
+}
+
+const minidump::ExceptionStream *MinidumpParser::GetExceptionStream() {
+ auto ExpectedStream = GetMinidumpFile().getExceptionStream();
+ if (ExpectedStream)
+ return &*ExpectedStream;
+
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Process), ExpectedStream.takeError(),
+ "Failed to read minidump exception stream: {0}");
+ return nullptr;
+}
+
+std::optional<minidump::Range>
+MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
+ llvm::ArrayRef<uint8_t> data64 = GetStream(StreamType::Memory64List);
+ Log *log = GetLog(LLDBLog::Modules);
+
+ auto ExpectedMemory = GetMinidumpFile().getMemoryList();
+ if (!ExpectedMemory) {
+ LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),
+ "Failed to read memory list: {0}");
+ } else {
+ for (const auto &memory_desc : *ExpectedMemory) {
+ const LocationDescriptor &loc_desc = memory_desc.Memory;
+ const lldb::addr_t range_start = memory_desc.StartOfMemoryRange;
+ const size_t range_size = loc_desc.DataSize;
+
+ if (loc_desc.RVA + loc_desc.DataSize > GetData().size())
+ return std::nullopt;
+
+ if (range_start <= addr && addr < range_start + range_size) {
+ auto ExpectedSlice = GetMinidumpFile().getRawData(loc_desc);
+ if (!ExpectedSlice) {
+ LLDB_LOG_ERROR(log, ExpectedSlice.takeError(),
+ "Failed to get memory slice: {0}");
+ return std::nullopt;
+ }
+ return minidump::Range(range_start, *ExpectedSlice);
+ }
+ }
+ }
+
+ // Some Minidumps have a Memory64ListStream that captures all the heap memory
+ // (full-memory Minidumps). We can't exactly use the same loop as above,
+ // because the Minidump uses slightly different data structures to describe
+ // those
+
+ if (!data64.empty()) {
+ llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
+ uint64_t base_rva;
+ std::tie(memory64_list, base_rva) =
+ MinidumpMemoryDescriptor64::ParseMemory64List(data64);
+
+ if (memory64_list.empty())
+ return std::nullopt;
+
+ for (const auto &memory_desc64 : memory64_list) {
+ const lldb::addr_t range_start = memory_desc64.start_of_memory_range;
+ const size_t range_size = memory_desc64.data_size;
+
+ if (base_rva + range_size > GetData().size())
+ return std::nullopt;
+
+ if (range_start <= addr && addr < range_start + range_size) {
+ return minidump::Range(range_start,
+ GetData().slice(base_rva, range_size));
+ }
+ base_rva += range_size;
+ }
+ }
+
+ return std::nullopt;
+}
+
+llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
+ size_t size) {
+ // I don't have a sense of how frequently this is called or how many memory
+ // ranges a Minidump 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.
+ std::optional<minidump::Range> range = FindMemoryRange(addr);
+ if (!range)
+ return {};
+
+ // 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.
+
+ const size_t offset = addr - range->start;
+
+ if (addr < range->start || offset >= range->range_ref.size())
+ return {};
+
+ const size_t overlap = std::min(size, range->range_ref.size() - offset);
+ return range->range_ref.slice(offset, overlap);
+}
+
+static bool
+CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> &regions) {
+ Log *log = GetLog(LLDBLog::Modules);
+ auto ExpectedInfo = parser.GetMinidumpFile().getMemoryInfoList();
+ if (!ExpectedInfo) {
+ LLDB_LOG_ERROR(log, ExpectedInfo.takeError(),
+ "Failed to read memory info list: {0}");
+ return false;
+ }
+ constexpr auto yes = MemoryRegionInfo::eYes;
+ constexpr auto no = MemoryRegionInfo::eNo;
+ for (const MemoryInfo &entry : *ExpectedInfo) {
+ MemoryRegionInfo region;
+ region.GetRange().SetRangeBase(entry.BaseAddress);
+ region.GetRange().SetByteSize(entry.RegionSize);
+
+ MemoryProtection prot = entry.Protect;
+ region.SetReadable(bool(prot & MemoryProtection::NoAccess) ? no : yes);
+ region.SetWritable(
+ bool(prot & (MemoryProtection::ReadWrite | MemoryProtection::WriteCopy |
+ MemoryProtection::ExecuteReadWrite |
+ MemoryProtection::ExeciteWriteCopy))
+ ? yes
+ : no);
+ region.SetExecutable(
+ bool(prot & (MemoryProtection::Execute | MemoryProtection::ExecuteRead |
+ MemoryProtection::ExecuteReadWrite |
+ MemoryProtection::ExeciteWriteCopy))
+ ? yes
+ : no);
+ region.SetMapped(entry.State != MemoryState::Free ? yes : no);
+ regions.push_back(region);
+ }
+ return !regions.empty();
+}
+
+static bool
+CreateRegionsCacheFromMemoryList(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> &regions) {
+ Log *log = GetLog(LLDBLog::Modules);
+ auto ExpectedMemory = parser.GetMinidumpFile().getMemoryList();
+ if (!ExpectedMemory) {
+ LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),
+ "Failed to read memory list: {0}");
+ return false;
+ }
+ regions.reserve(ExpectedMemory->size());
+ for (const MemoryDescriptor &memory_desc : *ExpectedMemory) {
+ if (memory_desc.Memory.DataSize == 0)
+ continue;
+ MemoryRegionInfo region;
+ region.GetRange().SetRangeBase(memory_desc.StartOfMemoryRange);
+ region.GetRange().SetByteSize(memory_desc.Memory.DataSize);
+ region.SetReadable(MemoryRegionInfo::eYes);
+ region.SetMapped(MemoryRegionInfo::eYes);
+ regions.push_back(region);
+ }
+ regions.shrink_to_fit();
+ return !regions.empty();
+}
+
+static bool
+CreateRegionsCacheFromMemory64List(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> &regions) {
+ llvm::ArrayRef<uint8_t> data =
+ parser.GetStream(StreamType::Memory64List);
+ if (data.empty())
+ return false;
+ llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
+ uint64_t base_rva;
+ std::tie(memory64_list, base_rva) =
+ MinidumpMemoryDescriptor64::ParseMemory64List(data);
+
+ if (memory64_list.empty())
+ return false;
+
+ regions.reserve(memory64_list.size());
+ for (const auto &memory_desc : memory64_list) {
+ if (memory_desc.data_size == 0)
+ continue;
+ MemoryRegionInfo region;
+ region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
+ region.GetRange().SetByteSize(memory_desc.data_size);
+ region.SetReadable(MemoryRegionInfo::eYes);
+ region.SetMapped(MemoryRegionInfo::eYes);
+ regions.push_back(region);
+ }
+ regions.shrink_to_fit();
+ return !regions.empty();
+}
+
+std::pair<MemoryRegionInfos, bool> MinidumpParser::BuildMemoryRegions() {
+ // We create the region cache using the best source. We start with
+ // the linux maps since they are the most complete and have names for the
+ // regions. Next we try the MemoryInfoList since it has
+ // read/write/execute/map data, and then fall back to the MemoryList and
+ // Memory64List to just get a list of the memory that is mapped in this
+ // core file
+ MemoryRegionInfos result;
+ const auto &return_sorted = [&](bool is_complete) {
+ llvm::sort(result);
+ return std::make_pair(std::move(result), is_complete);
+ };
+ if (CreateRegionsCacheFromLinuxMaps(*this, result))
+ return return_sorted(true);
+ if (CreateRegionsCacheFromMemoryInfoList(*this, result))
+ return return_sorted(true);
+ if (CreateRegionsCacheFromMemoryList(*this, result))
+ return return_sorted(false);
+ CreateRegionsCacheFromMemory64List(*this, result);
+ return return_sorted(false);
+}
+
+#define ENUM_TO_CSTR(ST) \
+ case StreamType::ST: \
+ return #ST
+
+llvm::StringRef
+MinidumpParser::GetStreamTypeAsString(StreamType stream_type) {
+ switch (stream_type) {
+ ENUM_TO_CSTR(Unused);
+ ENUM_TO_CSTR(ThreadList);
+ ENUM_TO_CSTR(ModuleList);
+ ENUM_TO_CSTR(MemoryList);
+ ENUM_TO_CSTR(Exception);
+ ENUM_TO_CSTR(SystemInfo);
+ ENUM_TO_CSTR(ThreadExList);
+ ENUM_TO_CSTR(Memory64List);
+ ENUM_TO_CSTR(CommentA);
+ ENUM_TO_CSTR(CommentW);
+ ENUM_TO_CSTR(HandleData);
+ ENUM_TO_CSTR(FunctionTable);
+ ENUM_TO_CSTR(UnloadedModuleList);
+ ENUM_TO_CSTR(MiscInfo);
+ ENUM_TO_CSTR(MemoryInfoList);
+ ENUM_TO_CSTR(ThreadInfoList);
+ ENUM_TO_CSTR(HandleOperationList);
+ ENUM_TO_CSTR(Token);
+ ENUM_TO_CSTR(JavascriptData);
+ ENUM_TO_CSTR(SystemMemoryInfo);
+ ENUM_TO_CSTR(ProcessVMCounters);
+ ENUM_TO_CSTR(LastReserved);
+ ENUM_TO_CSTR(BreakpadInfo);
+ ENUM_TO_CSTR(AssertionInfo);
+ ENUM_TO_CSTR(LinuxCPUInfo);
+ ENUM_TO_CSTR(LinuxProcStatus);
+ ENUM_TO_CSTR(LinuxLSBRelease);
+ ENUM_TO_CSTR(LinuxCMDLine);
+ ENUM_TO_CSTR(LinuxEnviron);
+ ENUM_TO_CSTR(LinuxAuxv);
+ ENUM_TO_CSTR(LinuxMaps);
+ ENUM_TO_CSTR(LinuxDSODebug);
+ ENUM_TO_CSTR(LinuxProcStat);
+ ENUM_TO_CSTR(LinuxProcUptime);
+ ENUM_TO_CSTR(LinuxProcFD);
+ ENUM_TO_CSTR(FacebookAppCustomData);
+ ENUM_TO_CSTR(FacebookBuildID);
+ ENUM_TO_CSTR(FacebookAppVersionName);
+ ENUM_TO_CSTR(FacebookJavaStack);
+ ENUM_TO_CSTR(FacebookDalvikInfo);
+ ENUM_TO_CSTR(FacebookUnwindSymbols);
+ ENUM_TO_CSTR(FacebookDumpErrorLog);
+ ENUM_TO_CSTR(FacebookAppStateLog);
+ ENUM_TO_CSTR(FacebookAbortReason);
+ ENUM_TO_CSTR(FacebookThreadName);
+ ENUM_TO_CSTR(FacebookLogcat);
+ }
+ return "unknown stream type";
+}
+
+MemoryRegionInfo
+MinidumpParser::GetMemoryRegionInfo(const MemoryRegionInfos &regions,
+ lldb::addr_t load_addr) {
+ MemoryRegionInfo region;
+ auto pos = llvm::upper_bound(regions, load_addr);
+ if (pos != regions.begin() &&
+ std::prev(pos)->GetRange().Contains(load_addr)) {
+ return *std::prev(pos);
+ }
+
+ if (pos == regions.begin())
+ region.GetRange().SetRangeBase(0);
+ else
+ region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd());
+
+ if (pos == regions.end())
+ region.GetRange().SetRangeEnd(UINT64_MAX);
+ else
+ region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());
+
+ region.SetReadable(MemoryRegionInfo::eNo);
+ region.SetWritable(MemoryRegionInfo::eNo);
+ region.SetExecutable(MemoryRegionInfo::eNo);
+ region.SetMapped(MemoryRegionInfo::eNo);
+ return region;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h
new file mode 100644
index 000000000000..050ba086f46f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h
@@ -0,0 +1,113 @@
+//===-- MinidumpParser.h -----------------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPPARSER_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPPARSER_H
+
+#include "MinidumpTypes.h"
+
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/UUID.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Minidump.h"
+
+// C includes
+
+// C++ includes
+#include <cstring>
+#include <optional>
+#include <unordered_map>
+
+namespace lldb_private {
+
+namespace minidump {
+
+// Describes a range of memory captured in the Minidump
+struct Range {
+ lldb::addr_t start; // virtual address of the beginning of the range
+ // range_ref - absolute pointer to the first byte of the range and size
+ llvm::ArrayRef<uint8_t> range_ref;
+
+ Range(lldb::addr_t start, llvm::ArrayRef<uint8_t> range_ref)
+ : start(start), range_ref(range_ref) {}
+
+ friend bool operator==(const Range &lhs, const Range &rhs) {
+ return lhs.start == rhs.start && lhs.range_ref == rhs.range_ref;
+ }
+};
+
+class MinidumpParser {
+public:
+ static llvm::Expected<MinidumpParser>
+ Create(const lldb::DataBufferSP &data_buf_sp);
+
+ llvm::ArrayRef<uint8_t> GetData();
+
+ llvm::ArrayRef<uint8_t> GetStream(StreamType stream_type);
+
+ UUID GetModuleUUID(const minidump::Module *module);
+
+ llvm::ArrayRef<minidump::Thread> GetThreads();
+
+ llvm::ArrayRef<uint8_t> GetThreadContext(const LocationDescriptor &location);
+
+ llvm::ArrayRef<uint8_t> GetThreadContext(const minidump::Thread &td);
+
+ llvm::ArrayRef<uint8_t> GetThreadContextWow64(const minidump::Thread &td);
+
+ ArchSpec GetArchitecture();
+
+ const MinidumpMiscInfo *GetMiscInfo();
+
+ std::optional<LinuxProcStatus> GetLinuxProcStatus();
+
+ std::optional<lldb::pid_t> GetPid();
+
+ llvm::ArrayRef<minidump::Module> GetModuleList();
+
+ // There are cases in which there is more than one record in the ModuleList
+ // for the same module name.(e.g. when the binary has non contiguous segments)
+ // So this function returns a filtered module list - if it finds records that
+ // have the same name, it keeps the copy with the lowest load address.
+ std::vector<const minidump::Module *> GetFilteredModuleList();
+
+ const llvm::minidump::ExceptionStream *GetExceptionStream();
+
+ std::optional<Range> FindMemoryRange(lldb::addr_t addr);
+
+ llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size);
+
+ /// Returns a list of memory regions and a flag indicating whether the list is
+ /// complete (includes all regions mapped into the process memory).
+ std::pair<MemoryRegionInfos, bool> BuildMemoryRegions();
+
+ static llvm::StringRef GetStreamTypeAsString(StreamType stream_type);
+
+ llvm::object::MinidumpFile &GetMinidumpFile() { return *m_file; }
+
+ static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos &regions,
+ lldb::addr_t load_addr);
+
+private:
+ MinidumpParser(lldb::DataBufferSP data_sp,
+ std::unique_ptr<llvm::object::MinidumpFile> file);
+
+ lldb::DataBufferSP m_data_sp;
+ std::unique_ptr<llvm::object::MinidumpFile> m_file;
+ ArchSpec m_arch;
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPPARSER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
new file mode 100644
index 000000000000..5b919828428f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
@@ -0,0 +1,79 @@
+//===-- MinidumpTypes.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinidumpTypes.h"
+#include <optional>
+
+// C includes
+// C++ includes
+
+using namespace lldb_private;
+using namespace minidump;
+
+// MinidumpMiscInfo
+const MinidumpMiscInfo *MinidumpMiscInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
+ const MinidumpMiscInfo *misc_info;
+ Status error = consumeObject(data, misc_info);
+ if (error.Fail())
+ return nullptr;
+
+ return misc_info;
+}
+
+std::optional<lldb::pid_t> MinidumpMiscInfo::GetPid() const {
+ uint32_t pid_flag = static_cast<uint32_t>(MinidumpMiscInfoFlags::ProcessID);
+ if (flags1 & pid_flag)
+ return std::optional<lldb::pid_t>(process_id);
+
+ return std::nullopt;
+}
+
+// Linux Proc Status
+// it's stored as an ascii string in the file
+std::optional<LinuxProcStatus>
+LinuxProcStatus::Parse(llvm::ArrayRef<uint8_t> &data) {
+ LinuxProcStatus result;
+ result.proc_status =
+ llvm::StringRef(reinterpret_cast<const char *>(data.data()), data.size());
+ data = data.drop_front(data.size());
+
+ llvm::SmallVector<llvm::StringRef, 0> lines;
+ result.proc_status.split(lines, '\n', 42);
+ // /proc/$pid/status has 41 lines, but why not use 42?
+ for (auto line : lines) {
+ if (line.consume_front("Pid:")) {
+ line = line.trim();
+ if (!line.getAsInteger(10, result.pid))
+ return result;
+ }
+ }
+
+ return std::nullopt;
+}
+
+lldb::pid_t LinuxProcStatus::GetPid() const { return pid; }
+
+std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
+MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef<uint8_t> &data) {
+ const llvm::support::ulittle64_t *mem_ranges_count;
+ Status error = consumeObject(data, mem_ranges_count);
+ if (error.Fail() ||
+ *mem_ranges_count * sizeof(MinidumpMemoryDescriptor64) > data.size())
+ return {};
+
+ const llvm::support::ulittle64_t *base_rva;
+ error = consumeObject(data, base_rva);
+ if (error.Fail())
+ return {};
+
+ return std::make_pair(
+ llvm::ArrayRef(
+ reinterpret_cast<const MinidumpMemoryDescriptor64 *>(data.data()),
+ *mem_ranges_count),
+ *base_rva);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
new file mode 100644
index 000000000000..fe99abf9e24e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
@@ -0,0 +1,107 @@
+//===-- MinidumpTypes.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPTYPES_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPTYPES_H
+
+#include "lldb/Utility/Status.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Minidump.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Endian.h"
+#include <optional>
+
+// C includes
+// C++ includes
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms679293(v=vs.85).aspx
+// https://chromium.googlesource.com/breakpad/breakpad/
+
+namespace lldb_private {
+
+namespace minidump {
+
+using namespace llvm::minidump;
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+enum class CvSignature : uint32_t {
+ Pdb70 = 0x53445352, // RSDS
+ ElfBuildId = 0x4270454c, // BpEL (Breakpad/Crashpad minidumps)
+};
+
+enum class MinidumpMiscInfoFlags : uint32_t {
+ ProcessID = (1 << 0),
+ ProcessTimes = (1 << 1),
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ ProcessTimes)
+};
+
+template <typename T>
+Status consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) {
+ Status error;
+ if (Buffer.size() < sizeof(T)) {
+ error.SetErrorString("Insufficient buffer!");
+ return error;
+ }
+
+ Object = reinterpret_cast<const T *>(Buffer.data());
+ Buffer = Buffer.drop_front(sizeof(T));
+ return error;
+}
+
+struct MinidumpMemoryDescriptor64 {
+ llvm::support::ulittle64_t start_of_memory_range;
+ llvm::support::ulittle64_t data_size;
+
+ static std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
+ ParseMemory64List(llvm::ArrayRef<uint8_t> &data);
+};
+static_assert(sizeof(MinidumpMemoryDescriptor64) == 16,
+ "sizeof MinidumpMemoryDescriptor64 is not correct!");
+
+// TODO misc2, misc3 ?
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680389(v=vs.85).aspx
+struct MinidumpMiscInfo {
+ llvm::support::ulittle32_t size;
+ // flags1 represents what info in the struct is valid
+ llvm::support::ulittle32_t flags1;
+ llvm::support::ulittle32_t process_id;
+ llvm::support::ulittle32_t process_create_time;
+ llvm::support::ulittle32_t process_user_time;
+ llvm::support::ulittle32_t process_kernel_time;
+
+ static const MinidumpMiscInfo *Parse(llvm::ArrayRef<uint8_t> &data);
+
+ std::optional<lldb::pid_t> GetPid() const;
+};
+static_assert(sizeof(MinidumpMiscInfo) == 24,
+ "sizeof MinidumpMiscInfo is not correct!");
+
+// The /proc/pid/status is saved as an ascii string in the file
+class LinuxProcStatus {
+public:
+ llvm::StringRef proc_status;
+ lldb::pid_t pid;
+
+ static std::optional<LinuxProcStatus> Parse(llvm::ArrayRef<uint8_t> &data);
+
+ lldb::pid_t GetPid() const;
+
+private:
+ LinuxProcStatus() = default;
+};
+
+} // namespace minidump
+} // namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPTYPES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/NtStructures.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/NtStructures.h
new file mode 100644
index 000000000000..1dafbe4a4f50
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/NtStructures.h
@@ -0,0 +1,42 @@
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_NTSTRUCTURES_H
+
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_NTSTRUCTURES_H
+
+//===-- NtStructures.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Plugins_Process_Minidump_NtStructures_h_
+#define liblldb_Plugins_Process_Minidump_NtStructures_h_
+
+#include "llvm/Support/Endian.h"
+
+namespace lldb_private {
+
+namespace minidump {
+
+// This describes the layout of a TEB (Thread Environment Block) for a 64-bit
+// process. It's adapted from the 32-bit TEB in winternl.h. Currently, we care
+// only about the position of the tls_slots.
+struct TEB64 {
+ llvm::support::ulittle64_t reserved1[12];
+ llvm::support::ulittle64_t process_environment_block;
+ llvm::support::ulittle64_t reserved2[399];
+ uint8_t reserved3[1952];
+ llvm::support::ulittle64_t tls_slots[64];
+ uint8_t reserved4[8];
+ llvm::support::ulittle64_t reserved5[26];
+ llvm::support::ulittle64_t reserved_for_ole; // Windows 2000 only
+ llvm::support::ulittle64_t reserved6[4];
+ llvm::support::ulittle64_t tls_expansion_slots;
+};
+
+#endif // liblldb_Plugins_Process_Minidump_NtStructures_h_
+} // namespace minidump
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
new file mode 100644
index 000000000000..13599f4a1553
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -0,0 +1,929 @@
+//===-- ProcessMinidump.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessMinidump.h"
+
+#include "ThreadMinidump.h"
+
+#include "lldb/Core/DumpDataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionGroupBoolean.h"
+#include "lldb/Target/JITLoaderList.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Threading.h"
+
+#include "Plugins/ObjectFile/Placeholder/ObjectFilePlaceholder.h"
+#include "Plugins/Process/Utility/StopInfoMachException.h"
+
+#include <memory>
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace minidump;
+
+LLDB_PLUGIN_DEFINE(ProcessMinidump)
+
+namespace {
+
+/// Duplicate the HashElfTextSection() from the breakpad sources.
+///
+/// Breakpad, a Google crash log reporting tool suite, creates minidump files
+/// for many different architectures. When using Breakpad to create ELF
+/// minidumps, it will check for a GNU build ID when creating a minidump file
+/// and if one doesn't exist in the file, it will say the UUID of the file is a
+/// checksum of up to the first 4096 bytes of the .text section. Facebook also
+/// uses breakpad and modified this hash to avoid collisions so we can
+/// calculate and check for this as well.
+///
+/// The breakpad code might end up hashing up to 15 bytes that immediately
+/// follow the .text section in the file, so this code must do exactly what it
+/// does so we can get an exact match for the UUID.
+///
+/// \param[in] module_sp The module to grab the .text section from.
+///
+/// \param[in,out] breakpad_uuid A vector that will receive the calculated
+/// breakpad .text hash.
+///
+/// \param[in,out] facebook_uuid A vector that will receive the calculated
+/// facebook .text hash.
+///
+void HashElfTextSection(ModuleSP module_sp, std::vector<uint8_t> &breakpad_uuid,
+ std::vector<uint8_t> &facebook_uuid) {
+ SectionList *sect_list = module_sp->GetSectionList();
+ if (sect_list == nullptr)
+ return;
+ SectionSP sect_sp = sect_list->FindSectionByName(ConstString(".text"));
+ if (!sect_sp)
+ return;
+ constexpr size_t kMDGUIDSize = 16;
+ constexpr size_t kBreakpadPageSize = 4096;
+ // The breakpad code has a bug where it might access beyond the end of a
+ // .text section by up to 15 bytes, so we must ensure we round up to the
+ // next kMDGUIDSize byte boundary.
+ DataExtractor data;
+ const size_t text_size = sect_sp->GetFileSize();
+ const size_t read_size = std::min<size_t>(
+ llvm::alignTo(text_size, kMDGUIDSize), kBreakpadPageSize);
+ sect_sp->GetObjectFile()->GetData(sect_sp->GetFileOffset(), read_size, data);
+
+ breakpad_uuid.assign(kMDGUIDSize, 0);
+ facebook_uuid.assign(kMDGUIDSize, 0);
+
+ // The only difference between the breakpad hash and the facebook hash is the
+ // hashing of the text section size into the hash prior to hashing the .text
+ // contents.
+ for (size_t i = 0; i < kMDGUIDSize; i++)
+ facebook_uuid[i] ^= text_size % 255;
+
+ // This code carefully duplicates how the hash was created in Breakpad
+ // sources, including the error where it might has an extra 15 bytes past the
+ // end of the .text section if the .text section is less than a page size in
+ // length.
+ const uint8_t *ptr = data.GetDataStart();
+ const uint8_t *ptr_end = data.GetDataEnd();
+ while (ptr < ptr_end) {
+ for (unsigned i = 0; i < kMDGUIDSize; i++) {
+ breakpad_uuid[i] ^= ptr[i];
+ facebook_uuid[i] ^= ptr[i];
+ }
+ ptr += kMDGUIDSize;
+ }
+}
+
+} // namespace
+
+llvm::StringRef ProcessMinidump::GetPluginDescriptionStatic() {
+ return "Minidump plug-in.";
+}
+
+lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file,
+ bool can_connect) {
+ if (!crash_file || can_connect)
+ return nullptr;
+
+ lldb::ProcessSP process_sp;
+ // Read enough data for the Minidump header
+ constexpr size_t header_size = sizeof(Header);
+ auto DataPtr = FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(),
+ header_size, 0);
+ if (!DataPtr)
+ return nullptr;
+
+ lldbassert(DataPtr->GetByteSize() == header_size);
+ if (identify_magic(toStringRef(DataPtr->GetData())) != llvm::file_magic::minidump)
+ return nullptr;
+
+ auto AllData =
+ FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), -1, 0);
+ if (!AllData)
+ return nullptr;
+
+ return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file,
+ std::move(AllData));
+}
+
+bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) {
+ return true;
+}
+
+ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec &core_file,
+ DataBufferSP core_data)
+ : PostMortemProcess(target_sp, listener_sp, core_file),
+ m_core_data(std::move(core_data)), m_active_exception(nullptr),
+ m_is_wow64(false) {}
+
+ProcessMinidump::~ProcessMinidump() {
+ 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(true /* destructing */);
+}
+
+void ProcessMinidump::Initialize() {
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ ProcessMinidump::CreateInstance);
+ });
+}
+
+void ProcessMinidump::Terminate() {
+ PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance);
+}
+
+Status ProcessMinidump::DoLoadCore() {
+ auto expected_parser = MinidumpParser::Create(m_core_data);
+ if (!expected_parser)
+ return Status(expected_parser.takeError());
+ m_minidump_parser = std::move(*expected_parser);
+
+ Status error;
+
+ // Do we support the minidump's architecture?
+ ArchSpec arch = GetArchitecture();
+ switch (arch.GetMachine()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ // Any supported architectures must be listed here and also supported in
+ // ThreadMinidump::CreateRegisterContextForFrame().
+ break;
+ default:
+ error.SetErrorStringWithFormat("unsupported minidump architecture: %s",
+ arch.GetArchitectureName());
+ return error;
+ }
+ GetTarget().SetArchitecture(arch, true /*set_platform*/);
+
+ m_thread_list = m_minidump_parser->GetThreads();
+ m_active_exception = m_minidump_parser->GetExceptionStream();
+
+ SetUnixSignals(UnixSignals::Create(GetArchitecture()));
+
+ ReadModuleList();
+ if (ModuleSP module = GetTarget().GetExecutableModule())
+ GetTarget().MergeArchitecture(module->GetArchitecture());
+ std::optional<lldb::pid_t> pid = m_minidump_parser->GetPid();
+ if (!pid) {
+ Debugger::ReportWarning("unable to retrieve process ID from minidump file, "
+ "setting process ID to 1",
+ GetTarget().GetDebugger().GetID());
+ pid = 1;
+ }
+ SetID(*pid);
+
+ return error;
+}
+
+Status ProcessMinidump::DoDestroy() { return Status(); }
+
+void ProcessMinidump::RefreshStateAfterStop() {
+
+ if (!m_active_exception)
+ return;
+
+ constexpr uint32_t BreakpadDumpRequested = 0xFFFFFFFF;
+ if (m_active_exception->ExceptionRecord.ExceptionCode ==
+ BreakpadDumpRequested) {
+ // This "ExceptionCode" value is a sentinel that is sometimes used
+ // when generating a dump for a process that hasn't crashed.
+
+ // TODO: The definition and use of this "dump requested" constant
+ // in Breakpad are actually Linux-specific, and for similar use
+ // cases on Mac/Windows it defines different constants, referring
+ // to them as "simulated" exceptions; consider moving this check
+ // down to the OS-specific paths and checking each OS for its own
+ // constant.
+ return;
+ }
+
+ lldb::StopInfoSP stop_info;
+ lldb::ThreadSP stop_thread;
+
+ Process::m_thread_list.SetSelectedThreadByID(m_active_exception->ThreadId);
+ stop_thread = Process::m_thread_list.GetSelectedThread();
+ ArchSpec arch = GetArchitecture();
+
+ if (arch.GetTriple().getOS() == llvm::Triple::Linux) {
+ uint32_t signo = m_active_exception->ExceptionRecord.ExceptionCode;
+
+ if (signo == 0) {
+ // No stop.
+ return;
+ }
+
+ stop_info = StopInfo::CreateStopReasonWithSignal(
+ *stop_thread, signo);
+ } else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) {
+ stop_info = StopInfoMachException::CreateStopReasonWithMachException(
+ *stop_thread, m_active_exception->ExceptionRecord.ExceptionCode, 2,
+ m_active_exception->ExceptionRecord.ExceptionFlags,
+ m_active_exception->ExceptionRecord.ExceptionAddress, 0);
+ } else {
+ std::string desc;
+ llvm::raw_string_ostream desc_stream(desc);
+ desc_stream << "Exception "
+ << llvm::format_hex(
+ m_active_exception->ExceptionRecord.ExceptionCode, 8)
+ << " encountered at address "
+ << llvm::format_hex(
+ m_active_exception->ExceptionRecord.ExceptionAddress, 8);
+ stop_info = StopInfo::CreateStopReasonWithException(
+ *stop_thread, desc_stream.str().c_str());
+ }
+
+ stop_thread->SetStopInfo(stop_info);
+}
+
+bool ProcessMinidump::IsAlive() { return true; }
+
+bool ProcessMinidump::WarnBeforeDetach() const { return false; }
+
+size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) {
+ // Don't allow the caching that lldb_private::Process::ReadMemory does since
+ // we have it all cached in our dump file anyway.
+ return DoReadMemory(addr, buf, size, error);
+}
+
+size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) {
+
+ llvm::ArrayRef<uint8_t> mem = m_minidump_parser->GetMemory(addr, size);
+ if (mem.empty()) {
+ error.SetErrorString("could not parse memory info");
+ return 0;
+ }
+
+ std::memcpy(buf, mem.data(), mem.size());
+ return mem.size();
+}
+
+ArchSpec ProcessMinidump::GetArchitecture() {
+ if (!m_is_wow64) {
+ return m_minidump_parser->GetArchitecture();
+ }
+
+ llvm::Triple triple;
+ triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
+ triple.setArch(llvm::Triple::ArchType::x86);
+ triple.setOS(llvm::Triple::OSType::Win32);
+ return ArchSpec(triple);
+}
+
+void ProcessMinidump::BuildMemoryRegions() {
+ if (m_memory_regions)
+ return;
+ m_memory_regions.emplace();
+ bool is_complete;
+ std::tie(*m_memory_regions, is_complete) =
+ m_minidump_parser->BuildMemoryRegions();
+
+ if (is_complete)
+ return;
+
+ MemoryRegionInfos to_add;
+ ModuleList &modules = GetTarget().GetImages();
+ SectionLoadList &load_list = GetTarget().GetSectionLoadList();
+ modules.ForEach([&](const ModuleSP &module_sp) {
+ SectionList *sections = module_sp->GetSectionList();
+ for (size_t i = 0; i < sections->GetSize(); ++i) {
+ SectionSP section_sp = sections->GetSectionAtIndex(i);
+ addr_t load_addr = load_list.GetSectionLoadAddress(section_sp);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ continue;
+ MemoryRegionInfo::RangeType section_range(load_addr,
+ section_sp->GetByteSize());
+ MemoryRegionInfo region =
+ MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr);
+ if (region.GetMapped() != MemoryRegionInfo::eYes &&
+ region.GetRange().GetRangeBase() <= section_range.GetRangeBase() &&
+ section_range.GetRangeEnd() <= region.GetRange().GetRangeEnd()) {
+ to_add.emplace_back();
+ to_add.back().GetRange() = section_range;
+ to_add.back().SetLLDBPermissions(section_sp->GetPermissions());
+ to_add.back().SetMapped(MemoryRegionInfo::eYes);
+ to_add.back().SetName(module_sp->GetFileSpec().GetPath().c_str());
+ }
+ }
+ return true;
+ });
+ m_memory_regions->insert(m_memory_regions->end(), to_add.begin(),
+ to_add.end());
+ llvm::sort(*m_memory_regions);
+}
+
+Status ProcessMinidump::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &region) {
+ BuildMemoryRegions();
+ region = MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr);
+ return Status();
+}
+
+Status ProcessMinidump::GetMemoryRegions(MemoryRegionInfos &region_list) {
+ BuildMemoryRegions();
+ region_list = *m_memory_regions;
+ return Status();
+}
+
+void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
+
+bool ProcessMinidump::DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
+ for (const minidump::Thread &thread : m_thread_list) {
+ LocationDescriptor context_location = thread.Context;
+
+ // If the minidump contains an exception context, use it
+ if (m_active_exception != nullptr &&
+ m_active_exception->ThreadId == thread.ThreadId) {
+ context_location = m_active_exception->ThreadContext;
+ }
+
+ llvm::ArrayRef<uint8_t> context;
+ if (!m_is_wow64)
+ context = m_minidump_parser->GetThreadContext(context_location);
+ else
+ context = m_minidump_parser->GetThreadContextWow64(thread);
+
+ lldb::ThreadSP thread_sp(new ThreadMinidump(*this, thread, context));
+ new_thread_list.AddThread(thread_sp);
+ }
+ return new_thread_list.GetSize(false) > 0;
+}
+
+ModuleSP ProcessMinidump::GetOrCreateModule(UUID minidump_uuid,
+ llvm::StringRef name,
+ ModuleSpec module_spec) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ Status error;
+
+ ModuleSP module_sp =
+ GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error);
+ if (!module_sp)
+ return module_sp;
+ // We consider the module to be a match if the minidump UUID is a
+ // prefix of the actual UUID, or if either of the UUIDs are empty.
+ const auto dmp_bytes = minidump_uuid.GetBytes();
+ const auto mod_bytes = module_sp->GetUUID().GetBytes();
+ const bool match = dmp_bytes.empty() || mod_bytes.empty() ||
+ mod_bytes.take_front(dmp_bytes.size()) == dmp_bytes;
+ if (match) {
+ LLDB_LOG(log, "Partial uuid match for {0}.", name);
+ return module_sp;
+ }
+
+ // Breakpad generates minindump files, and if there is no GNU build
+ // ID in the binary, it will calculate a UUID by hashing first 4096
+ // bytes of the .text section and using that as the UUID for a module
+ // in the minidump. Facebook uses a modified breakpad client that
+ // uses a slightly modified this hash to avoid collisions. Check for
+ // UUIDs from the minindump that match these cases and accept the
+ // module we find if they do match.
+ std::vector<uint8_t> breakpad_uuid;
+ std::vector<uint8_t> facebook_uuid;
+ HashElfTextSection(module_sp, breakpad_uuid, facebook_uuid);
+ if (dmp_bytes == llvm::ArrayRef<uint8_t>(breakpad_uuid)) {
+ LLDB_LOG(log, "Breakpad .text hash match for {0}.", name);
+ return module_sp;
+ }
+ if (dmp_bytes == llvm::ArrayRef<uint8_t>(facebook_uuid)) {
+ LLDB_LOG(log, "Facebook .text hash match for {0}.", name);
+ return module_sp;
+ }
+ // The UUID wasn't a partial match and didn't match the .text hash
+ // so remove the module from the target, we will need to create a
+ // placeholder object file.
+ GetTarget().GetImages().Remove(module_sp);
+ module_sp.reset();
+ return module_sp;
+}
+
+void ProcessMinidump::ReadModuleList() {
+ std::vector<const minidump::Module *> filtered_modules =
+ m_minidump_parser->GetFilteredModuleList();
+
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ for (auto module : filtered_modules) {
+ std::string name = cantFail(m_minidump_parser->GetMinidumpFile().getString(
+ module->ModuleNameRVA));
+ const uint64_t load_addr = module->BaseOfImage;
+ const uint64_t load_size = module->SizeOfImage;
+ LLDB_LOG(log, "found module: name: {0} {1:x10}-{2:x10} size: {3}", name,
+ load_addr, load_addr + load_size, load_size);
+
+ // check if the process is wow64 - a 32 bit windows process running on a
+ // 64 bit windows
+ if (llvm::StringRef(name).ends_with_insensitive("wow64.dll")) {
+ m_is_wow64 = true;
+ }
+
+ const auto uuid = m_minidump_parser->GetModuleUUID(module);
+ auto file_spec = FileSpec(name, GetArchitecture().GetTriple());
+ ModuleSpec module_spec(file_spec, uuid);
+ module_spec.GetArchitecture() = GetArchitecture();
+ Status error;
+ // Try and find a module with a full UUID that matches. This function will
+ // add the module to the target if it finds one.
+ lldb::ModuleSP module_sp = GetTarget().GetOrCreateModule(module_spec,
+ true /* notify */, &error);
+ if (module_sp) {
+ LLDB_LOG(log, "Full uuid match for {0}.", name);
+ } else {
+ // We couldn't find a module with an exactly-matching UUID. Sometimes
+ // a minidump UUID is only a partial match or is a hash. So try again
+ // without specifying the UUID, then again without specifying the
+ // directory if that fails. This will allow us to find modules with
+ // partial matches or hash UUIDs in user-provided sysroots or search
+ // directories (target.exec-search-paths).
+ ModuleSpec partial_module_spec = module_spec;
+ partial_module_spec.GetUUID().Clear();
+ module_sp = GetOrCreateModule(uuid, name, partial_module_spec);
+ if (!module_sp) {
+ partial_module_spec.GetFileSpec().ClearDirectory();
+ module_sp = GetOrCreateModule(uuid, name, partial_module_spec);
+ }
+ }
+ if (module_sp) {
+ // Watch out for place holder modules that have different paths, but the
+ // same UUID. If the base address is different, create a new module. If
+ // we don't then we will end up setting the load address of a different
+ // ObjectFilePlaceholder and an assertion will fire.
+ auto *objfile = module_sp->GetObjectFile();
+ if (objfile &&
+ objfile->GetPluginName() ==
+ ObjectFilePlaceholder::GetPluginNameStatic()) {
+ if (((ObjectFilePlaceholder *)objfile)->GetBaseImageAddress() !=
+ load_addr)
+ module_sp.reset();
+ }
+ }
+ if (!module_sp) {
+ // We failed to locate a matching local object file. Fortunately, the
+ // minidump format encodes enough information about each module's memory
+ // range to allow us to create placeholder modules.
+ //
+ // This enables most LLDB functionality involving address-to-module
+ // translations (ex. identifing the module for a stack frame PC) and
+ // modules/sections commands (ex. target modules list, ...)
+ LLDB_LOG(log,
+ "Unable to locate the matching object file, creating a "
+ "placeholder module for: {0}",
+ name);
+
+ module_sp = Module::CreateModuleFromObjectFile<ObjectFilePlaceholder>(
+ module_spec, load_addr, load_size);
+ GetTarget().GetImages().Append(module_sp, true /* notify */);
+ }
+
+ bool load_addr_changed = false;
+ module_sp->SetLoadAddress(GetTarget(), load_addr, false,
+ load_addr_changed);
+ }
+}
+
+bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) {
+ info.Clear();
+ info.SetProcessID(GetID());
+ info.SetArchitecture(GetArchitecture());
+ lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
+ if (module_sp) {
+ const bool add_exe_file_as_first_arg = false;
+ info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
+ add_exe_file_as_first_arg);
+ }
+ return true;
+}
+
+// For minidumps there's no runtime generated code so we don't need JITLoader(s)
+// Avoiding them will also speed up minidump loading since JITLoaders normally
+// try to set up symbolic breakpoints, which in turn may force loading more
+// debug information than needed.
+JITLoaderList &ProcessMinidump::GetJITLoaders() {
+ if (!m_jit_loaders_up) {
+ m_jit_loaders_up = std::make_unique<JITLoaderList>();
+ }
+ return *m_jit_loaders_up;
+}
+
+#define INIT_BOOL(VAR, LONG, SHORT, DESC) \
+ VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true)
+#define APPEND_OPT(VAR) \
+ m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)
+
+class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
+private:
+ OptionGroupOptions m_option_group;
+ OptionGroupBoolean m_dump_all;
+ OptionGroupBoolean m_dump_directory;
+ OptionGroupBoolean m_dump_linux_cpuinfo;
+ OptionGroupBoolean m_dump_linux_proc_status;
+ OptionGroupBoolean m_dump_linux_lsb_release;
+ OptionGroupBoolean m_dump_linux_cmdline;
+ OptionGroupBoolean m_dump_linux_environ;
+ OptionGroupBoolean m_dump_linux_auxv;
+ OptionGroupBoolean m_dump_linux_maps;
+ OptionGroupBoolean m_dump_linux_proc_stat;
+ OptionGroupBoolean m_dump_linux_proc_uptime;
+ OptionGroupBoolean m_dump_linux_proc_fd;
+ OptionGroupBoolean m_dump_linux_all;
+ OptionGroupBoolean m_fb_app_data;
+ OptionGroupBoolean m_fb_build_id;
+ OptionGroupBoolean m_fb_version;
+ OptionGroupBoolean m_fb_java_stack;
+ OptionGroupBoolean m_fb_dalvik;
+ OptionGroupBoolean m_fb_unwind;
+ OptionGroupBoolean m_fb_error_log;
+ OptionGroupBoolean m_fb_app_state;
+ OptionGroupBoolean m_fb_abort;
+ OptionGroupBoolean m_fb_thread;
+ OptionGroupBoolean m_fb_logcat;
+ OptionGroupBoolean m_fb_all;
+
+ void SetDefaultOptionsIfNoneAreSet() {
+ if (m_dump_all.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_all.GetOptionValue().GetCurrentValue() ||
+ m_fb_all.GetOptionValue().GetCurrentValue() ||
+ m_dump_directory.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_environ.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_auxv.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_maps.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue() ||
+ m_fb_app_data.GetOptionValue().GetCurrentValue() ||
+ m_fb_build_id.GetOptionValue().GetCurrentValue() ||
+ m_fb_version.GetOptionValue().GetCurrentValue() ||
+ m_fb_java_stack.GetOptionValue().GetCurrentValue() ||
+ m_fb_dalvik.GetOptionValue().GetCurrentValue() ||
+ m_fb_unwind.GetOptionValue().GetCurrentValue() ||
+ m_fb_error_log.GetOptionValue().GetCurrentValue() ||
+ m_fb_app_state.GetOptionValue().GetCurrentValue() ||
+ m_fb_abort.GetOptionValue().GetCurrentValue() ||
+ m_fb_thread.GetOptionValue().GetCurrentValue() ||
+ m_fb_logcat.GetOptionValue().GetCurrentValue())
+ return;
+ // If no options were set, then dump everything
+ m_dump_all.GetOptionValue().SetCurrentValue(true);
+ }
+ bool DumpAll() const {
+ return m_dump_all.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpDirectory() const {
+ return DumpAll() ||
+ m_dump_directory.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinux() const {
+ return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxCPUInfo() const {
+ return DumpLinux() ||
+ m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcStatus() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_status.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcStat() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxLSBRelease() const {
+ return DumpLinux() ||
+ m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxCMDLine() const {
+ return DumpLinux() ||
+ m_dump_linux_cmdline.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxEnviron() const {
+ return DumpLinux() ||
+ m_dump_linux_environ.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxAuxv() const {
+ return DumpLinux() ||
+ m_dump_linux_auxv.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxMaps() const {
+ return DumpLinux() ||
+ m_dump_linux_maps.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcUptime() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcFD() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebook() const {
+ return DumpAll() || m_fb_all.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookAppData() const {
+ return DumpFacebook() || m_fb_app_data.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookBuildID() const {
+ return DumpFacebook() || m_fb_build_id.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookVersionName() const {
+ return DumpFacebook() || m_fb_version.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookJavaStack() const {
+ return DumpFacebook() || m_fb_java_stack.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookDalvikInfo() const {
+ return DumpFacebook() || m_fb_dalvik.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookUnwindSymbols() const {
+ return DumpFacebook() || m_fb_unwind.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookErrorLog() const {
+ return DumpFacebook() || m_fb_error_log.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookAppStateLog() const {
+ return DumpFacebook() || m_fb_app_state.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookAbortReason() const {
+ return DumpFacebook() || m_fb_abort.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookThreadName() const {
+ return DumpFacebook() || m_fb_thread.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookLogcat() const {
+ return DumpFacebook() || m_fb_logcat.GetOptionValue().GetCurrentValue();
+ }
+public:
+ CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "process plugin dump",
+ "Dump information from the minidump file.", nullptr),
+ m_option_group(),
+ INIT_BOOL(m_dump_all, "all", 'a',
+ "Dump the everything in the minidump."),
+ INIT_BOOL(m_dump_directory, "directory", 'd',
+ "Dump the minidump directory map."),
+ INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C',
+ "Dump linux /proc/cpuinfo."),
+ INIT_BOOL(m_dump_linux_proc_status, "status", 's',
+ "Dump linux /proc/<pid>/status."),
+ INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r',
+ "Dump linux /etc/lsb-release."),
+ INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c',
+ "Dump linux /proc/<pid>/cmdline."),
+ INIT_BOOL(m_dump_linux_environ, "environ", 'e',
+ "Dump linux /proc/<pid>/environ."),
+ INIT_BOOL(m_dump_linux_auxv, "auxv", 'x',
+ "Dump linux /proc/<pid>/auxv."),
+ INIT_BOOL(m_dump_linux_maps, "maps", 'm',
+ "Dump linux /proc/<pid>/maps."),
+ INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S',
+ "Dump linux /proc/<pid>/stat."),
+ INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u',
+ "Dump linux process uptime."),
+ INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f',
+ "Dump linux /proc/<pid>/fd."),
+ INIT_BOOL(m_dump_linux_all, "linux", 'l',
+ "Dump all linux streams."),
+ INIT_BOOL(m_fb_app_data, "fb-app-data", 1,
+ "Dump Facebook application custom data."),
+ INIT_BOOL(m_fb_build_id, "fb-build-id", 2,
+ "Dump the Facebook build ID."),
+ INIT_BOOL(m_fb_version, "fb-version", 3,
+ "Dump Facebook application version string."),
+ INIT_BOOL(m_fb_java_stack, "fb-java-stack", 4,
+ "Dump Facebook java stack."),
+ INIT_BOOL(m_fb_dalvik, "fb-dalvik-info", 5,
+ "Dump Facebook Dalvik info."),
+ INIT_BOOL(m_fb_unwind, "fb-unwind-symbols", 6,
+ "Dump Facebook unwind symbols."),
+ INIT_BOOL(m_fb_error_log, "fb-error-log", 7,
+ "Dump Facebook error log."),
+ INIT_BOOL(m_fb_app_state, "fb-app-state-log", 8,
+ "Dump Facebook java stack."),
+ INIT_BOOL(m_fb_abort, "fb-abort-reason", 9,
+ "Dump Facebook abort reason."),
+ INIT_BOOL(m_fb_thread, "fb-thread-name", 10,
+ "Dump Facebook thread name."),
+ INIT_BOOL(m_fb_logcat, "fb-logcat", 11,
+ "Dump Facebook logcat."),
+ INIT_BOOL(m_fb_all, "facebook", 12, "Dump all Facebook streams.") {
+ APPEND_OPT(m_dump_all);
+ APPEND_OPT(m_dump_directory);
+ APPEND_OPT(m_dump_linux_cpuinfo);
+ APPEND_OPT(m_dump_linux_proc_status);
+ APPEND_OPT(m_dump_linux_lsb_release);
+ APPEND_OPT(m_dump_linux_cmdline);
+ APPEND_OPT(m_dump_linux_environ);
+ APPEND_OPT(m_dump_linux_auxv);
+ APPEND_OPT(m_dump_linux_maps);
+ APPEND_OPT(m_dump_linux_proc_stat);
+ APPEND_OPT(m_dump_linux_proc_uptime);
+ APPEND_OPT(m_dump_linux_proc_fd);
+ APPEND_OPT(m_dump_linux_all);
+ APPEND_OPT(m_fb_app_data);
+ APPEND_OPT(m_fb_build_id);
+ APPEND_OPT(m_fb_version);
+ APPEND_OPT(m_fb_java_stack);
+ APPEND_OPT(m_fb_dalvik);
+ APPEND_OPT(m_fb_unwind);
+ APPEND_OPT(m_fb_error_log);
+ APPEND_OPT(m_fb_app_state);
+ APPEND_OPT(m_fb_abort);
+ APPEND_OPT(m_fb_thread);
+ APPEND_OPT(m_fb_logcat);
+ APPEND_OPT(m_fb_all);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectProcessMinidumpDump() override = default;
+
+ Options *GetOptions() override { return &m_option_group; }
+
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ const size_t argc = command.GetArgumentCount();
+ if (argc > 0) {
+ result.AppendErrorWithFormat("'%s' take no arguments, only options",
+ m_cmd_name.c_str());
+ return;
+ }
+ SetDefaultOptionsIfNoneAreSet();
+
+ ProcessMinidump *process = static_cast<ProcessMinidump *>(
+ m_interpreter.GetExecutionContext().GetProcessPtr());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ Stream &s = result.GetOutputStream();
+ MinidumpParser &minidump = *process->m_minidump_parser;
+ if (DumpDirectory()) {
+ s.Printf("RVA SIZE TYPE StreamType\n");
+ s.Printf("---------- ---------- ---------- --------------------------\n");
+ for (const auto &stream_desc : minidump.GetMinidumpFile().streams())
+ s.Printf(
+ "0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)stream_desc.Location.RVA,
+ (uint32_t)stream_desc.Location.DataSize,
+ (unsigned)(StreamType)stream_desc.Type,
+ MinidumpParser::GetStreamTypeAsString(stream_desc.Type).data());
+ s.Printf("\n");
+ }
+ auto DumpTextStream = [&](StreamType stream_type,
+ llvm::StringRef label) -> void {
+ auto bytes = minidump.GetStream(stream_type);
+ if (!bytes.empty()) {
+ if (label.empty())
+ label = MinidumpParser::GetStreamTypeAsString(stream_type);
+ s.Printf("%s:\n%s\n\n", label.data(), bytes.data());
+ }
+ };
+ auto DumpBinaryStream = [&](StreamType stream_type,
+ llvm::StringRef label) -> void {
+ auto bytes = minidump.GetStream(stream_type);
+ if (!bytes.empty()) {
+ if (label.empty())
+ label = MinidumpParser::GetStreamTypeAsString(stream_type);
+ s.Printf("%s:\n", label.data());
+ DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
+ process->GetAddressByteSize());
+ DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1,
+ bytes.size(), 16, 0, 0, 0);
+ s.Printf("\n\n");
+ }
+ };
+
+ if (DumpLinuxCPUInfo())
+ DumpTextStream(StreamType::LinuxCPUInfo, "/proc/cpuinfo");
+ if (DumpLinuxProcStatus())
+ DumpTextStream(StreamType::LinuxProcStatus, "/proc/PID/status");
+ if (DumpLinuxLSBRelease())
+ DumpTextStream(StreamType::LinuxLSBRelease, "/etc/lsb-release");
+ if (DumpLinuxCMDLine())
+ DumpTextStream(StreamType::LinuxCMDLine, "/proc/PID/cmdline");
+ if (DumpLinuxEnviron())
+ DumpTextStream(StreamType::LinuxEnviron, "/proc/PID/environ");
+ if (DumpLinuxAuxv())
+ DumpBinaryStream(StreamType::LinuxAuxv, "/proc/PID/auxv");
+ if (DumpLinuxMaps())
+ DumpTextStream(StreamType::LinuxMaps, "/proc/PID/maps");
+ if (DumpLinuxProcStat())
+ DumpTextStream(StreamType::LinuxProcStat, "/proc/PID/stat");
+ if (DumpLinuxProcUptime())
+ DumpTextStream(StreamType::LinuxProcUptime, "uptime");
+ if (DumpLinuxProcFD())
+ DumpTextStream(StreamType::LinuxProcFD, "/proc/PID/fd");
+ if (DumpFacebookAppData())
+ DumpTextStream(StreamType::FacebookAppCustomData,
+ "Facebook App Data");
+ if (DumpFacebookBuildID()) {
+ auto bytes = minidump.GetStream(StreamType::FacebookBuildID);
+ if (bytes.size() >= 4) {
+ DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
+ process->GetAddressByteSize());
+ lldb::offset_t offset = 0;
+ uint32_t build_id = data.GetU32(&offset);
+ s.Printf("Facebook Build ID:\n");
+ s.Printf("%u\n", build_id);
+ s.Printf("\n");
+ }
+ }
+ if (DumpFacebookVersionName())
+ DumpTextStream(StreamType::FacebookAppVersionName,
+ "Facebook Version String");
+ if (DumpFacebookJavaStack())
+ DumpTextStream(StreamType::FacebookJavaStack,
+ "Facebook Java Stack");
+ if (DumpFacebookDalvikInfo())
+ DumpTextStream(StreamType::FacebookDalvikInfo,
+ "Facebook Dalvik Info");
+ if (DumpFacebookUnwindSymbols())
+ DumpBinaryStream(StreamType::FacebookUnwindSymbols,
+ "Facebook Unwind Symbols Bytes");
+ if (DumpFacebookErrorLog())
+ DumpTextStream(StreamType::FacebookDumpErrorLog,
+ "Facebook Error Log");
+ if (DumpFacebookAppStateLog())
+ DumpTextStream(StreamType::FacebookAppStateLog,
+ "Faceook Application State Log");
+ if (DumpFacebookAbortReason())
+ DumpTextStream(StreamType::FacebookAbortReason,
+ "Facebook Abort Reason");
+ if (DumpFacebookThreadName())
+ DumpTextStream(StreamType::FacebookThreadName,
+ "Facebook Thread Name");
+ if (DumpFacebookLogcat())
+ DumpTextStream(StreamType::FacebookLogcat, "Facebook Logcat");
+ }
+};
+
+class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword {
+public:
+ CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "process plugin",
+ "Commands for operating on a ProcessMinidump process.",
+ "process plugin <subcommand> [<subcommand-options>]") {
+ LoadSubCommand("dump",
+ CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter)));
+ }
+
+ ~CommandObjectMultiwordProcessMinidump() override = default;
+};
+
+CommandObject *ProcessMinidump::GetPluginCommandObject() {
+ if (!m_command_sp)
+ m_command_sp = std::make_shared<CommandObjectMultiwordProcessMinidump>(
+ GetTarget().GetDebugger().GetCommandInterpreter());
+ return m_command_sp.get();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
new file mode 100644
index 000000000000..3f3123a0a8b5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
@@ -0,0 +1,123 @@
+//===-- ProcessMinidump.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_PROCESSMINIDUMP_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_PROCESSMINIDUMP_H
+
+#include "MinidumpParser.h"
+#include "MinidumpTypes.h"
+
+#include "lldb/Target/PostMortemProcess.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <optional>
+
+namespace lldb_private {
+
+namespace minidump {
+
+class ProcessMinidump : public PostMortemProcess {
+public:
+ static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file_path,
+ bool can_connect);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "minidump"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ ProcessMinidump(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
+ const FileSpec &core_file, lldb::DataBufferSP code_data);
+
+ ~ProcessMinidump() override;
+
+ bool CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) override;
+
+ CommandObject *GetPluginCommandObject() override;
+
+ Status DoLoadCore() override;
+
+ DynamicLoader *GetDynamicLoader() override { return nullptr; }
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ SystemRuntime *GetSystemRuntime() override { return nullptr; }
+
+ Status DoDestroy() override;
+
+ void RefreshStateAfterStop() override;
+
+ bool IsAlive() override;
+
+ bool WarnBeforeDetach() const override;
+
+ size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) override;
+
+ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) override;
+
+ ArchSpec GetArchitecture();
+
+ Status GetMemoryRegions(
+ lldb_private::MemoryRegionInfos &region_list) override;
+
+ bool GetProcessInfo(ProcessInstanceInfo &info) override;
+
+ Status WillResume() override {
+ Status error;
+ error.SetErrorStringWithFormatv(
+ "error: {0} does not support resuming processes", GetPluginName());
+ return error;
+ }
+
+ std::optional<MinidumpParser> m_minidump_parser;
+
+protected:
+ void Clear();
+
+ bool DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override;
+
+ Status DoGetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
+
+ void ReadModuleList();
+
+ lldb::ModuleSP GetOrCreateModule(lldb_private::UUID minidump_uuid,
+ llvm::StringRef name,
+ lldb_private::ModuleSpec module_spec);
+
+ JITLoaderList &GetJITLoaders() override;
+
+private:
+ lldb::DataBufferSP m_core_data;
+ llvm::ArrayRef<minidump::Thread> m_thread_list;
+ const minidump::ExceptionStream *m_active_exception;
+ lldb::CommandObjectSP m_command_sp;
+ bool m_is_wow64;
+ std::optional<MemoryRegionInfos> m_memory_regions;
+
+ void BuildMemoryRegions();
+};
+
+} // namespace minidump
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_PROCESSMINIDUMP_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp
new file mode 100644
index 000000000000..0004d5d8d07e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp
@@ -0,0 +1,550 @@
+//===-- RegisterContextMinidump_ARM.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMinidump_ARM.h"
+
+#include "Utility/ARM_DWARF_Registers.h"
+#include "Utility/ARM_ehframe_Registers.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-enumerations.h"
+
+// C includes
+#include <cassert>
+
+// C++ includes
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace minidump;
+
+#define INV LLDB_INVALID_REGNUM
+#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM::Context, r))
+
+#define DEF_R(i) \
+ { \
+ "r" #i, nullptr, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \
+ {ehframe_r##i, dwarf_r##i, INV, INV, reg_r##i}, nullptr, nullptr, \
+ nullptr, \
+ }
+
+#define DEF_R_ARG(i, n) \
+ { \
+ "r" #i, "arg" #n, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \
+ {ehframe_r##i, dwarf_r##i, LLDB_REGNUM_GENERIC_ARG1 + i, INV, \
+ reg_r##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_D(i) \
+ { \
+ "d" #i, nullptr, 8, OFFSET(d) + i * 8, eEncodingVector, \
+ eFormatVectorOfUInt8, {dwarf_d##i, dwarf_d##i, INV, INV, reg_d##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_S(i) \
+ { \
+ "s" #i, nullptr, 4, OFFSET(s) + i * 4, eEncodingIEEE754, eFormatFloat, \
+ {dwarf_s##i, dwarf_s##i, INV, INV, reg_s##i}, nullptr, nullptr, \
+ nullptr, \
+ }
+
+#define DEF_Q(i) \
+ { \
+ "q" #i, nullptr, 16, OFFSET(q) + i * 16, eEncodingVector, \
+ eFormatVectorOfUInt8, {dwarf_q##i, dwarf_q##i, INV, INV, reg_q##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+// Zero based LLDB register numbers for this register context
+enum {
+ // General Purpose Registers
+ reg_r0,
+ reg_r1,
+ reg_r2,
+ reg_r3,
+ reg_r4,
+ reg_r5,
+ reg_r6,
+ reg_r7,
+ reg_r8,
+ reg_r9,
+ reg_r10,
+ reg_r11,
+ reg_r12,
+ reg_sp,
+ reg_lr,
+ reg_pc,
+ reg_cpsr,
+ // Floating Point Registers
+ reg_fpscr,
+ reg_d0,
+ reg_d1,
+ reg_d2,
+ reg_d3,
+ reg_d4,
+ reg_d5,
+ reg_d6,
+ reg_d7,
+ reg_d8,
+ reg_d9,
+ reg_d10,
+ reg_d11,
+ reg_d12,
+ reg_d13,
+ reg_d14,
+ reg_d15,
+ reg_d16,
+ reg_d17,
+ reg_d18,
+ reg_d19,
+ reg_d20,
+ reg_d21,
+ reg_d22,
+ reg_d23,
+ reg_d24,
+ reg_d25,
+ reg_d26,
+ reg_d27,
+ reg_d28,
+ reg_d29,
+ reg_d30,
+ reg_d31,
+ reg_s0,
+ reg_s1,
+ reg_s2,
+ reg_s3,
+ reg_s4,
+ reg_s5,
+ reg_s6,
+ reg_s7,
+ reg_s8,
+ reg_s9,
+ reg_s10,
+ reg_s11,
+ reg_s12,
+ reg_s13,
+ reg_s14,
+ reg_s15,
+ reg_s16,
+ reg_s17,
+ reg_s18,
+ reg_s19,
+ reg_s20,
+ reg_s21,
+ reg_s22,
+ reg_s23,
+ reg_s24,
+ reg_s25,
+ reg_s26,
+ reg_s27,
+ reg_s28,
+ reg_s29,
+ reg_s30,
+ reg_s31,
+ reg_q0,
+ reg_q1,
+ reg_q2,
+ reg_q3,
+ reg_q4,
+ reg_q5,
+ reg_q6,
+ reg_q7,
+ reg_q8,
+ reg_q9,
+ reg_q10,
+ reg_q11,
+ reg_q12,
+ reg_q13,
+ reg_q14,
+ reg_q15,
+ k_num_regs
+};
+
+static RegisterInfo g_reg_info_apple_fp = {
+ "fp",
+ "r7",
+ 4,
+ OFFSET(r) + 7 * 4,
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, INV, reg_r7},
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+static RegisterInfo g_reg_info_fp = {
+ "fp",
+ "r11",
+ 4,
+ OFFSET(r) + 11 * 4,
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, INV, reg_r11},
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+// Register info definitions for this register context
+static RegisterInfo g_reg_infos[] = {
+ DEF_R_ARG(0, 1),
+ DEF_R_ARG(1, 2),
+ DEF_R_ARG(2, 3),
+ DEF_R_ARG(3, 4),
+ DEF_R(4),
+ DEF_R(5),
+ DEF_R(6),
+ DEF_R(7),
+ DEF_R(8),
+ DEF_R(9),
+ DEF_R(10),
+ DEF_R(11),
+ DEF_R(12),
+ {"sp",
+ "r13",
+ 4,
+ OFFSET(r) + 13 * 4,
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, INV, reg_sp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"lr",
+ "r14",
+ 4,
+ OFFSET(r) + 14 * 4,
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, INV, reg_lr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"pc",
+ "r15",
+ 4,
+ OFFSET(r) + 15 * 4,
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"cpsr",
+ "psr",
+ 4,
+ OFFSET(cpsr),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"fpscr",
+ nullptr,
+ 8,
+ OFFSET(fpscr),
+ eEncodingUint,
+ eFormatHex,
+ {INV, INV, INV, INV, reg_fpscr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ DEF_D(0),
+ DEF_D(1),
+ DEF_D(2),
+ DEF_D(3),
+ DEF_D(4),
+ DEF_D(5),
+ DEF_D(6),
+ DEF_D(7),
+ DEF_D(8),
+ DEF_D(9),
+ DEF_D(10),
+ DEF_D(11),
+ DEF_D(12),
+ DEF_D(13),
+ DEF_D(14),
+ DEF_D(15),
+ DEF_D(16),
+ DEF_D(17),
+ DEF_D(18),
+ DEF_D(19),
+ DEF_D(20),
+ DEF_D(21),
+ DEF_D(22),
+ DEF_D(23),
+ DEF_D(24),
+ DEF_D(25),
+ DEF_D(26),
+ DEF_D(27),
+ DEF_D(28),
+ DEF_D(29),
+ DEF_D(30),
+ DEF_D(31),
+ DEF_S(0),
+ DEF_S(1),
+ DEF_S(2),
+ DEF_S(3),
+ DEF_S(4),
+ DEF_S(5),
+ DEF_S(6),
+ DEF_S(7),
+ DEF_S(8),
+ DEF_S(9),
+ DEF_S(10),
+ DEF_S(11),
+ DEF_S(12),
+ DEF_S(13),
+ DEF_S(14),
+ DEF_S(15),
+ DEF_S(16),
+ DEF_S(17),
+ DEF_S(18),
+ DEF_S(19),
+ DEF_S(20),
+ DEF_S(21),
+ DEF_S(22),
+ DEF_S(23),
+ DEF_S(24),
+ DEF_S(25),
+ DEF_S(26),
+ DEF_S(27),
+ DEF_S(28),
+ DEF_S(29),
+ DEF_S(30),
+ DEF_S(31),
+ DEF_Q(0),
+ DEF_Q(1),
+ DEF_Q(2),
+ DEF_Q(3),
+ DEF_Q(4),
+ DEF_Q(5),
+ DEF_Q(6),
+ DEF_Q(7),
+ DEF_Q(8),
+ DEF_Q(9),
+ DEF_Q(10),
+ DEF_Q(11),
+ DEF_Q(12),
+ DEF_Q(13),
+ DEF_Q(14),
+ DEF_Q(15)};
+
+constexpr size_t k_num_reg_infos = std::size(g_reg_infos);
+
+// ARM general purpose registers.
+const uint32_t g_gpr_regnums[] = {
+ reg_r0,
+ reg_r1,
+ reg_r2,
+ reg_r3,
+ reg_r4,
+ reg_r5,
+ reg_r6,
+ reg_r7,
+ reg_r8,
+ reg_r9,
+ reg_r10,
+ reg_r11,
+ reg_r12,
+ reg_sp,
+ reg_lr,
+ reg_pc,
+ reg_cpsr,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+const uint32_t g_fpu_regnums[] = {
+ reg_fpscr,
+ reg_d0,
+ reg_d1,
+ reg_d2,
+ reg_d3,
+ reg_d4,
+ reg_d5,
+ reg_d6,
+ reg_d7,
+ reg_d8,
+ reg_d9,
+ reg_d10,
+ reg_d11,
+ reg_d12,
+ reg_d13,
+ reg_d14,
+ reg_d15,
+ reg_d16,
+ reg_d17,
+ reg_d18,
+ reg_d19,
+ reg_d20,
+ reg_d21,
+ reg_d22,
+ reg_d23,
+ reg_d24,
+ reg_d25,
+ reg_d26,
+ reg_d27,
+ reg_d28,
+ reg_d29,
+ reg_d30,
+ reg_d31,
+ reg_s0,
+ reg_s1,
+ reg_s2,
+ reg_s3,
+ reg_s4,
+ reg_s5,
+ reg_s6,
+ reg_s7,
+ reg_s8,
+ reg_s9,
+ reg_s10,
+ reg_s11,
+ reg_s12,
+ reg_s13,
+ reg_s14,
+ reg_s15,
+ reg_s16,
+ reg_s17,
+ reg_s18,
+ reg_s19,
+ reg_s20,
+ reg_s21,
+ reg_s22,
+ reg_s23,
+ reg_s24,
+ reg_s25,
+ reg_s26,
+ reg_s27,
+ reg_s28,
+ reg_s29,
+ reg_s30,
+ reg_s31,
+ reg_q0,
+ reg_q1,
+ reg_q2,
+ reg_q3,
+ reg_q4,
+ reg_q5,
+ reg_q6,
+ reg_q7,
+ reg_q8,
+ reg_q9,
+ reg_q10,
+ reg_q11,
+ reg_q12,
+ reg_q13,
+ reg_q14,
+ reg_q15,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+// Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1
+constexpr size_t k_num_gpr_regs = std::size(g_gpr_regnums) - 1;
+constexpr size_t k_num_fpu_regs = std::size(g_fpu_regnums) - 1;
+
+static RegisterSet g_reg_sets[] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums},
+ {"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums},
+};
+
+constexpr size_t k_num_reg_sets = std::size(g_reg_sets);
+
+RegisterContextMinidump_ARM::RegisterContextMinidump_ARM(
+ lldb_private::Thread &thread, const DataExtractor &data, bool apple)
+ : RegisterContext(thread, 0), m_apple(apple) {
+ lldb::offset_t offset = 0;
+ m_regs.context_flags = data.GetU32(&offset);
+ for (unsigned i = 0; i < std::size(m_regs.r); ++i)
+ m_regs.r[i] = data.GetU32(&offset);
+ m_regs.cpsr = data.GetU32(&offset);
+ m_regs.fpscr = data.GetU64(&offset);
+ for (unsigned i = 0; i < std::size(m_regs.d); ++i)
+ m_regs.d[i] = data.GetU64(&offset);
+ lldbassert(k_num_regs == k_num_reg_infos);
+}
+
+size_t RegisterContextMinidump_ARM::GetRegisterCountStatic() {
+ return k_num_regs;
+}
+
+// Used for unit testing so we can verify register info is filled in for
+// all register flavors (DWARF, EH Frame, generic, etc).
+size_t RegisterContextMinidump_ARM::GetRegisterCount() {
+ return GetRegisterCountStatic();
+}
+
+// Used for unit testing so we can verify register info is filled in.
+const RegisterInfo *
+RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(size_t reg,
+ bool apple) {
+ if (reg < k_num_reg_infos) {
+ if (apple) {
+ if (reg == reg_r7)
+ return &g_reg_info_apple_fp;
+ } else {
+ if (reg == reg_r11)
+ return &g_reg_info_fp;
+ }
+ return &g_reg_infos[reg];
+ }
+ return nullptr;
+}
+
+const RegisterInfo *
+RegisterContextMinidump_ARM::GetRegisterInfoAtIndex(size_t reg) {
+ return GetRegisterInfoAtIndexStatic(reg, m_apple);
+}
+
+size_t RegisterContextMinidump_ARM::GetRegisterSetCount() {
+ return k_num_reg_sets;
+}
+
+const RegisterSet *RegisterContextMinidump_ARM::GetRegisterSet(size_t set) {
+ if (set < k_num_reg_sets)
+ return &g_reg_sets[set];
+ return nullptr;
+}
+
+const char *RegisterContextMinidump_ARM::GetRegisterName(unsigned reg) {
+ if (reg < k_num_reg_infos)
+ return g_reg_infos[reg].name;
+ return nullptr;
+}
+
+bool RegisterContextMinidump_ARM::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status error;
+ reg_value.SetFromMemoryData(
+ *reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset,
+ reg_info->byte_size, lldb::eByteOrderLittle, error);
+ return error.Success();
+}
+
+bool RegisterContextMinidump_ARM::WriteRegister(const RegisterInfo *,
+ const RegisterValue &) {
+ return false;
+}
+
+uint32_t RegisterContextMinidump_ARM::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ for (size_t i = 0; i < k_num_regs; ++i) {
+ if (g_reg_infos[i].kinds[kind] == num)
+ return i;
+ }
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h
new file mode 100644
index 000000000000..857f9c0a3767
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h
@@ -0,0 +1,98 @@
+//===-- RegisterContextMinidump_ARM.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM_H
+
+#include "MinidumpTypes.h"
+
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+
+#include "lldb/Target/RegisterContext.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+
+// C includes
+// C++ includes
+
+namespace lldb_private {
+
+namespace minidump {
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+class RegisterContextMinidump_ARM : public lldb_private::RegisterContext {
+public:
+ RegisterContextMinidump_ARM(lldb_private::Thread &thread,
+ const DataExtractor &data, bool apple);
+
+ ~RegisterContextMinidump_ARM() override = default;
+
+ void InvalidateAllRegisters() override {
+ // Do nothing... registers are always valid...
+ }
+
+ // Used for unit testing.
+ static size_t GetRegisterCountStatic();
+ // Used for unit testing.
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndexStatic(size_t reg, bool apple);
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+ bool ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ bool WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ // Reference: see breakpad/crashpad source
+ struct QRegValue {
+ uint64_t lo;
+ uint64_t hi;
+ };
+
+ struct Context {
+ uint32_t context_flags;
+ uint32_t r[16];
+ uint32_t cpsr;
+ uint64_t fpscr;
+ union {
+ uint64_t d[32];
+ uint32_t s[32];
+ QRegValue q[16];
+ };
+ uint32_t extra[8];
+ };
+
+protected:
+ enum class Flags : uint32_t {
+ ARM_Flag = 0x40000000,
+ Integer = ARM_Flag | 0x00000002,
+ FloatingPoint = ARM_Flag | 0x00000004,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint)
+ };
+ Context m_regs;
+ const bool m_apple; // True if this is an Apple ARM where FP is R7
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp
new file mode 100644
index 000000000000..a0476c962070
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp
@@ -0,0 +1,833 @@
+//===-- RegisterContextMinidump_ARM64.cpp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMinidump_ARM64.h"
+
+#include "Utility/ARM64_DWARF_Registers.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/lldb-enumerations.h"
+
+// C includes
+#include <cassert>
+
+// C++ includes
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace minidump;
+
+#define INV LLDB_INVALID_REGNUM
+#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM64::Context, r))
+
+#define DEF_X(i) \
+ { \
+ "x" #i, nullptr, 8, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \
+ {arm64_dwarf::x##i, arm64_dwarf::x##i, INV, INV, reg_x##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_W(i) \
+ { \
+ "w" #i, nullptr, 4, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \
+ {INV, INV, INV, INV, reg_w##i}, nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_X_ARG(i, n) \
+ { \
+ "x" #i, "arg" #n, 8, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \
+ {arm64_dwarf::x##i, arm64_dwarf::x##i, LLDB_REGNUM_GENERIC_ARG1 + i, \
+ INV, reg_x##i}, nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_V(i) \
+ { \
+ "v" #i, nullptr, 16, OFFSET(v) + i * 16, eEncodingVector, \
+ eFormatVectorOfUInt8, {arm64_dwarf::v##i, arm64_dwarf::v##i, INV, INV, \
+ reg_v##i}, nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_D(i) \
+ { \
+ "d" #i, nullptr, 8, OFFSET(v) + i * 16, eEncodingVector, \
+ eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_d##i}, nullptr, \
+ nullptr, nullptr, \
+ }
+
+#define DEF_S(i) \
+ { \
+ "s" #i, nullptr, 4, OFFSET(v) + i * 16, eEncodingVector, \
+ eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_s##i}, nullptr, \
+ nullptr, nullptr, \
+ }
+
+#define DEF_H(i) \
+ { \
+ "h" #i, nullptr, 2, OFFSET(v) + i * 16, eEncodingVector, \
+ eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_h##i}, nullptr, \
+ nullptr, nullptr, \
+ }
+
+// Zero based LLDB register numbers for this register context
+enum {
+ // General Purpose Registers
+ reg_x0 = 0,
+ reg_x1,
+ reg_x2,
+ reg_x3,
+ reg_x4,
+ reg_x5,
+ reg_x6,
+ reg_x7,
+ reg_x8,
+ reg_x9,
+ reg_x10,
+ reg_x11,
+ reg_x12,
+ reg_x13,
+ reg_x14,
+ reg_x15,
+ reg_x16,
+ reg_x17,
+ reg_x18,
+ reg_x19,
+ reg_x20,
+ reg_x21,
+ reg_x22,
+ reg_x23,
+ reg_x24,
+ reg_x25,
+ reg_x26,
+ reg_x27,
+ reg_x28,
+ reg_fp,
+ reg_lr,
+ reg_sp,
+ reg_pc,
+ reg_w0,
+ reg_w1,
+ reg_w2,
+ reg_w3,
+ reg_w4,
+ reg_w5,
+ reg_w6,
+ reg_w7,
+ reg_w8,
+ reg_w9,
+ reg_w10,
+ reg_w11,
+ reg_w12,
+ reg_w13,
+ reg_w14,
+ reg_w15,
+ reg_w16,
+ reg_w17,
+ reg_w18,
+ reg_w19,
+ reg_w20,
+ reg_w21,
+ reg_w22,
+ reg_w23,
+ reg_w24,
+ reg_w25,
+ reg_w26,
+ reg_w27,
+ reg_w28,
+ reg_w29,
+ reg_w30,
+ reg_w31,
+ reg_cpsr,
+ // Floating Point Registers
+ reg_fpsr,
+ reg_fpcr,
+ reg_v0,
+ reg_v1,
+ reg_v2,
+ reg_v3,
+ reg_v4,
+ reg_v5,
+ reg_v6,
+ reg_v7,
+ reg_v8,
+ reg_v9,
+ reg_v10,
+ reg_v11,
+ reg_v12,
+ reg_v13,
+ reg_v14,
+ reg_v15,
+ reg_v16,
+ reg_v17,
+ reg_v18,
+ reg_v19,
+ reg_v20,
+ reg_v21,
+ reg_v22,
+ reg_v23,
+ reg_v24,
+ reg_v25,
+ reg_v26,
+ reg_v27,
+ reg_v28,
+ reg_v29,
+ reg_v30,
+ reg_v31,
+ reg_d0,
+ reg_d1,
+ reg_d2,
+ reg_d3,
+ reg_d4,
+ reg_d5,
+ reg_d6,
+ reg_d7,
+ reg_d8,
+ reg_d9,
+ reg_d10,
+ reg_d11,
+ reg_d12,
+ reg_d13,
+ reg_d14,
+ reg_d15,
+ reg_d16,
+ reg_d17,
+ reg_d18,
+ reg_d19,
+ reg_d20,
+ reg_d21,
+ reg_d22,
+ reg_d23,
+ reg_d24,
+ reg_d25,
+ reg_d26,
+ reg_d27,
+ reg_d28,
+ reg_d29,
+ reg_d30,
+ reg_d31,
+ reg_s0,
+ reg_s1,
+ reg_s2,
+ reg_s3,
+ reg_s4,
+ reg_s5,
+ reg_s6,
+ reg_s7,
+ reg_s8,
+ reg_s9,
+ reg_s10,
+ reg_s11,
+ reg_s12,
+ reg_s13,
+ reg_s14,
+ reg_s15,
+ reg_s16,
+ reg_s17,
+ reg_s18,
+ reg_s19,
+ reg_s20,
+ reg_s21,
+ reg_s22,
+ reg_s23,
+ reg_s24,
+ reg_s25,
+ reg_s26,
+ reg_s27,
+ reg_s28,
+ reg_s29,
+ reg_s30,
+ reg_s31,
+ reg_h0,
+ reg_h1,
+ reg_h2,
+ reg_h3,
+ reg_h4,
+ reg_h5,
+ reg_h6,
+ reg_h7,
+ reg_h8,
+ reg_h9,
+ reg_h10,
+ reg_h11,
+ reg_h12,
+ reg_h13,
+ reg_h14,
+ reg_h15,
+ reg_h16,
+ reg_h17,
+ reg_h18,
+ reg_h19,
+ reg_h20,
+ reg_h21,
+ reg_h22,
+ reg_h23,
+ reg_h24,
+ reg_h25,
+ reg_h26,
+ reg_h27,
+ reg_h28,
+ reg_h29,
+ reg_h30,
+ reg_h31,
+ k_num_regs
+};
+
+// Register info definitions for this register context
+static RegisterInfo g_reg_infos[] = {
+ DEF_X_ARG(0, 1),
+ DEF_X_ARG(1, 2),
+ DEF_X_ARG(2, 3),
+ DEF_X_ARG(3, 4),
+ DEF_X_ARG(4, 5),
+ DEF_X_ARG(5, 6),
+ DEF_X_ARG(6, 7),
+ DEF_X_ARG(7, 8),
+ DEF_X(8),
+ DEF_X(9),
+ DEF_X(10),
+ DEF_X(11),
+ DEF_X(12),
+ DEF_X(13),
+ DEF_X(14),
+ DEF_X(15),
+ DEF_X(16),
+ DEF_X(17),
+ DEF_X(18),
+ DEF_X(19),
+ DEF_X(20),
+ DEF_X(21),
+ DEF_X(22),
+ DEF_X(23),
+ DEF_X(24),
+ DEF_X(25),
+ DEF_X(26),
+ DEF_X(27),
+ DEF_X(28),
+ {"fp",
+ "x29",
+ 8,
+ OFFSET(x) + 29 * 8,
+ eEncodingUint,
+ eFormatHex,
+ {arm64_dwarf::x29, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, INV, reg_fp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"lr",
+ "x30",
+ 8,
+ OFFSET(x) + 30 * 8,
+ eEncodingUint,
+ eFormatHex,
+ {arm64_dwarf::x30, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, INV, reg_lr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"sp",
+ "x31",
+ 8,
+ OFFSET(x) + 31 * 8,
+ eEncodingUint,
+ eFormatHex,
+ {arm64_dwarf::x31, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, INV, reg_sp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"pc",
+ nullptr,
+ 8,
+ OFFSET(pc),
+ eEncodingUint,
+ eFormatHex,
+ {arm64_dwarf::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ // w0 - w31
+ DEF_W(0),
+ DEF_W(1),
+ DEF_W(2),
+ DEF_W(3),
+ DEF_W(4),
+ DEF_W(5),
+ DEF_W(6),
+ DEF_W(7),
+ DEF_W(8),
+ DEF_W(9),
+ DEF_W(10),
+ DEF_W(11),
+ DEF_W(12),
+ DEF_W(13),
+ DEF_W(14),
+ DEF_W(15),
+ DEF_W(16),
+ DEF_W(17),
+ DEF_W(18),
+ DEF_W(19),
+ DEF_W(20),
+ DEF_W(21),
+ DEF_W(22),
+ DEF_W(23),
+ DEF_W(24),
+ DEF_W(25),
+ DEF_W(26),
+ DEF_W(27),
+ DEF_W(28),
+ DEF_W(29),
+ DEF_W(30),
+ DEF_W(31),
+ {"cpsr",
+ "psr",
+ 4,
+ OFFSET(cpsr),
+ eEncodingUint,
+ eFormatHex,
+ {INV, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"fpsr",
+ nullptr,
+ 4,
+ OFFSET(fpsr),
+ eEncodingUint,
+ eFormatHex,
+ {INV, INV, INV, INV, reg_fpsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"fpcr",
+ nullptr,
+ 4,
+ OFFSET(fpcr),
+ eEncodingUint,
+ eFormatHex,
+ {INV, INV, INV, INV, reg_fpcr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ // v0 - v31
+ DEF_V(0),
+ DEF_V(1),
+ DEF_V(2),
+ DEF_V(3),
+ DEF_V(4),
+ DEF_V(5),
+ DEF_V(6),
+ DEF_V(7),
+ DEF_V(8),
+ DEF_V(9),
+ DEF_V(10),
+ DEF_V(11),
+ DEF_V(12),
+ DEF_V(13),
+ DEF_V(14),
+ DEF_V(15),
+ DEF_V(16),
+ DEF_V(17),
+ DEF_V(18),
+ DEF_V(19),
+ DEF_V(20),
+ DEF_V(21),
+ DEF_V(22),
+ DEF_V(23),
+ DEF_V(24),
+ DEF_V(25),
+ DEF_V(26),
+ DEF_V(27),
+ DEF_V(28),
+ DEF_V(29),
+ DEF_V(30),
+ DEF_V(31),
+ // d0 - d31
+ DEF_D(0),
+ DEF_D(1),
+ DEF_D(2),
+ DEF_D(3),
+ DEF_D(4),
+ DEF_D(5),
+ DEF_D(6),
+ DEF_D(7),
+ DEF_D(8),
+ DEF_D(9),
+ DEF_D(10),
+ DEF_D(11),
+ DEF_D(12),
+ DEF_D(13),
+ DEF_D(14),
+ DEF_D(15),
+ DEF_D(16),
+ DEF_D(17),
+ DEF_D(18),
+ DEF_D(19),
+ DEF_D(20),
+ DEF_D(21),
+ DEF_D(22),
+ DEF_D(23),
+ DEF_D(24),
+ DEF_D(25),
+ DEF_D(26),
+ DEF_D(27),
+ DEF_D(28),
+ DEF_D(29),
+ DEF_D(30),
+ DEF_D(31),
+ // s0 - s31
+ DEF_S(0),
+ DEF_S(1),
+ DEF_S(2),
+ DEF_S(3),
+ DEF_S(4),
+ DEF_S(5),
+ DEF_S(6),
+ DEF_S(7),
+ DEF_S(8),
+ DEF_S(9),
+ DEF_S(10),
+ DEF_S(11),
+ DEF_S(12),
+ DEF_S(13),
+ DEF_S(14),
+ DEF_S(15),
+ DEF_S(16),
+ DEF_S(17),
+ DEF_S(18),
+ DEF_S(19),
+ DEF_S(20),
+ DEF_S(21),
+ DEF_S(22),
+ DEF_S(23),
+ DEF_S(24),
+ DEF_S(25),
+ DEF_S(26),
+ DEF_S(27),
+ DEF_S(28),
+ DEF_S(29),
+ DEF_S(30),
+ DEF_S(31),
+ // h0 - h31
+ DEF_H(0),
+ DEF_H(1),
+ DEF_H(2),
+ DEF_H(3),
+ DEF_H(4),
+ DEF_H(5),
+ DEF_H(6),
+ DEF_H(7),
+ DEF_H(8),
+ DEF_H(9),
+ DEF_H(10),
+ DEF_H(11),
+ DEF_H(12),
+ DEF_H(13),
+ DEF_H(14),
+ DEF_H(15),
+ DEF_H(16),
+ DEF_H(17),
+ DEF_H(18),
+ DEF_H(19),
+ DEF_H(20),
+ DEF_H(21),
+ DEF_H(22),
+ DEF_H(23),
+ DEF_H(24),
+ DEF_H(25),
+ DEF_H(26),
+ DEF_H(27),
+ DEF_H(28),
+ DEF_H(29),
+ DEF_H(30),
+ DEF_H(31),
+};
+
+constexpr size_t k_num_reg_infos = std::size(g_reg_infos);
+
+// ARM64 general purpose registers.
+const uint32_t g_gpr_regnums[] = {
+ reg_x0,
+ reg_x1,
+ reg_x2,
+ reg_x3,
+ reg_x4,
+ reg_x5,
+ reg_x6,
+ reg_x7,
+ reg_x8,
+ reg_x9,
+ reg_x10,
+ reg_x11,
+ reg_x12,
+ reg_x13,
+ reg_x14,
+ reg_x15,
+ reg_x16,
+ reg_x17,
+ reg_x18,
+ reg_x19,
+ reg_x20,
+ reg_x21,
+ reg_x22,
+ reg_x23,
+ reg_x24,
+ reg_x25,
+ reg_x26,
+ reg_x27,
+ reg_x28,
+ reg_fp,
+ reg_lr,
+ reg_sp,
+ reg_w0,
+ reg_w1,
+ reg_w2,
+ reg_w3,
+ reg_w4,
+ reg_w5,
+ reg_w6,
+ reg_w7,
+ reg_w8,
+ reg_w9,
+ reg_w10,
+ reg_w11,
+ reg_w12,
+ reg_w13,
+ reg_w14,
+ reg_w15,
+ reg_w16,
+ reg_w17,
+ reg_w18,
+ reg_w19,
+ reg_w20,
+ reg_w21,
+ reg_w22,
+ reg_w23,
+ reg_w24,
+ reg_w25,
+ reg_w26,
+ reg_w27,
+ reg_w28,
+ reg_w29,
+ reg_w30,
+ reg_w31,
+ reg_pc,
+ reg_cpsr,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+const uint32_t g_fpu_regnums[] = {
+ reg_v0,
+ reg_v1,
+ reg_v2,
+ reg_v3,
+ reg_v4,
+ reg_v5,
+ reg_v6,
+ reg_v7,
+ reg_v8,
+ reg_v9,
+ reg_v10,
+ reg_v11,
+ reg_v12,
+ reg_v13,
+ reg_v14,
+ reg_v15,
+ reg_v16,
+ reg_v17,
+ reg_v18,
+ reg_v19,
+ reg_v20,
+ reg_v21,
+ reg_v22,
+ reg_v23,
+ reg_v24,
+ reg_v25,
+ reg_v26,
+ reg_v27,
+ reg_v28,
+ reg_v29,
+ reg_v30,
+ reg_v31,
+ reg_d0,
+ reg_d1,
+ reg_d2,
+ reg_d3,
+ reg_d4,
+ reg_d5,
+ reg_d6,
+ reg_d7,
+ reg_d8,
+ reg_d9,
+ reg_d10,
+ reg_d11,
+ reg_d12,
+ reg_d13,
+ reg_d14,
+ reg_d15,
+ reg_d16,
+ reg_d17,
+ reg_d18,
+ reg_d19,
+ reg_d20,
+ reg_d21,
+ reg_d22,
+ reg_d23,
+ reg_d24,
+ reg_d25,
+ reg_d26,
+ reg_d27,
+ reg_d28,
+ reg_d29,
+ reg_d30,
+ reg_d31,
+ reg_s0,
+ reg_s1,
+ reg_s2,
+ reg_s3,
+ reg_s4,
+ reg_s5,
+ reg_s6,
+ reg_s7,
+ reg_s8,
+ reg_s9,
+ reg_s10,
+ reg_s11,
+ reg_s12,
+ reg_s13,
+ reg_s14,
+ reg_s15,
+ reg_s16,
+ reg_s17,
+ reg_s18,
+ reg_s19,
+ reg_s20,
+ reg_s21,
+ reg_s22,
+ reg_s23,
+ reg_s24,
+ reg_s25,
+ reg_s26,
+ reg_s27,
+ reg_s28,
+ reg_s29,
+ reg_s30,
+ reg_s31,
+ reg_h0,
+ reg_h1,
+ reg_h2,
+ reg_h3,
+ reg_h4,
+ reg_h5,
+ reg_h6,
+ reg_h7,
+ reg_h8,
+ reg_h9,
+ reg_h10,
+ reg_h11,
+ reg_h12,
+ reg_h13,
+ reg_h14,
+ reg_h15,
+ reg_h16,
+ reg_h17,
+ reg_h18,
+ reg_h19,
+ reg_h20,
+ reg_h21,
+ reg_h22,
+ reg_h23,
+ reg_h24,
+ reg_h25,
+ reg_h26,
+ reg_h27,
+ reg_h28,
+ reg_h29,
+ reg_h30,
+ reg_h31,
+ reg_fpsr,
+ reg_fpcr,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+// Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1
+constexpr size_t k_num_gpr_regs = std::size(g_gpr_regnums) - 1;
+constexpr size_t k_num_fpu_regs = std::size(g_fpu_regnums) - 1;
+
+static RegisterSet g_reg_sets[] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums},
+ {"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums},
+};
+
+constexpr size_t k_num_reg_sets = std::size(g_reg_sets);
+
+RegisterContextMinidump_ARM64::RegisterContextMinidump_ARM64(
+ lldb_private::Thread &thread, const DataExtractor &data)
+ : RegisterContext(thread, 0) {
+ lldb::offset_t offset = 0;
+ m_regs.context_flags = data.GetU64(&offset);
+ for (unsigned i = 0; i < 32; ++i)
+ m_regs.x[i] = data.GetU64(&offset);
+ m_regs.pc = data.GetU64(&offset);
+ m_regs.cpsr = data.GetU32(&offset);
+ m_regs.fpsr = data.GetU32(&offset);
+ m_regs.fpcr = data.GetU32(&offset);
+ auto regs_data = data.GetData(&offset, sizeof(m_regs.v));
+ if (regs_data)
+ memcpy(m_regs.v, regs_data, sizeof(m_regs.v));
+ static_assert(k_num_regs == k_num_reg_infos);
+}
+size_t RegisterContextMinidump_ARM64::GetRegisterCount() { return k_num_regs; }
+
+const RegisterInfo *
+RegisterContextMinidump_ARM64::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < k_num_reg_infos)
+ return &g_reg_infos[reg];
+ return nullptr;
+}
+
+size_t RegisterContextMinidump_ARM64::GetRegisterSetCount() {
+ return k_num_reg_sets;
+}
+
+const RegisterSet *RegisterContextMinidump_ARM64::GetRegisterSet(size_t set) {
+ if (set < k_num_reg_sets)
+ return &g_reg_sets[set];
+ return nullptr;
+}
+
+const char *RegisterContextMinidump_ARM64::GetRegisterName(unsigned reg) {
+ if (reg < k_num_reg_infos)
+ return g_reg_infos[reg].name;
+ return nullptr;
+}
+
+bool RegisterContextMinidump_ARM64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status error;
+ reg_value.SetFromMemoryData(
+ *reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset,
+ reg_info->byte_size, lldb::eByteOrderLittle, error);
+ return error.Success();
+}
+
+bool RegisterContextMinidump_ARM64::WriteRegister(const RegisterInfo *,
+ const RegisterValue &) {
+ return false;
+}
+
+uint32_t RegisterContextMinidump_ARM64::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ for (size_t i = 0; i < k_num_regs; ++i) {
+ if (g_reg_infos[i].kinds[kind] == num)
+ return i;
+ }
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h
new file mode 100644
index 000000000000..58cf8d62fb86
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h
@@ -0,0 +1,83 @@
+//===-- RegisterContextMinidump_ARM64.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM64_H
+
+#include "MinidumpTypes.h"
+
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+
+// C includes
+// C++ includes
+
+namespace lldb_private {
+
+namespace minidump {
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+class RegisterContextMinidump_ARM64 : public lldb_private::RegisterContext {
+public:
+ RegisterContextMinidump_ARM64(lldb_private::Thread &thread,
+ const DataExtractor &data);
+
+ ~RegisterContextMinidump_ARM64() override = default;
+
+ void InvalidateAllRegisters() override {
+ // Do nothing... registers are always valid...
+ }
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+ bool ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ bool WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ // Reference: see breakpad/crashpad source
+ struct Context {
+ uint64_t context_flags;
+ uint64_t x[32];
+ uint64_t pc;
+ uint32_t cpsr;
+ uint32_t fpsr;
+ uint32_t fpcr;
+ uint8_t v[32 * 16]; // 32 128-bit floating point registers
+ };
+
+ enum class Flags : uint32_t {
+ ARM64_Flag = 0x80000000,
+ Integer = ARM64_Flag | 0x00000002,
+ FloatingPoint = ARM64_Flag | 0x00000004,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint)
+ };
+
+protected:
+ Context m_regs;
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp
new file mode 100644
index 000000000000..7681002c6fb8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp
@@ -0,0 +1,96 @@
+//===-- RegisterContextMinidump_x86_32.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMinidump_x86_32.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+
+// C includes
+// C++ includes
+
+using namespace lldb_private;
+using namespace minidump;
+
+static void writeRegister(const void *reg_src,
+ llvm::MutableArrayRef<uint8_t> reg_dest) {
+ memcpy(reg_dest.data(), reg_src, reg_dest.size());
+}
+
+lldb::DataBufferSP lldb_private::minidump::ConvertMinidumpContext_x86_32(
+ llvm::ArrayRef<uint8_t> source_data,
+ RegisterInfoInterface *target_reg_interface) {
+
+ const RegisterInfo *reg_info = target_reg_interface->GetRegisterInfo();
+
+ lldb::WritableDataBufferSP result_context_buf(
+ new DataBufferHeap(target_reg_interface->GetGPRSize(), 0));
+ uint8_t *result_base = result_context_buf->GetBytes();
+
+ if (source_data.size() < sizeof(MinidumpContext_x86_32))
+ return nullptr;
+
+ const MinidumpContext_x86_32 *context;
+ consumeObject(source_data, context);
+
+ const MinidumpContext_x86_32_Flags context_flags =
+ static_cast<MinidumpContext_x86_32_Flags>(
+ static_cast<uint32_t>(context->context_flags));
+ auto x86_32_Flag = MinidumpContext_x86_32_Flags::x86_32_Flag;
+ auto ControlFlag = MinidumpContext_x86_32_Flags::Control;
+ auto IntegerFlag = MinidumpContext_x86_32_Flags::Integer;
+ auto SegmentsFlag = MinidumpContext_x86_32_Flags::Segments;
+
+ if ((context_flags & x86_32_Flag) != x86_32_Flag) {
+ return nullptr;
+ }
+
+ if ((context_flags & ControlFlag) == ControlFlag) {
+ writeRegister(&context->ebp,
+ reg_info[lldb_ebp_i386].mutable_data(result_base));
+ writeRegister(&context->eip,
+ reg_info[lldb_eip_i386].mutable_data(result_base));
+ writeRegister(&context->cs,
+ reg_info[lldb_cs_i386].mutable_data(result_base));
+ writeRegister(&context->eflags,
+ reg_info[lldb_eflags_i386].mutable_data(result_base));
+ writeRegister(&context->esp,
+ reg_info[lldb_esp_i386].mutable_data(result_base));
+ writeRegister(&context->ss,
+ reg_info[lldb_ss_i386].mutable_data(result_base));
+ }
+
+ if ((context_flags & SegmentsFlag) == SegmentsFlag) {
+ writeRegister(&context->ds,
+ reg_info[lldb_ds_i386].mutable_data(result_base));
+ writeRegister(&context->es,
+ reg_info[lldb_es_i386].mutable_data(result_base));
+ writeRegister(&context->fs,
+ reg_info[lldb_fs_i386].mutable_data(result_base));
+ writeRegister(&context->gs,
+ reg_info[lldb_gs_i386].mutable_data(result_base));
+ }
+
+ if ((context_flags & IntegerFlag) == IntegerFlag) {
+ writeRegister(&context->eax,
+ reg_info[lldb_eax_i386].mutable_data(result_base));
+ writeRegister(&context->ecx,
+ reg_info[lldb_ecx_i386].mutable_data(result_base));
+ writeRegister(&context->edx,
+ reg_info[lldb_edx_i386].mutable_data(result_base));
+ writeRegister(&context->ebx,
+ reg_info[lldb_ebx_i386].mutable_data(result_base));
+ writeRegister(&context->esi,
+ reg_info[lldb_esi_i386].mutable_data(result_base));
+ writeRegister(&context->edi,
+ reg_info[lldb_edi_i386].mutable_data(result_base));
+ }
+
+ // TODO parse the floating point registers
+
+ return result_context_buf;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h
new file mode 100644
index 000000000000..4dffc4f9db0e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h
@@ -0,0 +1,135 @@
+//===-- RegisterContextMinidump_x86_32.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_32_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_32_H
+
+#include "MinidumpTypes.h"
+
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+#include "lldb/Target/RegisterContext.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/Support/Endian.h"
+
+// C includes
+// C++ includes
+
+namespace lldb_private {
+
+namespace minidump {
+
+// This function receives an ArrayRef pointing to the bytes of the Minidump
+// register context and returns a DataBuffer that's ordered by the offsets
+// specified in the RegisterInfoInterface argument
+// This way we can reuse the already existing register contexts
+lldb::DataBufferSP
+ConvertMinidumpContext_x86_32(llvm::ArrayRef<uint8_t> source_data,
+ RegisterInfoInterface *target_reg_interface);
+
+// Reference: see breakpad/crashpad source or WinNT.h
+struct MinidumpFloatingSaveAreaX86 {
+ llvm::support::ulittle32_t control_word;
+ llvm::support::ulittle32_t status_word;
+ llvm::support::ulittle32_t tag_word;
+ llvm::support::ulittle32_t error_offset;
+ llvm::support::ulittle32_t error_selector;
+ llvm::support::ulittle32_t data_offset;
+ llvm::support::ulittle32_t data_selector;
+
+ enum {
+ RegisterAreaSize = 80,
+ };
+ // register_area contains eight 80-bit (x87 "long double") quantities for
+ // floating-point registers %st0 (%mm0) through %st7 (%mm7).
+ uint8_t register_area[RegisterAreaSize];
+ llvm::support::ulittle32_t cr0_npx_state;
+};
+
+struct MinidumpContext_x86_32 {
+ // The context_flags field determines which parts
+ // of the structure are populated (have valid values)
+ llvm::support::ulittle32_t context_flags;
+
+ // The next 6 registers are included with
+ // MinidumpContext_x86_32_Flags::DebugRegisters
+ llvm::support::ulittle32_t dr0;
+ llvm::support::ulittle32_t dr1;
+ llvm::support::ulittle32_t dr2;
+ llvm::support::ulittle32_t dr3;
+ llvm::support::ulittle32_t dr6;
+ llvm::support::ulittle32_t dr7;
+
+ // The next field is included with
+ // MinidumpContext_x86_32_Flags::FloatingPoint
+ MinidumpFloatingSaveAreaX86 float_save;
+
+ // The next 4 registers are included with
+ // MinidumpContext_x86_32_Flags::Segments
+ llvm::support::ulittle32_t gs;
+ llvm::support::ulittle32_t fs;
+ llvm::support::ulittle32_t es;
+ llvm::support::ulittle32_t ds;
+
+ // The next 6 registers are included with
+ // MinidumpContext_x86_32_Flags::Integer
+ llvm::support::ulittle32_t edi;
+ llvm::support::ulittle32_t esi;
+ llvm::support::ulittle32_t ebx;
+ llvm::support::ulittle32_t edx;
+ llvm::support::ulittle32_t ecx;
+ llvm::support::ulittle32_t eax;
+
+ // The next 6 registers are included with
+ // MinidumpContext_x86_32_Flags::Control
+ llvm::support::ulittle32_t ebp;
+ llvm::support::ulittle32_t eip;
+ llvm::support::ulittle32_t cs; // WinNT.h says "must be sanitized"
+ llvm::support::ulittle32_t eflags; // WinNT.h says "must be sanitized"
+ llvm::support::ulittle32_t esp;
+ llvm::support::ulittle32_t ss;
+
+ // The next field is included with
+ // MinidumpContext_x86_32_Flags::ExtendedRegisters
+ // It contains vector (MMX/SSE) registers. It is laid out in the
+ // format used by the fxsave and fsrstor instructions, so it includes
+ // a copy of the x87 floating-point registers as well. See FXSAVE in
+ // "Intel Architecture Software Developer's Manual, Volume 2."
+ enum {
+ ExtendedRegistersSize = 512,
+ };
+ uint8_t extended_registers[ExtendedRegistersSize];
+};
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+// For context_flags. These values indicate the type of
+// context stored in the structure. The high 24 bits identify the CPU, the
+// low 8 bits identify the type of context saved.
+enum class MinidumpContext_x86_32_Flags : uint32_t {
+ x86_32_Flag = 0x00010000, // CONTEXT_i386, CONTEXT_i486
+ Control = x86_32_Flag | 0x00000001,
+ Integer = x86_32_Flag | 0x00000002,
+ Segments = x86_32_Flag | 0x00000004,
+ FloatingPoint = x86_32_Flag | 0x00000008,
+ DebugRegisters = x86_32_Flag | 0x00000010,
+ ExtendedRegisters = x86_32_Flag | 0x00000020,
+ XState = x86_32_Flag | 0x00000040,
+
+ Full = Control | Integer | Segments,
+ All = Full | FloatingPoint | DebugRegisters | ExtendedRegisters,
+
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ All)
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_32_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
new file mode 100644
index 000000000000..917140cab297
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
@@ -0,0 +1,110 @@
+//===-- RegisterContextMinidump_x86_64.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMinidump_x86_64.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+
+// C includes
+// C++ includes
+
+using namespace lldb_private;
+using namespace minidump;
+
+static llvm::MutableArrayRef<uint8_t> getDestRegister(uint8_t *context,
+ const RegisterInfo &reg) {
+ auto bytes = reg.mutable_data(context);
+
+ switch (reg.kinds[lldb::eRegisterKindLLDB]) {
+ case lldb_cs_x86_64:
+ case lldb_ds_x86_64:
+ case lldb_es_x86_64:
+ case lldb_fs_x86_64:
+ case lldb_gs_x86_64:
+ case lldb_ss_x86_64:
+ return bytes.take_front(2);
+ break;
+ case lldb_rflags_x86_64:
+ return bytes.take_front(4);
+ break;
+ default:
+ return bytes.take_front(8);
+ break;
+ }
+}
+
+static void writeRegister(const void *reg_src, uint8_t *context,
+ const RegisterInfo &reg) {
+ llvm::MutableArrayRef<uint8_t> reg_dest = getDestRegister(context, reg);
+ memcpy(reg_dest.data(), reg_src, reg_dest.size());
+}
+
+lldb::DataBufferSP lldb_private::minidump::ConvertMinidumpContext_x86_64(
+ llvm::ArrayRef<uint8_t> source_data,
+ RegisterInfoInterface *target_reg_interface) {
+
+ const RegisterInfo *reg_info = target_reg_interface->GetRegisterInfo();
+
+ lldb::WritableDataBufferSP result_context_buf(
+ new DataBufferHeap(target_reg_interface->GetGPRSize(), 0));
+ uint8_t *result_base = result_context_buf->GetBytes();
+
+ if (source_data.size() < sizeof(MinidumpContext_x86_64))
+ return nullptr;
+
+ const MinidumpContext_x86_64 *context;
+ consumeObject(source_data, context);
+
+ const MinidumpContext_x86_64_Flags context_flags =
+ static_cast<MinidumpContext_x86_64_Flags>(
+ static_cast<uint32_t>(context->context_flags));
+ auto x86_64_Flag = MinidumpContext_x86_64_Flags::x86_64_Flag;
+ auto ControlFlag = MinidumpContext_x86_64_Flags::Control;
+ auto IntegerFlag = MinidumpContext_x86_64_Flags::Integer;
+ auto SegmentsFlag = MinidumpContext_x86_64_Flags::Segments;
+
+ if ((context_flags & x86_64_Flag) != x86_64_Flag)
+ return nullptr;
+
+ if ((context_flags & ControlFlag) == ControlFlag) {
+ writeRegister(&context->cs, result_base, reg_info[lldb_cs_x86_64]);
+ writeRegister(&context->ss, result_base, reg_info[lldb_ss_x86_64]);
+ writeRegister(&context->eflags, result_base, reg_info[lldb_rflags_x86_64]);
+ writeRegister(&context->rsp, result_base, reg_info[lldb_rsp_x86_64]);
+ writeRegister(&context->rip, result_base, reg_info[lldb_rip_x86_64]);
+ }
+
+ if ((context_flags & SegmentsFlag) == SegmentsFlag) {
+ writeRegister(&context->ds, result_base, reg_info[lldb_ds_x86_64]);
+ writeRegister(&context->es, result_base, reg_info[lldb_es_x86_64]);
+ writeRegister(&context->fs, result_base, reg_info[lldb_fs_x86_64]);
+ writeRegister(&context->gs, result_base, reg_info[lldb_gs_x86_64]);
+ }
+
+ if ((context_flags & IntegerFlag) == IntegerFlag) {
+ writeRegister(&context->rax, result_base, reg_info[lldb_rax_x86_64]);
+ writeRegister(&context->rcx, result_base, reg_info[lldb_rcx_x86_64]);
+ writeRegister(&context->rdx, result_base, reg_info[lldb_rdx_x86_64]);
+ writeRegister(&context->rbx, result_base, reg_info[lldb_rbx_x86_64]);
+ writeRegister(&context->rbp, result_base, reg_info[lldb_rbp_x86_64]);
+ writeRegister(&context->rsi, result_base, reg_info[lldb_rsi_x86_64]);
+ writeRegister(&context->rdi, result_base, reg_info[lldb_rdi_x86_64]);
+ writeRegister(&context->r8, result_base, reg_info[lldb_r8_x86_64]);
+ writeRegister(&context->r9, result_base, reg_info[lldb_r9_x86_64]);
+ writeRegister(&context->r10, result_base, reg_info[lldb_r10_x86_64]);
+ writeRegister(&context->r11, result_base, reg_info[lldb_r11_x86_64]);
+ writeRegister(&context->r12, result_base, reg_info[lldb_r12_x86_64]);
+ writeRegister(&context->r13, result_base, reg_info[lldb_r13_x86_64]);
+ writeRegister(&context->r14, result_base, reg_info[lldb_r14_x86_64]);
+ writeRegister(&context->r15, result_base, reg_info[lldb_r15_x86_64]);
+ }
+
+ // TODO parse the floating point registers
+
+ return result_context_buf;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h
new file mode 100644
index 000000000000..d920ea9d823f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h
@@ -0,0 +1,180 @@
+//===-- RegisterContextMinidump_x86_64.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_64_H
+
+#include "MinidumpTypes.h"
+
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+#include "lldb/Target/RegisterContext.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/Support/Endian.h"
+
+// C includes
+// C++ includes
+
+namespace lldb_private {
+
+namespace minidump {
+
+// This function receives an ArrayRef pointing to the bytes of the Minidump
+// register context and returns a DataBuffer that's ordered by the offsets
+// specified in the RegisterInfoInterface argument
+// This way we can reuse the already existing register contexts
+lldb::DataBufferSP
+ConvertMinidumpContext_x86_64(llvm::ArrayRef<uint8_t> source_data,
+ RegisterInfoInterface *target_reg_interface);
+
+struct Uint128 {
+ llvm::support::ulittle64_t high;
+ llvm::support::ulittle64_t low;
+};
+
+// Reference: see breakpad/crashpad source or WinNT.h
+struct MinidumpXMMSaveArea32AMD64 {
+ llvm::support::ulittle16_t control_word;
+ llvm::support::ulittle16_t status_word;
+ uint8_t tag_word;
+ uint8_t reserved1;
+ llvm::support::ulittle16_t error_opcode;
+ llvm::support::ulittle32_t error_offset;
+ llvm::support::ulittle16_t error_selector;
+ llvm::support::ulittle16_t reserved2;
+ llvm::support::ulittle32_t data_offset;
+ llvm::support::ulittle16_t data_selector;
+ llvm::support::ulittle16_t reserved3;
+ llvm::support::ulittle32_t mx_csr;
+ llvm::support::ulittle32_t mx_csr_mask;
+ Uint128 float_registers[8];
+ Uint128 xmm_registers[16];
+ uint8_t reserved4[96];
+};
+
+struct MinidumpContext_x86_64 {
+ // Register parameter home addresses.
+ llvm::support::ulittle64_t p1_home;
+ llvm::support::ulittle64_t p2_home;
+ llvm::support::ulittle64_t p3_home;
+ llvm::support::ulittle64_t p4_home;
+ llvm::support::ulittle64_t p5_home;
+ llvm::support::ulittle64_t p6_home;
+
+ // The context_flags field determines which parts
+ // of the structure are populated (have valid values)
+ llvm::support::ulittle32_t context_flags;
+ llvm::support::ulittle32_t mx_csr;
+
+ // The next register is included with
+ // MinidumpContext_x86_64_Flags::Control
+ llvm::support::ulittle16_t cs;
+
+ // The next 4 registers are included with
+ // MinidumpContext_x86_64_Flags::Segments
+ llvm::support::ulittle16_t ds;
+ llvm::support::ulittle16_t es;
+ llvm::support::ulittle16_t fs;
+ llvm::support::ulittle16_t gs;
+
+ // The next 2 registers are included with
+ // MinidumpContext_x86_64_Flags::Control
+ llvm::support::ulittle16_t ss;
+ llvm::support::ulittle32_t eflags;
+
+ // The next 6 registers are included with
+ // MinidumpContext_x86_64_Flags::DebugRegisters
+ llvm::support::ulittle64_t dr0;
+ llvm::support::ulittle64_t dr1;
+ llvm::support::ulittle64_t dr2;
+ llvm::support::ulittle64_t dr3;
+ llvm::support::ulittle64_t dr6;
+ llvm::support::ulittle64_t dr7;
+
+ // The next 4 registers are included with
+ // MinidumpContext_x86_64_Flags::Integer
+ llvm::support::ulittle64_t rax;
+ llvm::support::ulittle64_t rcx;
+ llvm::support::ulittle64_t rdx;
+ llvm::support::ulittle64_t rbx;
+
+ // The next register is included with
+ // MinidumpContext_x86_64_Flags::Control
+ llvm::support::ulittle64_t rsp;
+
+ // The next 11 registers are included with
+ // MinidumpContext_x86_64_Flags::Integer
+ llvm::support::ulittle64_t rbp;
+ llvm::support::ulittle64_t rsi;
+ llvm::support::ulittle64_t rdi;
+ llvm::support::ulittle64_t r8;
+ llvm::support::ulittle64_t r9;
+ llvm::support::ulittle64_t r10;
+ llvm::support::ulittle64_t r11;
+ llvm::support::ulittle64_t r12;
+ llvm::support::ulittle64_t r13;
+ llvm::support::ulittle64_t r14;
+ llvm::support::ulittle64_t r15;
+
+ // The next register is included with
+ // MinidumpContext_x86_64_Flags::Control
+ llvm::support::ulittle64_t rip;
+
+ // The next set of registers are included with
+ // MinidumpContext_x86_64_Flags:FloatingPoint
+ union FPR {
+ MinidumpXMMSaveArea32AMD64 flt_save;
+ struct {
+ Uint128 header[2];
+ Uint128 legacy[8];
+ Uint128 xmm[16];
+ } sse_registers;
+ };
+
+ enum {
+ VRCount = 26,
+ };
+
+ Uint128 vector_register[VRCount];
+ llvm::support::ulittle64_t vector_control;
+
+ // The next 5 registers are included with
+ // MinidumpContext_x86_64_Flags::DebugRegisters
+ llvm::support::ulittle64_t debug_control;
+ llvm::support::ulittle64_t last_branch_to_rip;
+ llvm::support::ulittle64_t last_branch_from_rip;
+ llvm::support::ulittle64_t last_exception_to_rip;
+ llvm::support::ulittle64_t last_exception_from_rip;
+};
+
+// For context_flags. These values indicate the type of
+// context stored in the structure. The high 24 bits identify the CPU, the
+// low 8 bits identify the type of context saved.
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+enum class MinidumpContext_x86_64_Flags : uint32_t {
+ x86_64_Flag = 0x00100000,
+ Control = x86_64_Flag | 0x00000001,
+ Integer = x86_64_Flag | 0x00000002,
+ Segments = x86_64_Flag | 0x00000004,
+ FloatingPoint = x86_64_Flag | 0x00000008,
+ DebugRegisters = x86_64_Flag | 0x00000010,
+ XState = x86_64_Flag | 0x00000040,
+
+ Full = Control | Integer | FloatingPoint,
+ All = Full | Segments | DebugRegisters,
+
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ All)
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp
new file mode 100644
index 000000000000..1fbc52815238
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp
@@ -0,0 +1,118 @@
+//===-- ThreadMinidump.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThreadMinidump.h"
+
+#include "ProcessMinidump.h"
+
+#include "RegisterContextMinidump_ARM.h"
+#include "RegisterContextMinidump_ARM64.h"
+#include "RegisterContextMinidump_x86_32.h"
+#include "RegisterContextMinidump_x86_64.h"
+
+#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace minidump;
+
+ThreadMinidump::ThreadMinidump(Process &process, const minidump::Thread &td,
+ llvm::ArrayRef<uint8_t> gpregset_data)
+ : Thread(process, td.ThreadId), m_thread_reg_ctx_sp(),
+ m_gpregset_data(gpregset_data) {}
+
+ThreadMinidump::~ThreadMinidump() = default;
+
+void ThreadMinidump::RefreshStateAfterStop() {}
+
+RegisterContextSP ThreadMinidump::GetRegisterContext() {
+ if (!m_reg_context_sp) {
+ m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
+ }
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadMinidump::CreateRegisterContextForFrame(StackFrame *frame) {
+ 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)
+ return m_thread_reg_ctx_sp;
+
+ ProcessMinidump *process =
+ static_cast<ProcessMinidump *>(GetProcess().get());
+ ArchSpec arch = process->GetArchitecture();
+ RegisterInfoInterface *reg_interface = nullptr;
+
+ // TODO write other register contexts and add them here
+ switch (arch.GetMachine()) {
+ case llvm::Triple::x86: {
+ reg_interface = new RegisterContextLinux_i386(arch);
+ lldb::DataBufferSP buf =
+ ConvertMinidumpContext_x86_32(m_gpregset_data, reg_interface);
+ DataExtractor gpregset(buf, lldb::eByteOrderLittle, 4);
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_x86_64>(
+ *this, reg_interface, gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote>());
+ break;
+ }
+ case llvm::Triple::x86_64: {
+ reg_interface = new RegisterContextLinux_x86_64(arch);
+ lldb::DataBufferSP buf =
+ ConvertMinidumpContext_x86_64(m_gpregset_data, reg_interface);
+ DataExtractor gpregset(buf, lldb::eByteOrderLittle, 8);
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_x86_64>(
+ *this, reg_interface, gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote>());
+ break;
+ }
+ case llvm::Triple::aarch64: {
+ DataExtractor data(m_gpregset_data.data(), m_gpregset_data.size(),
+ lldb::eByteOrderLittle, 8);
+ m_thread_reg_ctx_sp =
+ std::make_shared<RegisterContextMinidump_ARM64>(*this, data);
+ break;
+ }
+ case llvm::Triple::arm: {
+ DataExtractor data(m_gpregset_data.data(), m_gpregset_data.size(),
+ lldb::eByteOrderLittle, 8);
+ const bool apple = arch.GetTriple().getVendor() == llvm::Triple::Apple;
+ m_thread_reg_ctx_sp =
+ std::make_shared<RegisterContextMinidump_ARM>(*this, data, apple);
+ break;
+ }
+ default:
+ break;
+ }
+
+ reg_ctx_sp = m_thread_reg_ctx_sp;
+ } else if (m_unwinder_up) {
+ reg_ctx_sp = m_unwinder_up->CreateRegisterContextForFrame(frame);
+ }
+
+ return reg_ctx_sp;
+}
+
+bool ThreadMinidump::CalculateStopInfo() { return false; }
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.h
new file mode 100644
index 000000000000..aed7cfbc1b16
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.h
@@ -0,0 +1,45 @@
+//===-- ThreadMinidump.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_THREADMINIDUMP_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_THREADMINIDUMP_H
+
+#include "MinidumpTypes.h"
+
+#include "lldb/Target/Thread.h"
+
+
+namespace lldb_private {
+
+namespace minidump {
+
+class ThreadMinidump : public Thread {
+public:
+ ThreadMinidump(Process &process, const minidump::Thread &td,
+ llvm::ArrayRef<uint8_t> gpregset_data);
+
+ ~ThreadMinidump() override;
+
+ void RefreshStateAfterStop() override;
+
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(StackFrame *frame) override;
+
+protected:
+ lldb::RegisterContextSP m_thread_reg_ctx_sp;
+ llvm::ArrayRef<uint8_t> m_gpregset_data;
+
+ bool CalculateStopInfo() override;
+};
+
+} // namespace minidump
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_THREADMINIDUMP_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
new file mode 100644
index 000000000000..66f861350d14
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -0,0 +1,540 @@
+//===-- ScriptedProcess.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptedProcess.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionGroupBoolean.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/Queue.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/ScriptedMetadata.h"
+#include "lldb/Utility/State.h"
+
+#include <mutex>
+
+LLDB_PLUGIN_DEFINE(ScriptedProcess)
+
+using namespace lldb;
+using namespace lldb_private;
+
+llvm::StringRef ScriptedProcess::GetPluginDescriptionStatic() {
+ return "Scripted Process plug-in.";
+}
+
+static constexpr lldb::ScriptLanguage g_supported_script_languages[] = {
+ ScriptLanguage::eScriptLanguagePython,
+};
+
+bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) {
+ llvm::ArrayRef<lldb::ScriptLanguage> supported_languages =
+ llvm::ArrayRef(g_supported_script_languages);
+
+ return llvm::is_contained(supported_languages, language);
+}
+
+lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *file,
+ bool can_connect) {
+ if (!target_sp ||
+ !IsScriptLanguageSupported(target_sp->GetDebugger().GetScriptLanguage()))
+ return nullptr;
+
+ ScriptedMetadata scripted_metadata(target_sp->GetProcessLaunchInfo());
+
+ Status error;
+ auto process_sp = std::shared_ptr<ScriptedProcess>(
+ new ScriptedProcess(target_sp, listener_sp, scripted_metadata, error));
+
+ if (error.Fail() || !process_sp || !process_sp->m_interface_up) {
+ LLDB_LOGF(GetLog(LLDBLog::Process), "%s", error.AsCString());
+ return nullptr;
+ }
+
+ return process_sp;
+}
+
+bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) {
+ return true;
+}
+
+ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const ScriptedMetadata &scripted_metadata,
+ Status &error)
+ : Process(target_sp, listener_sp), m_scripted_metadata(scripted_metadata) {
+
+ if (!target_sp) {
+ error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
+ __FUNCTION__, "Invalid target");
+ return;
+ }
+
+ ScriptInterpreter *interpreter =
+ target_sp->GetDebugger().GetScriptInterpreter();
+
+ if (!interpreter) {
+ error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
+ __FUNCTION__,
+ "Debugger has no Script Interpreter");
+ return;
+ }
+
+ // Create process instance interface
+ m_interface_up = interpreter->CreateScriptedProcessInterface();
+ if (!m_interface_up) {
+ error.SetErrorStringWithFormat(
+ "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,
+ "Script interpreter couldn't create Scripted Process Interface");
+ return;
+ }
+
+ ExecutionContext exe_ctx(target_sp, /*get_process=*/false);
+
+ // Create process script object
+ auto obj_or_err = GetInterface().CreatePluginObject(
+ m_scripted_metadata.GetClassName(), exe_ctx,
+ m_scripted_metadata.GetArgsSP());
+
+ if (!obj_or_err) {
+ llvm::consumeError(obj_or_err.takeError());
+ error.SetErrorString("Failed to create script object.");
+ return;
+ }
+
+ StructuredData::GenericSP object_sp = *obj_or_err;
+
+ if (!object_sp || !object_sp->IsValid()) {
+ error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
+ __FUNCTION__,
+ "Failed to create valid script object");
+ return;
+ }
+}
+
+ScriptedProcess::~ScriptedProcess() {
+ Clear();
+ // If the interface is not valid, we can't call Finalize(). When that happens
+ // it means that the Scripted Process instanciation failed and the
+ // CreateProcess function returns a nullptr, so no one besides this class
+ // should have access to that bogus process object.
+ if (!m_interface_up)
+ return;
+ // 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(true /* destructing */);
+}
+
+void ScriptedProcess::Initialize() {
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+ });
+}
+
+void ScriptedProcess::Terminate() {
+ PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance);
+}
+
+Status ScriptedProcess::DoLoadCore() {
+ ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo();
+
+ return DoLaunch(nullptr, launch_info);
+}
+
+Status ScriptedProcess::DoLaunch(Module *exe_module,
+ ProcessLaunchInfo &launch_info) {
+ LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s launching process", __FUNCTION__);
+
+ /* MARK: This doesn't reflect how lldb actually launches a process.
+ In reality, it attaches to debugserver, then resume the process.
+ That's not true in all cases. If debugserver is remote, lldb
+ asks debugserver to launch the process for it. */
+ Status error = GetInterface().Launch();
+ SetPrivateState(eStateStopped);
+ return error;
+}
+
+void ScriptedProcess::DidLaunch() { m_pid = GetInterface().GetProcessID(); }
+
+void ScriptedProcess::DidResume() {
+ // Update the PID again, in case the user provided a placeholder pid at launch
+ m_pid = GetInterface().GetProcessID();
+}
+
+Status ScriptedProcess::DoResume() {
+ LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s resuming process", __FUNCTION__);
+
+ return GetInterface().Resume();
+}
+
+Status ScriptedProcess::DoAttach(const ProcessAttachInfo &attach_info) {
+ Status error = GetInterface().Attach(attach_info);
+ SetPrivateState(eStateRunning);
+ SetPrivateState(eStateStopped);
+ if (error.Fail())
+ return error;
+ // NOTE: We need to set the PID before finishing to attach otherwise we will
+ // hit an assert when calling the attach completion handler.
+ DidLaunch();
+
+ return {};
+}
+
+Status
+ScriptedProcess::DoAttachToProcessWithID(lldb::pid_t pid,
+ const ProcessAttachInfo &attach_info) {
+ return DoAttach(attach_info);
+}
+
+Status ScriptedProcess::DoAttachToProcessWithName(
+ const char *process_name, const ProcessAttachInfo &attach_info) {
+ return DoAttach(attach_info);
+}
+
+void ScriptedProcess::DidAttach(ArchSpec &process_arch) {
+ process_arch = GetArchitecture();
+}
+
+Status ScriptedProcess::DoDestroy() { return Status(); }
+
+bool ScriptedProcess::IsAlive() { return GetInterface().IsAlive(); }
+
+size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) {
+ lldb::DataExtractorSP data_extractor_sp =
+ GetInterface().ReadMemoryAtAddress(addr, size, error);
+
+ if (!data_extractor_sp || !data_extractor_sp->GetByteSize() || error.Fail())
+ return 0;
+
+ offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData(
+ 0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder());
+
+ if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET)
+ return ScriptedInterface::ErrorWithMessage<size_t>(
+ LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error);
+
+ // FIXME: We should use the diagnostic system to report a warning if the
+ // `bytes_copied` is different from `size`.
+
+ return bytes_copied;
+}
+
+size_t ScriptedProcess::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
+ size_t size, Status &error) {
+ lldb::DataExtractorSP data_extractor_sp = std::make_shared<DataExtractor>(
+ buf, size, GetByteOrder(), GetAddressByteSize());
+
+ if (!data_extractor_sp || !data_extractor_sp->GetByteSize())
+ return 0;
+
+ lldb::offset_t bytes_written =
+ GetInterface().WriteMemoryAtAddress(vm_addr, data_extractor_sp, error);
+
+ if (!bytes_written || bytes_written == LLDB_INVALID_OFFSET)
+ return ScriptedInterface::ErrorWithMessage<size_t>(
+ LLVM_PRETTY_FUNCTION, "Failed to copy write buffer to memory.", error);
+
+ // FIXME: We should use the diagnostic system to report a warning if the
+ // `bytes_written` is different from `size`.
+
+ return bytes_written;
+}
+
+Status ScriptedProcess::EnableBreakpointSite(BreakpointSite *bp_site) {
+ assert(bp_site != nullptr);
+
+ if (bp_site->IsEnabled()) {
+ return {};
+ }
+
+ if (bp_site->HardwareRequired()) {
+ return Status("Scripted Processes don't support hardware breakpoints");
+ }
+
+ Status error;
+ GetInterface().CreateBreakpoint(bp_site->GetLoadAddress(), error);
+
+ return error;
+}
+
+ArchSpec ScriptedProcess::GetArchitecture() {
+ return GetTarget().GetArchitecture();
+}
+
+Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &region) {
+ Status error;
+ if (auto region_or_err =
+ GetInterface().GetMemoryRegionContainingAddress(load_addr, error))
+ region = *region_or_err;
+
+ return error;
+}
+
+Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_list) {
+ Status error;
+ lldb::addr_t address = 0;
+
+ while (auto region_or_err =
+ GetInterface().GetMemoryRegionContainingAddress(address, error)) {
+ if (error.Fail())
+ break;
+
+ MemoryRegionInfo &mem_region = *region_or_err;
+ auto range = mem_region.GetRange();
+ address += range.GetRangeBase() + range.GetByteSize();
+ region_list.push_back(mem_region);
+ }
+
+ return error;
+}
+
+void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); }
+
+bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
+ // TODO: Implement
+ // This is supposed to get the current set of threads, if any of them are in
+ // old_thread_list then they get copied to new_thread_list, and then any
+ // actually new threads will get added to new_thread_list.
+ m_thread_plans.ClearThreadCache();
+
+ Status error;
+ StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();
+
+ if (!thread_info_sp)
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ "Couldn't fetch thread list from Scripted Process.", error);
+
+ // Because `StructuredData::Dictionary` uses a `std::map<ConstString,
+ // ObjectSP>` for storage, each item is sorted based on the key alphabetical
+ // order. Since `GetThreadsInfo` provides thread indices as the key element,
+ // thread info comes ordered alphabetically, instead of numerically, so we
+ // need to sort the thread indices before creating thread.
+
+ StructuredData::ArraySP keys = thread_info_sp->GetKeys();
+
+ std::map<size_t, StructuredData::ObjectSP> sorted_threads;
+ auto sort_keys = [&sorted_threads,
+ &thread_info_sp](StructuredData::Object *item) -> bool {
+ if (!item)
+ return false;
+
+ llvm::StringRef key = item->GetStringValue();
+ size_t idx = 0;
+
+ // Make sure the provided index is actually an integer
+ if (!llvm::to_integer(key, idx))
+ return false;
+
+ sorted_threads[idx] = thread_info_sp->GetValueForKey(key);
+ return true;
+ };
+
+ size_t thread_count = thread_info_sp->GetSize();
+
+ if (!keys->ForEach(sort_keys) || sorted_threads.size() != thread_count)
+ // Might be worth showing the unsorted thread list instead of return early.
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, "Couldn't sort thread list.", error);
+
+ auto create_scripted_thread =
+ [this, &error, &new_thread_list](
+ const std::pair<size_t, StructuredData::ObjectSP> pair) -> bool {
+ size_t idx = pair.first;
+ StructuredData::ObjectSP object_sp = pair.second;
+
+ if (!object_sp)
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, "Invalid thread info object", error);
+
+ auto thread_or_error =
+ ScriptedThread::Create(*this, object_sp->GetAsGeneric());
+
+ if (!thread_or_error)
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, toString(thread_or_error.takeError()), error);
+
+ ThreadSP thread_sp = thread_or_error.get();
+ lldbassert(thread_sp && "Couldn't initialize scripted thread.");
+
+ RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
+ if (!reg_ctx_sp)
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine("Invalid Register Context for thread " + llvm::Twine(idx))
+ .str(),
+ error);
+
+ new_thread_list.AddThread(thread_sp);
+
+ return true;
+ };
+
+ llvm::for_each(sorted_threads, create_scripted_thread);
+
+ return new_thread_list.GetSize(false) > 0;
+}
+
+void ScriptedProcess::RefreshStateAfterStop() {
+ // Let all threads recover from stopping and do any clean up based on the
+ // previous thread state (if any).
+ m_thread_list.RefreshStateAfterStop();
+}
+
+bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {
+ info.Clear();
+ info.SetProcessID(GetID());
+ info.SetArchitecture(GetArchitecture());
+ lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
+ if (module_sp) {
+ const bool add_exe_file_as_first_arg = false;
+ info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
+ add_exe_file_as_first_arg);
+ }
+ return true;
+}
+
+lldb_private::StructuredData::ObjectSP
+ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
+ Status error;
+ auto error_with_message = [&error](llvm::StringRef message) {
+ return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
+ message.data(), error);
+ };
+
+ StructuredData::ArraySP loaded_images_sp = GetInterface().GetLoadedImages();
+
+ if (!loaded_images_sp || !loaded_images_sp->GetSize())
+ return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
+ LLVM_PRETTY_FUNCTION, "No loaded images.", error);
+
+ ModuleList module_list;
+ Target &target = GetTarget();
+
+ auto reload_image = [&target, &module_list, &error_with_message](
+ StructuredData::Object *obj) -> bool {
+ StructuredData::Dictionary *dict = obj->GetAsDictionary();
+
+ if (!dict)
+ return error_with_message("Couldn't cast image object into dictionary.");
+
+ ModuleSpec module_spec;
+ llvm::StringRef value;
+
+ bool has_path = dict->HasKey("path");
+ bool has_uuid = dict->HasKey("uuid");
+ if (!has_path && !has_uuid)
+ return error_with_message("Dictionary should have key 'path' or 'uuid'");
+ if (!dict->HasKey("load_addr"))
+ return error_with_message("Dictionary is missing key 'load_addr'");
+
+ if (has_path) {
+ dict->GetValueForKeyAsString("path", value);
+ module_spec.GetFileSpec().SetPath(value);
+ }
+
+ if (has_uuid) {
+ dict->GetValueForKeyAsString("uuid", value);
+ module_spec.GetUUID().SetFromStringRef(value);
+ }
+ module_spec.GetArchitecture() = target.GetArchitecture();
+
+ ModuleSP module_sp =
+ target.GetOrCreateModule(module_spec, true /* notify */);
+
+ if (!module_sp)
+ return error_with_message("Couldn't create or get module.");
+
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ lldb::offset_t slide = LLDB_INVALID_OFFSET;
+ dict->GetValueForKeyAsInteger("load_addr", load_addr);
+ dict->GetValueForKeyAsInteger("slide", slide);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ return error_with_message(
+ "Couldn't get valid load address or slide offset.");
+
+ if (slide != LLDB_INVALID_OFFSET)
+ load_addr += slide;
+
+ bool changed = false;
+ module_sp->SetLoadAddress(target, load_addr, false /*=value_is_offset*/,
+ changed);
+
+ if (!changed && !module_sp->GetObjectFile())
+ return error_with_message("Couldn't set the load address for module.");
+
+ dict->GetValueForKeyAsString("path", value);
+ FileSpec objfile(value);
+ module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename());
+
+ return module_list.AppendIfNeeded(module_sp);
+ };
+
+ if (!loaded_images_sp->ForEach(reload_image))
+ return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
+ LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error);
+
+ target.ModulesDidLoad(module_list);
+
+ return loaded_images_sp;
+}
+
+lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() {
+ StructuredData::DictionarySP metadata_sp = GetInterface().GetMetadata();
+
+ Status error;
+ if (!metadata_sp || !metadata_sp->GetSize())
+ return ScriptedInterface::ErrorWithMessage<StructuredData::DictionarySP>(
+ LLVM_PRETTY_FUNCTION, "No metadata.", error);
+
+ return metadata_sp;
+}
+
+void ScriptedProcess::UpdateQueueListIfNeeded() {
+ CheckScriptedInterface();
+ for (ThreadSP thread_sp : Threads()) {
+ if (const char *queue_name = thread_sp->GetQueueName()) {
+ QueueSP queue_sp = std::make_shared<Queue>(
+ m_process->shared_from_this(), thread_sp->GetQueueID(), queue_name);
+ m_queue_list.AddQueue(queue_sp);
+ }
+ }
+}
+
+ScriptedProcessInterface &ScriptedProcess::GetInterface() const {
+ CheckScriptedInterface();
+ return *m_interface_up;
+}
+
+void *ScriptedProcess::GetImplementation() {
+ StructuredData::GenericSP object_instance_sp =
+ GetInterface().GetScriptObjectInstance();
+ if (object_instance_sp &&
+ object_instance_sp->GetType() == eStructuredDataTypeGeneric)
+ return object_instance_sp->GetAsGeneric()->GetValue();
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.h b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
new file mode 100644
index 000000000000..0335364b4010
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
@@ -0,0 +1,136 @@
+//===-- ScriptedProcess.h ------------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SCRIPTED_PROCESS_H
+#define LLDB_SOURCE_PLUGINS_SCRIPTED_PROCESS_H
+
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/ScriptedMetadata.h"
+#include "lldb/Utility/State.h"
+#include "lldb/Utility/Status.h"
+
+#include "ScriptedThread.h"
+
+#include <mutex>
+
+namespace lldb_private {
+class ScriptedProcess : public Process {
+public:
+ static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file_path,
+ bool can_connect);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "ScriptedProcess"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ ~ScriptedProcess() override;
+
+ bool CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) override;
+
+ DynamicLoader *GetDynamicLoader() override { return nullptr; }
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ Status DoLoadCore() override;
+
+ Status DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override;
+
+ void DidLaunch() override;
+
+ void DidResume() override;
+
+ Status DoResume() override;
+
+ Status DoAttachToProcessWithID(lldb::pid_t pid,
+ const ProcessAttachInfo &attach_info) override;
+
+ Status
+ DoAttachToProcessWithName(const char *process_name,
+ const ProcessAttachInfo &attach_info) override;
+
+ void DidAttach(ArchSpec &process_arch) override;
+
+ Status DoDestroy() override;
+
+ void RefreshStateAfterStop() override;
+
+ bool IsAlive() override;
+
+ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) override;
+
+ size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ Status &error) override;
+
+ Status EnableBreakpointSite(BreakpointSite *bp_site) override;
+
+ ArchSpec GetArchitecture();
+
+ Status
+ GetMemoryRegions(lldb_private::MemoryRegionInfos &region_list) override;
+
+ bool GetProcessInfo(ProcessInstanceInfo &info) override;
+
+ lldb_private::StructuredData::ObjectSP
+ GetLoadedDynamicLibrariesInfos() override;
+
+ lldb_private::StructuredData::DictionarySP GetMetadata() override;
+
+ void UpdateQueueListIfNeeded() override;
+
+ void *GetImplementation() override;
+
+ void ForceScriptedState(lldb::StateType state) override {
+ // If we're about to stop, we should fetch the loaded dynamic libraries
+ // dictionary before emitting the private stop event to avoid having the
+ // module loading happen while the process state is changing.
+ if (StateIsStoppedState(state, true))
+ GetLoadedDynamicLibrariesInfos();
+ SetPrivateState(state);
+ }
+
+protected:
+ ScriptedProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
+ const ScriptedMetadata &scripted_metadata, Status &error);
+
+ void Clear();
+
+ bool DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override;
+
+ Status DoGetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
+
+ Status DoAttach(const ProcessAttachInfo &attach_info);
+
+private:
+ friend class ScriptedThread;
+
+ inline void CheckScriptedInterface() const {
+ lldbassert(m_interface_up && "Invalid scripted process interface.");
+ }
+
+ ScriptedProcessInterface &GetInterface() const;
+ static bool IsScriptLanguageSupported(lldb::ScriptLanguage language);
+
+ // Member variables.
+ const ScriptedMetadata m_scripted_metadata;
+ lldb::ScriptedProcessInterfaceUP m_interface_up;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SCRIPTED_PROCESS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
new file mode 100644
index 000000000000..88a4ca3b0389
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
@@ -0,0 +1,370 @@
+//===-- ScriptedThread.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptedThread.h"
+
+#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
+#include "Plugins/Process/Utility/StopInfoMachException.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBLog.h"
+#include <memory>
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+
+void ScriptedThread::CheckInterpreterAndScriptObject() const {
+ lldbassert(m_script_object_sp && "Invalid Script Object.");
+ lldbassert(GetInterface() && "Invalid Scripted Thread Interface.");
+}
+
+llvm::Expected<std::shared_ptr<ScriptedThread>>
+ScriptedThread::Create(ScriptedProcess &process,
+ StructuredData::Generic *script_object) {
+ if (!process.IsValid())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Invalid scripted process.");
+
+ process.CheckScriptedInterface();
+
+ auto scripted_thread_interface =
+ process.GetInterface().CreateScriptedThreadInterface();
+ if (!scripted_thread_interface)
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Failed to create scripted thread interface.");
+
+ llvm::StringRef thread_class_name;
+ if (!script_object) {
+ std::optional<std::string> class_name =
+ process.GetInterface().GetScriptedThreadPluginName();
+ if (!class_name || class_name->empty())
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Failed to get scripted thread class name.");
+ thread_class_name = *class_name;
+ }
+
+ ExecutionContext exe_ctx(process);
+ auto obj_or_err = scripted_thread_interface->CreatePluginObject(
+ thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(),
+ script_object);
+
+ if (!obj_or_err) {
+ llvm::consumeError(obj_or_err.takeError());
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Failed to create script object.");
+ }
+
+ StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
+
+ if (!owned_script_object_sp->IsValid())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Created script object is invalid.");
+
+ lldb::tid_t tid = scripted_thread_interface->GetThreadID();
+
+ return std::make_shared<ScriptedThread>(process, scripted_thread_interface,
+ tid, owned_script_object_sp);
+}
+
+ScriptedThread::ScriptedThread(ScriptedProcess &process,
+ ScriptedThreadInterfaceSP interface_sp,
+ lldb::tid_t tid,
+ StructuredData::GenericSP script_object_sp)
+ : Thread(process, tid), m_scripted_process(process),
+ m_scripted_thread_interface_sp(interface_sp),
+ m_script_object_sp(script_object_sp) {}
+
+ScriptedThread::~ScriptedThread() { DestroyThread(); }
+
+const char *ScriptedThread::GetName() {
+ CheckInterpreterAndScriptObject();
+ std::optional<std::string> thread_name = GetInterface()->GetName();
+ if (!thread_name)
+ return nullptr;
+ return ConstString(thread_name->c_str()).AsCString();
+}
+
+const char *ScriptedThread::GetQueueName() {
+ CheckInterpreterAndScriptObject();
+ std::optional<std::string> queue_name = GetInterface()->GetQueue();
+ if (!queue_name)
+ return nullptr;
+ return ConstString(queue_name->c_str()).AsCString();
+}
+
+void ScriptedThread::WillResume(StateType resume_state) {}
+
+void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); }
+
+RegisterContextSP ScriptedThread::GetRegisterContext() {
+ if (!m_reg_context_sp)
+ m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
+ const uint32_t concrete_frame_idx =
+ frame ? frame->GetConcreteFrameIndex() : 0;
+
+ if (concrete_frame_idx)
+ return GetUnwinder().CreateRegisterContextForFrame(frame);
+
+ lldb::RegisterContextSP reg_ctx_sp;
+ Status error;
+
+ std::optional<std::string> reg_data = GetInterface()->GetRegisterContext();
+ if (!reg_data)
+ return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(
+ LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.",
+ error, LLDBLog::Thread);
+
+ DataBufferSP data_sp(
+ std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
+
+ if (!data_sp->GetByteSize())
+ return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(
+ LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error,
+ LLDBLog::Thread);
+
+ std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
+ std::make_shared<RegisterContextMemory>(
+ *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
+ if (!reg_ctx_memory)
+ return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>(
+ LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error,
+ LLDBLog::Thread);
+
+ reg_ctx_memory->SetAllRegisterData(data_sp);
+ m_reg_context_sp = reg_ctx_memory;
+
+ return m_reg_context_sp;
+}
+
+bool ScriptedThread::LoadArtificialStackFrames() {
+ StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames();
+
+ Status error;
+ if (!arr_sp)
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.",
+ error, LLDBLog::Thread);
+
+ size_t arr_size = arr_sp->GetSize();
+ if (arr_size > std::numeric_limits<uint32_t>::max())
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine(
+ "StackFrame array size (" + llvm::Twine(arr_size) +
+ llvm::Twine(
+ ") is greater than maximum authorized for a StackFrameList."))
+ .str(),
+ error, LLDBLog::Thread);
+
+ StackFrameListSP frames = GetStackFrameList();
+
+ for (size_t idx = 0; idx < arr_size; idx++) {
+ std::optional<StructuredData::Dictionary *> maybe_dict =
+ arr_sp->GetItemAtIndexAsDictionary(idx);
+ if (!maybe_dict)
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine(
+ "Couldn't get artificial stackframe dictionary at index (" +
+ llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
+ .str(),
+ error, LLDBLog::Thread);
+ StructuredData::Dictionary *dict = *maybe_dict;
+
+ lldb::addr_t pc;
+ if (!dict->GetValueForKeyAsInteger("pc", pc))
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ "Couldn't find value for key 'pc' in stackframe dictionary.", error,
+ LLDBLog::Thread);
+
+ Address symbol_addr;
+ symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());
+
+ lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
+ bool cfa_is_valid = false;
+ const bool behaves_like_zeroth_frame = false;
+ SymbolContext sc;
+ symbol_addr.CalculateSymbolContext(&sc);
+
+ StackFrameSP synth_frame_sp = std::make_shared<StackFrame>(
+ this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
+ StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc);
+
+ if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) +
+ llvm::Twine(") to ScriptedThread StackFrameList."))
+ .str(),
+ error, LLDBLog::Thread);
+ }
+
+ return true;
+}
+
+bool ScriptedThread::CalculateStopInfo() {
+ StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();
+
+ Status error;
+ if (!dict_sp)
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error,
+ LLDBLog::Thread);
+
+ lldb::StopInfoSP stop_info_sp;
+ lldb::StopReason stop_reason_type;
+
+ if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type))
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ "Couldn't find value for key 'type' in stop reason dictionary.", error,
+ LLDBLog::Thread);
+
+ StructuredData::Dictionary *data_dict;
+ if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict))
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ "Couldn't find value for key 'data' in stop reason dictionary.", error,
+ LLDBLog::Thread);
+
+ switch (stop_reason_type) {
+ case lldb::eStopReasonNone:
+ return true;
+ case lldb::eStopReasonBreakpoint: {
+ lldb::break_id_t break_id;
+ data_dict->GetValueForKeyAsInteger("break_id", break_id,
+ LLDB_INVALID_BREAK_ID);
+ stop_info_sp =
+ StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id);
+ } break;
+ case lldb::eStopReasonSignal: {
+ uint32_t signal;
+ llvm::StringRef description;
+ if (!data_dict->GetValueForKeyAsInteger("signal", signal)) {
+ signal = LLDB_INVALID_SIGNAL_NUMBER;
+ return false;
+ }
+ data_dict->GetValueForKeyAsString("desc", description);
+ stop_info_sp =
+ StopInfo::CreateStopReasonWithSignal(*this, signal, description.data());
+ } break;
+ case lldb::eStopReasonTrace: {
+ stop_info_sp = StopInfo::CreateStopReasonToTrace(*this);
+ } break;
+ case lldb::eStopReasonException: {
+#if defined(__APPLE__)
+ StructuredData::Dictionary *mach_exception;
+ if (data_dict->GetValueForKeyAsDictionary("mach_exception",
+ mach_exception)) {
+ llvm::StringRef value;
+ mach_exception->GetValueForKeyAsString("type", value);
+ auto exc_type =
+ StopInfoMachException::MachException::ExceptionCode(value.data());
+
+ if (!exc_type)
+ return false;
+
+ uint32_t exc_data_size = 0;
+ llvm::SmallVector<uint64_t, 3> raw_codes;
+
+ StructuredData::Array *exc_rawcodes;
+ mach_exception->GetValueForKeyAsArray("rawCodes", exc_rawcodes);
+ if (exc_rawcodes) {
+ auto fetch_data = [&raw_codes](StructuredData::Object *obj) {
+ if (!obj)
+ return false;
+ raw_codes.push_back(obj->GetUnsignedIntegerValue());
+ return true;
+ };
+
+ exc_rawcodes->ForEach(fetch_data);
+ exc_data_size = raw_codes.size();
+ }
+
+ stop_info_sp = StopInfoMachException::CreateStopReasonWithMachException(
+ *this, *exc_type, exc_data_size,
+ exc_data_size >= 1 ? raw_codes[0] : 0,
+ exc_data_size >= 2 ? raw_codes[1] : 0,
+ exc_data_size >= 3 ? raw_codes[2] : 0);
+
+ break;
+ }
+#endif
+ stop_info_sp =
+ StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS");
+ } break;
+ default:
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine("Unsupported stop reason type (" +
+ llvm::Twine(stop_reason_type) + llvm::Twine(")."))
+ .str(),
+ error, LLDBLog::Thread);
+ }
+
+ if (!stop_info_sp)
+ return false;
+
+ SetStopInfo(stop_info_sp);
+ return true;
+}
+
+void ScriptedThread::RefreshStateAfterStop() {
+ GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
+ LoadArtificialStackFrames();
+}
+
+lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
+ return m_scripted_thread_interface_sp;
+}
+
+std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
+ CheckInterpreterAndScriptObject();
+
+ if (!m_register_info_sp) {
+ StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
+
+ Status error;
+ if (!reg_info)
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers info.",
+ error, LLDBLog::Thread);
+
+ m_register_info_sp = DynamicRegisterInfo::Create(
+ *reg_info, m_scripted_process.GetTarget().GetArchitecture());
+ }
+
+ return m_register_info_sp;
+}
+
+StructuredData::ObjectSP ScriptedThread::FetchThreadExtendedInfo() {
+ CheckInterpreterAndScriptObject();
+
+ Status error;
+ StructuredData::ArraySP extended_info_sp = GetInterface()->GetExtendedInfo();
+
+ if (!extended_info_sp || !extended_info_sp->GetSize())
+ return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
+ LLVM_PRETTY_FUNCTION, "No extended information found", error);
+
+ return extended_info_sp;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.h b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.h
new file mode 100644
index 000000000000..cd224d60ceef
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.h
@@ -0,0 +1,80 @@
+//===-- ScriptedThread.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SCRIPTED_THREAD_H
+#define LLDB_SOURCE_PLUGINS_SCRIPTED_THREAD_H
+
+#include <string>
+
+#include "ScriptedProcess.h"
+
+#include "Plugins/Process/Utility/RegisterContextMemory.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target//DynamicRegisterInfo.h"
+#include "lldb/Target/Thread.h"
+
+namespace lldb_private {
+class ScriptedProcess;
+}
+
+namespace lldb_private {
+
+class ScriptedThread : public lldb_private::Thread {
+
+public:
+ ScriptedThread(ScriptedProcess &process,
+ lldb::ScriptedThreadInterfaceSP interface_sp, lldb::tid_t tid,
+ StructuredData::GenericSP script_object_sp = nullptr);
+
+ ~ScriptedThread() override;
+
+ static llvm::Expected<std::shared_ptr<ScriptedThread>>
+ Create(ScriptedProcess &process,
+ StructuredData::Generic *script_object = nullptr);
+
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+ bool LoadArtificialStackFrames();
+
+ bool CalculateStopInfo() override;
+
+ const char *GetInfo() override { return nullptr; }
+
+ const char *GetName() override;
+
+ const char *GetQueueName() override;
+
+ void WillResume(lldb::StateType resume_state) override;
+
+ void RefreshStateAfterStop() override;
+
+ void ClearStackFrames() override;
+
+ StructuredData::ObjectSP FetchThreadExtendedInfo() override;
+
+private:
+ void CheckInterpreterAndScriptObject() const;
+ lldb::ScriptedThreadInterfaceSP GetInterface() const;
+
+ ScriptedThread(const ScriptedThread &) = delete;
+ const ScriptedThread &operator=(const ScriptedThread &) = delete;
+
+ std::shared_ptr<DynamicRegisterInfo> GetDynamicRegisterInfo();
+
+ const ScriptedProcess &m_scripted_process;
+ lldb::ScriptedThreadInterfaceSP m_scripted_thread_interface_sp = nullptr;
+ lldb_private::StructuredData::GenericSP m_script_object_sp = nullptr;
+ std::shared_ptr<DynamicRegisterInfo> m_register_info_sp = nullptr;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SCRIPTED_THREAD_H