diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp index 2ddf8440aeb03..bd02bb0e69a4d 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -69,6 +69,15 @@ RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch, if (fpmr_data.GetByteSize() >= sizeof(uint64_t)) opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskFPMR); + DataExtractor gcs_data = getRegset(notes, arch.GetTriple(), AARCH64_GCS_Desc); + struct __attribute__((packed)) gcs_regs { + uint64_t features_enabled; + uint64_t features_locked; + uint64_t gcspr_e0; + }; + if (gcs_data.GetByteSize() >= sizeof(gcs_regs)) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskGCS); + auto register_info_up = std::make_unique(arch, opt_regsets); return std::unique_ptr( @@ -136,6 +145,9 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( if (m_register_info_up->IsFPMRPresent()) m_fpmr_data = getRegset(notes, target_triple, AARCH64_FPMR_Desc); + if (m_register_info_up->IsGCSPresent()) + m_gcs_data = getRegset(notes, target_triple, AARCH64_GCS_Desc); + ConfigureRegisterContext(); } @@ -330,6 +342,11 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, assert(offset < m_mte_data.GetByteSize()); value.SetFromMemoryData(*reg_info, m_mte_data.GetDataStart() + offset, reg_info->byte_size, lldb::eByteOrderLittle, error); + } else if (IsGCS(reg)) { + offset = reg_info->byte_offset - m_register_info_up->GetGCSOffset(); + assert(offset < m_gcs_data.GetByteSize()); + value.SetFromMemoryData(*reg_info, m_gcs_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. diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h index 35588c40c2eb1..6140f805ffc78 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h @@ -63,6 +63,7 @@ class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 { lldb_private::DataExtractor m_mte_data; lldb_private::DataExtractor m_zt_data; lldb_private::DataExtractor m_fpmr_data; + lldb_private::DataExtractor m_gcs_data; SVEState m_sve_state = SVEState::Unknown; uint16_t m_sve_vector_length = 0; diff --git a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h index b97279b0d735b..59382a12cde0a 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h @@ -148,6 +148,10 @@ constexpr RegsetDesc AARCH64_FPMR_Desc[] = { {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_FPMR}, }; +constexpr RegsetDesc AARCH64_GCS_Desc[] = { + {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_GCS}, +}; + 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}, diff --git a/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py b/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py index 797551b061a23..adbef69c5c38b 100644 --- a/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py +++ b/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py @@ -374,3 +374,35 @@ def test_gcs_expression_enable_gcs(self): # consistent with the disabled -> enabled behaviour. enabled |= 1 self.check_gcs_registers(enabled, locked, spr_el0) + + @skipIfLLVMTargetMissing("AArch64") + def test_gcs_core_file(self): + # To re-generate the core file, build the test file and run it on a + # machine with GCS enabled. Note that because the kernel decides where + # the GCS is stored, the value of gcspr_el0 and which memory region it + # points to may change between runs. + + self.runCmd("target create --core corefile") + + self.expect( + "bt", + substrs=["stop reason = SIGSEGV: control protection fault"], + ) + + self.expect( + "register read --all", + substrs=[ + "Guarded Control Stack Registers:", + "gcs_features_enabled = 0x0000000000000001", + "gcs_features_locked = 0x0000000000000000", + "gcspr_el0 = 0x0000ffffa83ffff0", + ], + ) + + # Core files do not include /proc/pid/smaps, so we cannot see the + # shadow stack "ss" flag. gcspr_el0 should at least point to some mapped + # region. + self.expect( + "memory region $gcspr_el0", + substrs=["[0x0000ffffa8000000-0x0000ffffa8400000) rw-"], + ) diff --git a/lldb/test/API/linux/aarch64/gcs/corefile b/lldb/test/API/linux/aarch64/gcs/corefile new file mode 100644 index 0000000000000..34faa98c4d783 Binary files /dev/null and b/lldb/test/API/linux/aarch64/gcs/corefile differ