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>
diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc
index 6bd2614..33a63fc 100644
--- a/src/common/dwarf/dwarf2reader.cc
+++ b/src/common/dwarf/dwarf2reader.cc
@@ -2721,23 +2721,32 @@
     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;
     }
 
diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h
index 97e5fea..0526ee7 100644
--- a/src/common/dwarf/dwarf2reader.h
+++ b/src/common/dwarf/dwarf2reader.h
@@ -1332,6 +1332,9 @@
   // 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.
 
diff --git a/src/common/dwarf/dwarf2reader_cfi_unittest.cc b/src/common/dwarf/dwarf2reader_cfi_unittest.cc
index 5f70379..686ecb1 100644
--- a/src/common/dwarf/dwarf2reader_cfi_unittest.cc
+++ b/src/common/dwarf/dwarf2reader_cfi_unittest.cc
@@ -114,6 +114,7 @@
   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 @@
       .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
diff --git a/src/common/dwarf_cfi_to_module.cc b/src/common/dwarf_cfi_to_module.cc
index 739b9fe..794bab5 100644
--- a/src/common/dwarf_cfi_to_module.cc
+++ b/src/common/dwarf_cfi_to_module.cc
@@ -264,6 +264,10 @@
   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,"
diff --git a/src/common/dwarf_cfi_to_module.h b/src/common/dwarf_cfi_to_module.h
index 3e2e6ff..b6d5fce 100644
--- a/src/common/dwarf_cfi_to_module.h
+++ b/src/common/dwarf_cfi_to_module.h
@@ -152,6 +152,8 @@
                                  const string& expression);
   virtual bool End();
 
+  virtual string Architecture();
+
  private:
   // Return the name to use for register REG.
   string RegisterName(int i);