Skip to content

Commit c837597

Browse files
committed
[lldb][AArch64] Add Guarded Control Stack support for Linux core files
This allows you to read the same registers as you would for a live process. As the content of proc/pid/smaps is not included in the core file, we don't get the "ss" marker. The GCS region is stil in the list though.
1 parent 290899d commit c837597

File tree

5 files changed

+54
-0
lines changed

5 files changed

+54
-0
lines changed

lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@ RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch,
6969
if (fpmr_data.GetByteSize() >= sizeof(uint64_t))
7070
opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskFPMR);
7171

72+
DataExtractor gcs_data = getRegset(notes, arch.GetTriple(), AARCH64_GCS_Desc);
73+
struct __attribute__((packed)) gcs_regs {
74+
uint64_t features_enabled;
75+
uint64_t features_locked;
76+
uint64_t gcspr_e0;
77+
};
78+
if (gcs_data.GetByteSize() >= sizeof(gcs_regs))
79+
opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskGCS);
80+
7281
auto register_info_up =
7382
std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
7483
return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
@@ -136,6 +145,9 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
136145
if (m_register_info_up->IsFPMRPresent())
137146
m_fpmr_data = getRegset(notes, target_triple, AARCH64_FPMR_Desc);
138147

148+
if (m_register_info_up->IsGCSPresent())
149+
m_gcs_data = getRegset(notes, target_triple, AARCH64_GCS_Desc);
150+
139151
ConfigureRegisterContext();
140152
}
141153

@@ -330,6 +342,11 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
330342
assert(offset < m_mte_data.GetByteSize());
331343
value.SetFromMemoryData(*reg_info, m_mte_data.GetDataStart() + offset,
332344
reg_info->byte_size, lldb::eByteOrderLittle, error);
345+
} else if (IsGCS(reg)) {
346+
offset = reg_info->byte_offset - m_register_info_up->GetGCSOffset();
347+
assert(offset < m_gcs_data.GetByteSize());
348+
value.SetFromMemoryData(*reg_info, m_gcs_data.GetDataStart() + offset,
349+
reg_info->byte_size, lldb::eByteOrderLittle, error);
333350
} else if (IsSME(reg)) {
334351
// If you had SME in the process, active or otherwise, there will at least
335352
// be a ZA header. No header, no SME at all.

lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 {
6363
lldb_private::DataExtractor m_mte_data;
6464
lldb_private::DataExtractor m_zt_data;
6565
lldb_private::DataExtractor m_fpmr_data;
66+
lldb_private::DataExtractor m_gcs_data;
6667

6768
SVEState m_sve_state = SVEState::Unknown;
6869
uint16_t m_sve_vector_length = 0;

lldb/source/Plugins/Process/elf-core/RegisterUtilities.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ constexpr RegsetDesc AARCH64_FPMR_Desc[] = {
148148
{llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_FPMR},
149149
};
150150

151+
constexpr RegsetDesc AARCH64_GCS_Desc[] = {
152+
{llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_GCS},
153+
};
154+
151155
constexpr RegsetDesc PPC_VMX_Desc[] = {
152156
{llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},
153157
{llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},

lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,35 @@ def test_gcs_expression_enable_gcs(self):
358358
# consistent with the disabled -> enabled behaviour.
359359
enabled |= 1
360360
self.check_gcs_registers(enabled, locked, spr_el0)
361+
362+
@skipIfLLVMTargetMissing("AArch64")
363+
def test_gcs_core_file(self):
364+
# To re-generate the core file, build the test file and run it on a
365+
# machine with GCS enabled. Note that because the kernel decides where
366+
# the GCS is stored, the value of gcspr_el0 and which memory region it
367+
# points to may change between runs.
368+
369+
self.runCmd("target create --core corefile")
370+
371+
self.expect(
372+
"bt",
373+
substrs=["stop reason = SIGSEGV: control protection fault"],
374+
)
375+
376+
self.expect(
377+
"register read --all",
378+
substrs=[
379+
"Guarded Control Stack Registers:",
380+
"gcs_features_enabled = 0x0000000000000001",
381+
"gcs_features_locked = 0x0000000000000000",
382+
"gcspr_el0 = 0x0000ffffa83ffff0",
383+
],
384+
)
385+
386+
# Core files do not include /proc/pid/smaps, so we cannot see the
387+
# shadow stack "ss" flag. gcspr_el0 should at least point to some mapped
388+
# region.
389+
self.expect(
390+
"memory region $gcspr_el0",
391+
substrs=["[0x0000ffffa8000000-0x0000ffffa8400000) rw-"],
392+
)
24 KB
Binary file not shown.

0 commit comments

Comments
 (0)