blob: 4669f89d073083ac8c992225fba4f9c9e3a175f1 [file] [log] [blame]
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;