[lldb][debugserver] Save and restore the SVE/SME register state (#134184)

debugserver isn't saving and restoring the SVE/SME register state around
inferior function calls.

Making arbitrary function calls while in Streaming SVE mode is generally
a poor idea because a NEON instruction can be hit and crash the
expression execution, which is how I missed this, but they should be
handled correctly if the user knows it is safe to do.

rdar://146886210
This commit is contained in:
Jason Molenda
2025-04-02 20:37:07 -07:00
committed by GitHub
parent 6a46c6c865
commit 4e40c7c4bd

View File

@@ -2952,8 +2952,15 @@ kern_return_t DNBArchMachARM64::SetRegisterState(int set) {
return err;
switch (set) {
case e_regSetALL:
return SetGPRState() | SetVFPState() | SetEXCState() | SetDBGState(false);
case e_regSetALL: {
kern_return_t ret =
SetGPRState() | SetVFPState() | SetEXCState() | SetDBGState(false);
if (CPUHasSME()) {
ret |= SetSVEState();
ret |= SetSMEState();
}
return ret;
}
case e_regSetGPR:
return SetGPRState();
case e_regSetVFP:
@@ -3119,9 +3126,20 @@ uint32_t DNBArchMachARM64::SaveRegisterState() {
"error: GPR regs failed to read: %u ",
kret);
} else if ((kret = GetVFPState(force)) != KERN_SUCCESS) {
DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () "
"error: %s regs failed to read: %u",
DNBLogThreadedIf(LOG_THREAD,
"DNBArchMachARM64::SaveRegisterState () "
"error: %s regs failed to read: %u",
"VFP", kret);
} else if (CPUHasSME() && (kret = SetSVEState() != KERN_SUCCESS)) {
DNBLogThreadedIf(LOG_THREAD,
"DNBArchMachARM64::SaveRegisterState () "
"error: %s regs failed to read: %u",
"SVE", kret);
} else if (CPUHasSME() && (kret = SetSMEState() != KERN_SUCCESS)) {
DNBLogThreadedIf(LOG_THREAD,
"DNBArchMachARM64::SaveRegisterState () "
"error: %s regs failed to read: %u",
"SME", kret);
} else {
const uint32_t save_id = GetNextRegisterStateSaveID();
m_saved_register_states[save_id] = m_state.context;
@@ -3144,11 +3162,26 @@ bool DNBArchMachARM64::RestoreRegisterState(uint32_t save_id) {
save_id, kret);
success = false;
} else if ((kret = SetVFPState()) != KERN_SUCCESS) {
DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState "
"(save_id = %u) error: %s regs failed to "
"write: %u",
DNBLogThreadedIf(LOG_THREAD,
"DNBArchMachARM64::RestoreRegisterState "
"(save_id = %u) error: %s regs failed to "
"write: %u",
save_id, "VFP", kret);
success = false;
} else if ((kret = SetSVEState()) != KERN_SUCCESS) {
DNBLogThreadedIf(LOG_THREAD,
"DNBArchMachARM64::RestoreRegisterState "
"(save_id = %u) error: %s regs failed to "
"write: %u",
save_id, "SVE", kret);
success = false;
} else if ((kret = SetSMEState()) != KERN_SUCCESS) {
DNBLogThreadedIf(LOG_THREAD,
"DNBArchMachARM64::RestoreRegisterState "
"(save_id = %u) error: %s regs failed to "
"write: %u",
save_id, "SME", kret);
success = false;
}
m_saved_register_states.erase(pos);
return success;