From: Guo Ren <guoren@linux.alibaba.com>
Date: Wed, 29 Jun 2022 16:46:46 +0800
Subject: Add riscv64 support

This patch contains the dwarf unwind support for 64bit risc-v.

    * DwarfCfa.cpp (cfa_def_cfa_register): setup register if CFA_REG is
    not setup for riscv64
    * Elf.cpp (GetRelPc): convert offset to virtual address for riscv64.
    * ElfInterface.cpp (GetVirtAddrFromOffset): New for riscv64.
    * RegsRiscv64.cpp (StepIfSignalHandler): Fix signal frame check.
    libunwindstack/include/unwindstack/
    * ElfInterface.h (GetVirtAddrFromOffset): New for riscv64.
    libunwindstack/tests/
    * DwarfCfaTest.cpp (cfa_def_cfa_register): ok for riscv64.
    * RegsStepIfSignalHandlerTest.cpp (riscv64_step_if_signal_handler): Fix
    testcase for riscv64

Test: Builds.
Test: All unit tests pass.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Lifang Xia <lifang_xia@linux.alibaba.com>
Signed-off-by: Mao Han <han_mao@linux.alibaba.com>
Change-Id: Ib21ddf23cc83f332af202df7bffcaceec16063e0
---
 system/core/libunwindstack/Android.bp              |   1 +
 system/core/libunwindstack/Elf.cpp                 |   2 +
 system/core/libunwindstack/Regs.cpp                |  10 ++
 system/core/libunwindstack/RegsRiscv64.cpp         | 156 +++++++++++++++++++++
 .../core/libunwindstack/include/unwindstack/Elf.h  |   5 +
 .../include/unwindstack/MachineRiscv64.h           |  59 ++++++++
 .../include/unwindstack/RegsGetLocal.h             |  43 ++++++
 .../include/unwindstack/RegsRiscv64.h              |  59 ++++++++
 .../include/unwindstack/UcontextRiscv64.h          |  80 +++++++++++
 .../include/unwindstack/UserRiscv64.h              |  37 +++++
 system/core/libunwindstack/tools/unwind.cpp        |   3 +
 .../core/libunwindstack/tools/unwind_symbols.cpp   |   3 +
 12 files changed, 458 insertions(+)
 create mode 100644 system/core/libunwindstack/RegsRiscv64.cpp
 create mode 100644 system/core/libunwindstack/include/unwindstack/MachineRiscv64.h
 create mode 100644 system/core/libunwindstack/include/unwindstack/RegsRiscv64.h
 create mode 100644 system/core/libunwindstack/include/unwindstack/UcontextRiscv64.h
 create mode 100644 system/core/libunwindstack/include/unwindstack/UserRiscv64.h

