libunwindstack: support for Armv8.3-A Pointer Authentication

This patch adds support for handling return addresses signed with
pointer authentication. It simply strips the authentication code
without verifying its correctness, and thus works with both A and B
keys and through key-change boundaries.

Additons:
  * DW_CFA_AARCH64_negate_ra_state: new CFA operation.
  * RA_SIGN_STATE: new pseudo register.
  * Pass the arch to DwarfCfa so that the new op is only executed
    on aarch64.

The stripping uses the xpaclri instruction. This is a hint space
instruction which is compatible with pre Armv8.3-A devices. For cases
where it cannot be used, a mask can be set instead.

Test: libunwindstack_test
      Without this patch all UnwindTest.* testcases should fail if
      compiled with Pointer Authentication.

The tests should be executed with both -mbranch-protection=pac-ret and
pac-ret+leaf flags so that either some or all functions have pointer
authentication instructions.

Change-Id: Id7c3f1d0e2fc7fccb19bd1430826264405a9df7c
diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h
index 569c17c..d627e15 100644
--- a/libunwindstack/DwarfCfa.h
+++ b/libunwindstack/DwarfCfa.h
@@ -31,6 +31,9 @@
 
 namespace unwindstack {
 
+// Forward declarations.
+enum ArchEnum : uint8_t;
+
 // DWARF Standard home: http://dwarfstd.org/
 // This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf
 // See section 6.4.2.1 for a description of the DW_CFA_xxx values.
@@ -72,7 +75,8 @@
   typedef typename std::make_signed<AddressType>::type SignedType;
 
  public:
-  DwarfCfa(DwarfMemory* memory, const DwarfFde* fde) : memory_(memory), fde_(fde) {}
+  DwarfCfa(DwarfMemory* memory, const DwarfFde* fde, ArchEnum arch)
+      : memory_(memory), fde_(fde), arch_(arch) {}
   virtual ~DwarfCfa() = default;
 
   bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset,
@@ -99,6 +103,7 @@
   DwarfErrorData last_error_;
   DwarfMemory* memory_;
   const DwarfFde* fde_;
+  ArchEnum arch_;
 
   AddressType cur_pc_;
   const dwarf_loc_regs_t* cie_loc_regs_ = nullptr;
@@ -128,6 +133,7 @@
   bool cfa_val_offset_sf(dwarf_loc_regs_t*);
   bool cfa_val_expression(dwarf_loc_regs_t*);
   bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*);
+  bool cfa_aarch64_negate_ra_state(dwarf_loc_regs_t*);
 
   using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*);
   constexpr static process_func kCallbackTable[64] = {
@@ -221,8 +227,9 @@
       nullptr,
       // 0x2c illegal cfa
       nullptr,
-      // 0x2d DW_CFA_GNU_window_save (Treat this as illegal)
-      nullptr,
+      // 0x2d DW_CFA_AARCH64_negate_ra_state (aarch64 only)
+      // DW_CFA_GNU_window_save on other architectures.
+      &DwarfCfa::cfa_aarch64_negate_ra_state,
       // 0x2e DW_CFA_GNU_args_size
       &DwarfCfa::cfa_nop,
       // 0x2f DW_CFA_GNU_negative_offset_extended