--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ * Authors: Adrian Szyndela <adrian.s@samsung.com>
+ * Ćukasz Stelmach <l.stelmach@samsung.com>
+ * Mateusz Moscicki <m.moscicki@samsung.com>
+ */
+/**
+ * @file crash-stack-riscv64.c
+ * @brief unwinding call stacks, functions specific for riscv64
+ */
+#include "crash-stack.h"
+#include "shared/log.h"
+#include "shared/util.h"
+
+#include <elf.h>
+#include <sys/user.h>
+#include <string.h>
+#include <stdio.h>
+#include <asm/ptrace.h>
+
+#define REG_RISCV_S0 8
+#define REG_RISCV_RA 1
+
+static struct user_regs_struct g_registers; ///< static storage for registers
+
+/**
+ * @brief Important registers for unwinding stack on riscv64
+ */
+struct Regs {
+ Elf64_Addr pc; ///< register: program counter
+ Elf64_Addr ra; ///< x1 register contains return address
+ Elf64_Addr sp; ///< x2 register: stack pointer
+ Elf64_Addr s0; ///< x8 register contains frame pointer
+};
+
+typedef struct Regs Regs; ///< convenience type definition
+static Regs g_regs; ///< static storage for target register values
+
+void *_crash_stack_get_memory_for_registers(size_t *size)
+{
+ if (NULL != size)
+ *size = sizeof(g_registers);
+ return &g_registers;
+}
+
+void _crash_stack_set_registers(void *regbuf)
+{
+ struct user_regs_struct *regs = regbuf;
+
+ memcpy(_get_place_for_register_value("pc", REG_RISCV_PC), ®s->pc, sizeof(regs->pc));
+ memcpy(_get_place_for_register_value("ra", REG_RISCV_RA), ®s->ra, sizeof(regs->ra));
+ memcpy(_get_place_for_register_value("sp", REG_RISCV_SP), ®s->sp, sizeof(regs->sp));
+ memcpy(_get_place_for_register_value("s0", REG_RISCV_S0), ®s->s0, sizeof(regs->s0));
+}
+
+void *_get_place_for_register_value(const char *regname, int regnum)
+{
+ if (strcmp(regname, "pc") == 0 || REG_RISCV_PC == regnum)
+ return &g_regs.pc;
+ else if (strcmp(regname, "ra") == 0 || REG_RISCV_RA == regnum)
+ return &g_regs.ra;
+ else if (strcmp(regname, "sp") == 0 || REG_RISCV_SP == regnum)
+ return &g_regs.sp;
+ else if (strcmp(regname, "s0") == 0 || REG_RISCV_S0 == regnum)
+ return &g_regs.s0;
+ return NULL;
+}
+
+unsigned long _get_register_value(int n)
+{
+ // return g_registers.regs[n];
+ const static int reg_map[] = {
+ [UNW_RISCV_X0] = offsetof(struct user_regs_struct, pc) / sizeof(long),
+ [UNW_RISCV_X1] = offsetof(struct user_regs_struct, ra) / sizeof(long),
+ [UNW_RISCV_X2] = offsetof(struct user_regs_struct, sp) / sizeof(long),
+ [UNW_RISCV_X3] = offsetof(struct user_regs_struct, gp) / sizeof(long),
+ [UNW_RISCV_X4] = offsetof(struct user_regs_struct, tp) / sizeof(long),
+ [UNW_RISCV_X5] = offsetof(struct user_regs_struct, t0) / sizeof(long),
+ [UNW_RISCV_X6] = offsetof(struct user_regs_struct, t1) / sizeof(long),
+ [UNW_RISCV_X7] = offsetof(struct user_regs_struct, t2) / sizeof(long),
+ [UNW_RISCV_X8] = offsetof(struct user_regs_struct, s0) / sizeof(long),
+ [UNW_RISCV_X9] = offsetof(struct user_regs_struct, s1) / sizeof(long),
+ [UNW_RISCV_X10] = offsetof(struct user_regs_struct, a0) / sizeof(long),
+ [UNW_RISCV_X11] = offsetof(struct user_regs_struct, a1) / sizeof(long),
+ [UNW_RISCV_X12] = offsetof(struct user_regs_struct, a2) / sizeof(long),
+ [UNW_RISCV_X13] = offsetof(struct user_regs_struct, a3) / sizeof(long),
+ [UNW_RISCV_X14] = offsetof(struct user_regs_struct, a4) / sizeof(long),
+ [UNW_RISCV_X15] = offsetof(struct user_regs_struct, a5) / sizeof(long),
+ [UNW_RISCV_X16] = offsetof(struct user_regs_struct, a6) / sizeof(long),
+ [UNW_RISCV_X17] = offsetof(struct user_regs_struct, a7) / sizeof(long),
+ [UNW_RISCV_X18] = offsetof(struct user_regs_struct, s2) / sizeof(long),
+ [UNW_RISCV_X19] = offsetof(struct user_regs_struct, s3) / sizeof(long),
+ [UNW_RISCV_X20] = offsetof(struct user_regs_struct, s4) / sizeof(long),
+ [UNW_RISCV_X21] = offsetof(struct user_regs_struct, s5) / sizeof(long),
+ [UNW_RISCV_X22] = offsetof(struct user_regs_struct, s6) / sizeof(long),
+ [UNW_RISCV_X23] = offsetof(struct user_regs_struct, s7) / sizeof(long),
+ [UNW_RISCV_X24] = offsetof(struct user_regs_struct, s8) / sizeof(long),
+ [UNW_RISCV_X25] = offsetof(struct user_regs_struct, s9) / sizeof(long),
+ [UNW_RISCV_X26] = offsetof(struct user_regs_struct, s10) / sizeof(long),
+ [UNW_RISCV_X27] = offsetof(struct user_regs_struct, s11) / sizeof(long),
+ [UNW_RISCV_X28] = offsetof(struct user_regs_struct, t3) / sizeof(long),
+ [UNW_RISCV_X29] = offsetof(struct user_regs_struct, t4) / sizeof(long),
+ [UNW_RISCV_X30] = offsetof(struct user_regs_struct, t5) / sizeof(long),
+ [UNW_RISCV_X31] = offsetof(struct user_regs_struct, t6) / sizeof(long),
+ };
+ n = reg_map[n];
+ return ((elf_greg_t*)&g_registers)[n];
+}
+
+void _crash_stack_print_regs(json_object *jobj)
+{
+ json_object *j_regs = json_object_new_array();
+
+ struct reg {
+ const char *name;
+ unsigned long long int value;
+ } regs[] = {
+ {"pc", g_registers.pc},
+ {"ra", g_registers.ra},
+ {"sp", g_registers.sp},
+ {"gp", g_registers.gp},
+ {"tp", g_registers.tp},
+ {"t0", g_registers.t0},
+ {"t1", g_registers.t1},
+ {"t2", g_registers.t2},
+ {"s0", g_registers.s0},
+ {"s1", g_registers.s1},
+ {"a0", g_registers.a0},
+ {"a1", g_registers.a1},
+ {"a2", g_registers.a2},
+ {"a3", g_registers.a3},
+ {"a4", g_registers.a4},
+ {"a5", g_registers.a5},
+ {"a6", g_registers.a6},
+ {"a7", g_registers.a7},
+ {"s2", g_registers.s2},
+ {"s3", g_registers.s3},
+ {"s4", g_registers.s4},
+ {"s5", g_registers.s5},
+ {"s6", g_registers.s6},
+ {"s7", g_registers.s7},
+ {"s8", g_registers.s8},
+ {"s9", g_registers.s9},
+ {"s10", g_registers.s10},
+ {"s11", g_registers.s11},
+ {"t3", g_registers.t3},
+ {"t4", g_registers.t4},
+ {"t5", g_registers.t5},
+ {"t6", g_registers.t6},
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(regs); i++) {
+ char value_str[16+3];
+ if (sprintf(value_str, "0x%016llx", regs[i].value) == -1) {
+ _E("Cannot print register value: %m");
+ continue;
+ }
+ ADD_REG_TO_JSON_ARRAY(j_regs, regs[i].name, value_str);
+ }
+
+ json_object_object_add(jobj, K_REGISTERS, j_regs);
+}