diff --git a/system/core/libunwindstack/Android.bp b/system/core/libunwindstack/Android.bp
index 3695f72..f1f9c68 100644
--- a/system/core/libunwindstack/Android.bp
+++ b/system/core/libunwindstack/Android.bp
@@ -70,6 +70,7 @@ cc_library {
         "RegsArm64.cpp",
         "RegsX86.cpp",
         "RegsX86_64.cpp",
+        "RegsRiscv64.cpp",
         "RegsMips.cpp",
         "RegsMips64.cpp",
         "Unwinder.cpp",
diff --git a/system/core/libunwindstack/Elf.cpp b/system/core/libunwindstack/Elf.cpp
index f01b092..3c2088b 100644
--- a/system/core/libunwindstack/Elf.cpp
+++ b/system/core/libunwindstack/Elf.cpp
@@ -290,6 +290,8 @@ ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
       arch_ = ARCH_X86_64;
     } else if (e_machine == EM_MIPS) {
       arch_ = ARCH_MIPS64;
+    } else if (e_machine == EM_RISCV) {
+      arch_ = ARCH_RISCV64;
     } else {
       // Unsupported.
       ALOGI("64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = %d\n",
diff --git a/system/core/libunwindstack/Regs.cpp b/system/core/libunwindstack/Regs.cpp
index c7dec52..447a554 100644
--- a/system/core/libunwindstack/Regs.cpp
+++ b/system/core/libunwindstack/Regs.cpp
@@ -27,12 +27,14 @@
 #include <unwindstack/RegsArm64.h>
 #include <unwindstack/RegsMips.h>
 #include <unwindstack/RegsMips64.h>
+#include <unwindstack/RegsRiscv64.h>
 #include <unwindstack/RegsX86.h>
 #include <unwindstack/RegsX86_64.h>
 #include <unwindstack/UserArm.h>
 #include <unwindstack/UserArm64.h>
 #include <unwindstack/UserMips.h>
 #include <unwindstack/UserMips64.h>
+#include <unwindstack/UserRiscv64.h>
 #include <unwindstack/UserX86.h>
 #include <unwindstack/UserX86_64.h>
 
@@ -67,6 +69,8 @@ Regs* Regs::RemoteGet(pid_t pid) {
     return RegsMips::Read(buffer.data());
   case sizeof(mips64_user_regs):
     return RegsMips64::Read(buffer.data());
+  case sizeof(riscv64_user_regs):
+    return RegsRiscv64::Read(buffer.data());
   }
   return nullptr;
 }
@@ -85,6 +89,8 @@ Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) {
       return RegsMips::CreateFromUcontext(ucontext);
     case ARCH_MIPS64:
       return RegsMips64::CreateFromUcontext(ucontext);
+    case ARCH_RISCV64:
+      return RegsRiscv64::CreateFromUcontext(ucontext);
     case ARCH_UNKNOWN:
     default:
       return nullptr;
@@ -104,6 +110,8 @@ ArchEnum Regs::CurrentArch() {
   return ARCH_MIPS;
 #elif defined(__mips__) && defined(__LP64__)
   return ARCH_MIPS64;
+#elif defined(__riscv)
+  return ARCH_RISCV64;
 #else
   abort();
 #endif
@@ -123,6 +131,8 @@ Regs* Regs::CreateFromLocal() {
   regs = new RegsMips();
 #elif defined(__mips__) && defined(__LP64__)
   regs = new RegsMips64();
+#elif defined(__riscv)
+  regs = new RegsRiscv64();
 #else
   abort();
 #endif
diff --git a/system/core/libunwindstack/RegsRiscv64.cpp b/system/core/libunwindstack/RegsRiscv64.cpp
new file mode 100644
index 0000000..887762a
--- /dev/null
+++ b/system/core/libunwindstack/RegsRiscv64.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MachineRiscv64.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsRiscv64.h>
+#include <unwindstack/UcontextRiscv64.h>
+#include <unwindstack/UserRiscv64.h>
+
+namespace unwindstack {
+
+RegsRiscv64::RegsRiscv64()
+    : RegsImpl<uint64_t>(RISCV64_REG_MAX, Location(LOCATION_REGISTER, RISCV64_REG_RA)) {}
+
+ArchEnum RegsRiscv64::Arch() {
+  return ARCH_RISCV64;
+}
+
+uint64_t RegsRiscv64::pc() {
+  return regs_[RISCV64_REG_PC];
+}
+
+uint64_t RegsRiscv64::sp() {
+  return regs_[RISCV64_REG_SP];
+}
+
+void RegsRiscv64::set_pc(uint64_t pc) {
+  regs_[RISCV64_REG_PC] = pc;
+}
+
+void RegsRiscv64::set_sp(uint64_t sp) {
+  regs_[RISCV64_REG_SP] = sp;
+}
+
+uint64_t RegsRiscv64::GetPcAdjustment(uint64_t rel_pc, Elf*) {
+  if (rel_pc < 8) {
+    return 0;
+  }
+  // For now, just assume no compact branches
+  return 8;
+}
+
+bool RegsRiscv64::SetPcFromReturnAddress(Memory*) {
+  uint64_t ra = regs_[RISCV64_REG_RA];
+  if (regs_[RISCV64_REG_PC] == ra) {
+    return false;
+  }
+
+  regs_[RISCV64_REG_PC] = ra;
+  return true;
+}
+
+void RegsRiscv64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("pc", regs_[RISCV64_REG_PC]);
+  fn("ra", regs_[RISCV64_REG_RA]);
+  fn("sp", regs_[RISCV64_REG_SP]);
+  fn("gp", regs_[RISCV64_REG_GP]);
+  fn("tp", regs_[RISCV64_REG_TP]);
+  fn("t0", regs_[RISCV64_REG_T0]);
+  fn("t1", regs_[RISCV64_REG_T1]);
+  fn("t2", regs_[RISCV64_REG_T2]);
+  fn("t3", regs_[RISCV64_REG_T3]);
+  fn("t4", regs_[RISCV64_REG_T4]);
+  fn("t5", regs_[RISCV64_REG_T5]);
+  fn("t6", regs_[RISCV64_REG_T6]);
+  fn("s0", regs_[RISCV64_REG_S0]);
+  fn("s1", regs_[RISCV64_REG_S1]);
+  fn("s2", regs_[RISCV64_REG_S2]);
+  fn("s3", regs_[RISCV64_REG_S3]);
+  fn("s4", regs_[RISCV64_REG_S4]);
+  fn("s5", regs_[RISCV64_REG_S5]);
+  fn("s6", regs_[RISCV64_REG_S6]);
+  fn("s7", regs_[RISCV64_REG_S7]);
+  fn("s8", regs_[RISCV64_REG_S8]);
+  fn("s9", regs_[RISCV64_REG_S9]);
+  fn("s10", regs_[RISCV64_REG_S10]);
+  fn("s11", regs_[RISCV64_REG_S11]);
+  fn("a0", regs_[RISCV64_REG_A0]);
+  fn("a1", regs_[RISCV64_REG_A1]);
+  fn("a2", regs_[RISCV64_REG_A2]);
+  fn("a3", regs_[RISCV64_REG_A3]);
+  fn("a4", regs_[RISCV64_REG_A4]);
+  fn("a5", regs_[RISCV64_REG_A5]);
+  fn("a6", regs_[RISCV64_REG_A6]);
+  fn("a7", regs_[RISCV64_REG_A7]);
+}
+
+Regs* RegsRiscv64::Read(void* remote_data) {
+  riscv64_user_regs* user = reinterpret_cast<riscv64_user_regs*>(remote_data);
+
+  RegsRiscv64* regs = new RegsRiscv64();
+  memcpy(regs->RawData(), &user->regs[0], RISCV64_REG_MAX * sizeof(uint64_t));
+  // uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
+  return regs;
+}
+
+Regs* RegsRiscv64::CreateFromUcontext(void* ucontext) {
+  riscv64_ucontext_t* riscv64_ucontext = reinterpret_cast<riscv64_ucontext_t*>(ucontext);
+
+  RegsRiscv64* regs = new RegsRiscv64();
+  memcpy(regs->RawData(), &riscv64_ucontext->uc_mcontext.__gregs[0],
+         RISCV64_REG_MAX * sizeof(uint64_t));
+  return regs;
+}
+
+bool RegsRiscv64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
+    return false;
+  }
+  // Look for the kernel sigreturn function.
+  // __kernel_rt_sigreturn:
+  // li a7, __NR_rt_sigreturn
+  // scall
+
+  const uint8_t li_scall[] = {0x93, 0x08, 0xb0, 0x08, 0x73, 0x00, 0x00, 0x00};
+  if (memcmp(&data, &li_scall, 8) != 0) {
+    return false;
+  }
+
+  // SP + sizeof(siginfo_t) + uc_mcontext offset + PC offset.
+  if (!process_memory->ReadFully(regs_[RISCV64_REG_SP] + 0x80 + 0xb0 + 0x00, regs_.data(),
+                                 sizeof(uint64_t) * (RISCV64_REG_MAX))) {
+    return false;
+  }
+  return true;
+}
+
+Regs* RegsRiscv64::Clone() {
+  return new RegsRiscv64(*this);
+}
+
+}  // namespace unwindstack
diff --git a/system/core/libunwindstack/include/unwindstack/Elf.h b/system/core/libunwindstack/include/unwindstack/Elf.h
index 472ed92..88fa0ff 100644
--- a/system/core/libunwindstack/include/unwindstack/Elf.h
+++ b/system/core/libunwindstack/include/unwindstack/Elf.h
@@ -32,6 +32,10 @@
 #define EM_AARCH64 183
 #endif
 
