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

View File

@ -1332,6 +1332,9 @@ class CallFrameInfo::Handler {
// should stop. // should stop.
virtual bool End() = 0; virtual bool End() = 0;
// The target architecture for the data.
virtual string Architecture() = 0;
// Handler functions for Linux C++ exception handling data. These are // Handler functions for Linux C++ exception handling data. These are
// only called if the data includes 'z' augmentation strings. // 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, MOCK_METHOD3(ValExpressionRule, bool(uint64_t address, int reg,
const string& expression)); const string& expression));
MOCK_METHOD0(End, bool()); MOCK_METHOD0(End, bool());
MOCK_METHOD0(Architecture, string());
MOCK_METHOD2(PersonalityRoutine, bool(uint64_t address, bool indirect)); MOCK_METHOD2(PersonalityRoutine, bool(uint64_t address, bool indirect));
MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64_t address, bool indirect)); MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64_t address, bool indirect));
MOCK_METHOD0(SignalHandler, bool()); MOCK_METHOD0(SignalHandler, bool());
@ -1539,6 +1540,8 @@ TEST_F(CFIInsn, DW_CFA_GNU_window_save) {
.D8(google_breakpad::DW_CFA_GNU_window_save) .D8(google_breakpad::DW_CFA_GNU_window_save)
.FinishEntry(); .FinishEntry();
EXPECT_CALL(handler, Architecture()).WillRepeatedly(Return("sparc"));
// Don't include all the rules in any particular sequence. // Don't include all the rules in any particular sequence.
// The caller's %o0-%o7 have become the callee's %i0-%i7. This is // 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; return true;
} }
string DwarfCFIToModule::Architecture() {
return module_->architecture();
}
void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) { void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
fprintf(stderr, "%s, section '%s': " fprintf(stderr, "%s, section '%s': "
"the call frame entry at offset 0x%zx refers to register %d," "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); const string& expression);
virtual bool End(); virtual bool End();
virtual string Architecture();
private: private:
// Return the name to use for register REG. // Return the name to use for register REG.
string RegisterName(int i); string RegisterName(int i);