Skip to content

[lldb][AArch64] Add Guarded Control Stack support for Linux core files #124293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down
32 changes: 32 additions & 0 deletions lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py
Original file line number Diff line number Diff line change
Expand Up @@ -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-"],
)
Binary file added lldb/test/API/linux/aarch64/gcs/corefile
Binary file not shown.
Loading