+#if !defined(EM_RISCV)
+#define EM_RISCV 243
+#endif
+
 namespace unwindstack {
 
 // Forward declaration.
@@ -46,6 +50,7 @@ enum ArchEnum : uint8_t {
   ARCH_X86_64,
   ARCH_MIPS,
   ARCH_MIPS64,
+  ARCH_RISCV64,
 };
 
 class Elf {
diff --git a/system/core/libunwindstack/include/unwindstack/MachineRiscv64.h b/system/core/libunwindstack/include/unwindstack/MachineRiscv64.h
new file mode 100644
index 0000000..397e680
--- /dev/null
+++ b/system/core/libunwindstack/include/unwindstack/MachineRiscv64.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum Riscv64Reg : uint16_t {
+  RISCV64_REG_PC,
+  RISCV64_REG_RA,
+  RISCV64_REG_SP,
+  RISCV64_REG_GP,
+  RISCV64_REG_TP,
+  RISCV64_REG_T0,
+  RISCV64_REG_T1,
+  RISCV64_REG_T2,
+  RISCV64_REG_S0,
+  RISCV64_REG_S1,
+  RISCV64_REG_A0,
+  RISCV64_REG_A1,
+  RISCV64_REG_A2,
+  RISCV64_REG_A3,
+  RISCV64_REG_A4,
+  RISCV64_REG_A5,
+  RISCV64_REG_A6,
+  RISCV64_REG_A7,
+  RISCV64_REG_S2,
+  RISCV64_REG_S3,
+  RISCV64_REG_S4,
+  RISCV64_REG_S5,
+  RISCV64_REG_S6,
+  RISCV64_REG_S7,
+  RISCV64_REG_S8,
+  RISCV64_REG_S9,
+  RISCV64_REG_S10,
+  RISCV64_REG_S11,
+  RISCV64_REG_T3,
+  RISCV64_REG_T4,
+  RISCV64_REG_T5,
+  RISCV64_REG_T6,
+  RISCV64_REG_MAX,
+};
+
+}  // namespace unwindstack
diff --git a/system/core/libunwindstack/include/unwindstack/RegsGetLocal.h b/system/core/libunwindstack/include/unwindstack/RegsGetLocal.h
index f0b5e3a..698eba2 100644
--- a/system/core/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/system/core/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -81,6 +81,49 @@ inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) {
       : "x12", "x13", "memory");
 }
 
