arm64: don't interpret DW_CFA_GNU_window_save

DW_CFA_AARCH64_negate_ra_state uses the same encoding as
DW_CFA_GNU_window_save. It is meant to indicate that x30/LR
has been signed, but breakpad does not require this information.

Bug: b/239086293
Change-Id: I5a17bd5e0673a3ff80a8c6e347013d66054314e8
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3781136
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Joshua Peraza 2022-07-21 17:09:21 -07:00
parent e467c59c68
commit afc8daa2de
5 changed files with 37 additions and 16 deletions

View File

@ -2721,23 +2721,32 @@ bool CallFrameInfo::State::DoInstruction() {
case DW_CFA_nop:
break;
// A SPARC register window save: Registers 8 through 15 (%o0-%o7)
// are saved in registers 24 through 31 (%i0-%i7), and registers
// 16 through 31 (%l0-%l7 and %i0-%i7) are saved at CFA offsets
// (0-15 * the register size). The register numbers must be
// hard-coded. A GNU extension, and not a pretty one.
// case DW_CFA_AARCH64_negate_ra_state
case DW_CFA_GNU_window_save: {
// Save %o0-%o7 in %i0-%i7.
for (int i = 8; i < 16; i++)
if (!DoRule(i, new RegisterRule(i + 16)))
return false;
// Save %l0-%l7 and %i0-%i7 at the CFA.
for (int i = 16; i < 32; i++)
// Assume that the byte reader's address size is the same as
// the architecture's register size. !@#%*^ hilarious.
if (!DoRule(i, new OffsetRule(Handler::kCFARegister,
(i - 16) * reader_->AddressSize())))
return false;
if (handler_->Architecture() == "arm64") {
// Indicates that the return address, x30 has been signed.
// Breakpad will speculatively remove pointer-authentication codes when
// interpreting return addresses, regardless of this bit.
} else if (handler_->Architecture() == "sparc" ||
handler_->Architecture() == "sparcv9") {
// A SPARC register window save: Registers 8 through 15 (%o0-%o7)
// are saved in registers 24 through 31 (%i0-%i7), and registers
// 16 through 31 (%l0-%l7 and %i0-%i7) are saved at CFA offsets
// (0-15 * the register size). The register numbers must be
// hard-coded. A GNU extension, and not a pretty one.
// Save %o0-%o7 in %i0-%i7.
for (int i = 8; i < 16; i++)
if (!DoRule(i, new RegisterRule(i + 16)))
return false;
// Save %l0-%l7 and %i0-%i7 at the CFA.
for (int i = 16; i < 32; i++)
// Assume that the byte reader's address size is the same as
// the architecture's register size. !@#%*^ hilarious.
if (!DoRule(i, new OffsetRule(Handler::kCFARegister,
(i - 16) * reader_->AddressSize())))
return false;
}
break;
}

View File

@ -1332,6 +1332,9 @@ class CallFrameInfo::Handler {
// should stop.
virtual bool End() = 0;
// The target architecture for the data.
virtual string Architecture() = 0;
// Handler functions for Linux C++ exception handling data. These are
// only called if the data includes 'z' augmentation strings.

View File

@ -114,6 +114,7 @@ class MockCallFrameInfoHandler: public CallFrameInfo::Handler {
MOCK_METHOD3(ValExpressionRule, bool(uint64_t address, int reg,
const string& expression));
MOCK_METHOD0(End, bool());
MOCK_METHOD0(Architecture, string());
MOCK_METHOD2(PersonalityRoutine, bool(uint64_t address, bool indirect));
MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64_t address, bool indirect));
MOCK_METHOD0(SignalHandler, bool());
@ -1539,6 +1540,8 @@ TEST_F(CFIInsn, DW_CFA_GNU_window_save) {
.D8(google_breakpad::DW_CFA_GNU_window_save)
.FinishEntry();
EXPECT_CALL(handler, Architecture()).WillRepeatedly(Return("sparc"));
// Don't include all the rules in any particular sequence.
// The caller's %o0-%o7 have become the callee's %i0-%i7. This is

View File

@ -264,6 +264,10 @@ bool DwarfCFIToModule::End() {
return true;
}
string DwarfCFIToModule::Architecture() {
return module_->architecture();
}
void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
fprintf(stderr, "%s, section '%s': "
"the call frame entry at offset 0x%zx refers to register %d,"

View File

@ -152,6 +152,8 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
const string& expression);
virtual bool End();
virtual string Architecture();
private:
// Return the name to use for register REG.
string RegisterName(int i);