+#elif defined(__riscv)
+
+inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) {
+  asm volatile(
+      "1:\n"
+      "sd ra, 8(%[base])\n"
+      "sd sp, 16(%[base])\n"
+      "sd gp, 24(%[base])\n"
+      "sd tp, 32(%[base])\n"
+      "sd t0, 40(%[base])\n"
+      "sd t1, 48(%[base])\n"
+      "sd t2, 56(%[base])\n"
+      "sd s0, 64(%[base])\n"
+      "sd s1, 72(%[base])\n"
+      "sd a0, 80(%[base])\n"
+      "sd a1, 88(%[base])\n"
+      "sd a2, 96(%[base])\n"
+      "sd a3, 104(%[base])\n"
+      "sd a4, 112(%[base])\n"
+      "sd a5, 120(%[base])\n"
+      "sd a6, 128(%[base])\n"
+      "sd a7, 136(%[base])\n"
+      "sd s2, 144(%[base])\n"
+      "sd s3, 152(%[base])\n"
+      "sd s4, 160(%[base])\n"
+      "sd s5, 168(%[base])\n"
+      "sd s6, 176(%[base])\n"
+      "sd s7, 184(%[base])\n"
+      "sd s8, 192(%[base])\n"
+      "sd s9, 200(%[base])\n"
+      "sd s10, 208(%[base])\n"
+      "sd s11, 216(%[base])\n"
+      "sd t3, 224(%[base])\n"
+      "sd t4, 232(%[base])\n"
+      "sd t5, 240(%[base])\n"
+      "sd t6, 248(%[base])\n"
+      "la t1, 1b\n"
+      "sd t1, 0(%[base])\n"
+      : [base] "+r"(reg_data)
+      :
+      : "t1", "memory");
+}
+
 #elif defined(__i386__) || defined(__x86_64__) || defined(__mips__)
 
 extern "C" void AsmGetRegs(void* regs);
diff --git a/system/core/libunwindstack/include/unwindstack/RegsRiscv64.h b/system/core/libunwindstack/include/unwindstack/RegsRiscv64.h
new file mode 100644
index 0000000..eb09397
--- /dev/null
+++ b/system/core/libunwindstack/include/unwindstack/RegsRiscv64.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+
+class RegsRiscv64 : public RegsImpl<uint64_t> {
+ public:
+  RegsRiscv64();
+  virtual ~RegsRiscv64() = default;
+
+  ArchEnum Arch() override final;
+
+  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
+
+  void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  uint64_t pc() override;
+  uint64_t sp() override;
+
+  void set_pc(uint64_t pc) override;
+  void set_sp(uint64_t sp) override;
+
+  Regs* Clone() override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
diff --git a/system/core/libunwindstack/include/unwindstack/UcontextRiscv64.h b/system/core/libunwindstack/include/unwindstack/UcontextRiscv64.h
new file mode 100644
index 0000000..c6c82b1
--- /dev/null
+++ b/system/core/libunwindstack/include/unwindstack/UcontextRiscv64.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+typedef uint64_t __riscv_mc_gp_state[32];  // unsigned long
+
+struct __riscv_mc_f_ext_state {
+  uint32_t __f[32];
+  uint32_t __fcsr;
+};
+
+struct __riscv_mc_d_ext_state {
+  uint64_t __f[32];
+  uint32_t __fcsr;
+};
+
+struct __riscv_mc_q_ext_state {
+  uint64_t __f[64] __attribute__((__aligned__(16)));
+  uint32_t __fcsr;
+  uint32_t __reserved[3];
+};
+
+union __riscv_mc_fp_state {
+  struct __riscv_mc_f_ext_state __f;
+  struct __riscv_mc_d_ext_state __d;
+  struct __riscv_mc_q_ext_state __q;
+};
+
+struct __riscv_stack_t {
+  uint64_t ss_sp;
+  int32_t ss_flags;
+  uint64_t ss_size;
+};
+
+struct riscv64_sigset_t {
+  uint64_t sig;  // unsigned long
+};
+
+struct riscv64_mcontext_t {
+  __riscv_mc_gp_state __gregs;
+  union __riscv_mc_fp_state __fpregs;
+};
+
+struct riscv64_ucontext_t {
+  uint64_t uc_flags;  // unsigned long
+  struct riscv64_ucontext_t* uc_link;
+  __riscv_stack_t uc_stack;
+  riscv64_sigset_t uc_sigmask;
+  /* The kernel adds extra padding here to allow sigset_t to grow. */
+  int8_t __padding[128 - sizeof(riscv64_sigset_t)];  // char
+  riscv64_mcontext_t uc_mcontext;
+};
diff --git a/system/core/libunwindstack/include/unwindstack/UserRiscv64.h b/system/core/libunwindstack/include/unwindstack/UserRiscv64.h
new file mode 100644
index 0000000..1e91228
--- /dev/null
+++ b/system/core/libunwindstack/include/unwindstack/UserRiscv64.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace unwindstack {
+
+struct riscv64_user_regs {
+  uint64_t regs[32];
+};
+
+}  // namespace unwindstack
diff --git a/system/core/libunwindstack/tools/unwind.cpp b/system/core/libunwindstack/tools/unwind.cpp
index 1812e50..ae20891 100644
--- a/system/core/libunwindstack/tools/unwind.cpp
+++ b/system/core/libunwindstack/tools/unwind.cpp
@@ -83,6 +83,9 @@ void DoUnwind(pid_t pid) {
     case unwindstack::ARCH_MIPS64:
       printf("mips64");
       break;
+    case unwindstack::ARCH_RISCV64:
+      printf("riscv64");
+      break;
     default:
       printf("unknown\n");
       return;
diff --git a/system/core/libunwindstack/tools/unwind_symbols.cpp b/system/core/libunwindstack/tools/unwind_symbols.cpp
index 8df2284..976db56 100644
--- a/system/core/libunwindstack/tools/unwind_symbols.cpp
+++ b/system/core/libunwindstack/tools/unwind_symbols.cpp
@@ -77,6 +77,9 @@ int main(int argc, char** argv) {
     case EM_AARCH64:
       printf("ABI: arm64\n");
       break;
+    case EM_RISCV:
+      printf("ABI: riscv64\n");
+      break;
     case EM_386:
       printf("ABI: x86\n");
       break;
