Add support for RISC-V 35/285135/4
authorMateusz Moscicki <m.moscicki2@partner.samsung.com>
Thu, 1 Dec 2022 11:34:48 +0000 (12:34 +0100)
committerMateusz Moscicki <m.moscicki2@partner.samsung.com>
Wed, 7 Dec 2022 12:12:56 +0000 (13:12 +0100)
Change-Id: Id1cbadf09b55f7da416833981b0e14ce6202cd7e

12 files changed:
src/crash-manager/dbus_notify.c
src/crash-stack/CMakeLists.txt
src/crash-stack/crash-stack-riscv64.c [new file with mode: 0644]
src/crash-stack/crash-stack-stub.c
src/crash-stack/crash-stack.h
src/crash-stack/unwind.c
src/livedumper/core.hpp
src/livedumper/helpers.hpp
src/livedumper/livedumper.hpp
src/livedumper/main.cpp
src/livedumper/note.hpp
tests/test1.c

index 81f82f0..eec8a0a 100644 (file)
@@ -20,6 +20,7 @@
 #include <sys/mman.h>
 #include <sys/procfs.h>
 #include <unistd.h>
+#include <asm/ptrace.h>
 
 #define CRASH_BUS_NAME          "org.tizen.system.crash"
 #define CRASH_OBJECT_PATH       "/Org/Tizen/System/Crash"
@@ -77,7 +78,7 @@ static int _get_important_registers(int fd, struct RegInfo **reg_info)
 
 #if (defined __i386__) || (defined __x86_64__)
        count = 1;
-#elif (defined __arm__) || (defined __aarch64__)
+#elif (defined __arm__) || (defined __aarch64__) || ((defined __riscv) && __riscv_xlen == 64)
        count = 2;
 #endif
 
@@ -126,6 +127,16 @@ static int _get_important_registers(int fd, struct RegInfo **reg_info)
                goto strdup_error;
        reginfo[1].value = (long long int)g_registers->regs[AARCH64_REG_LR];
 
+#elif defined(__riscv) && __riscv_xlen == 64
+
+       struct user_regs_struct *g_registers = (struct user_regs_struct*)prstatus->pr_reg;
+
+       if ((reginfo[0].name = strdup("riscv.pc")) == NULL)
+               goto strdup_error;
+       reginfo[0].value = (long long int)g_registers->pc;
+       if ((reginfo[1].name = strdup("riscv.ra")) == NULL)
+               goto strdup_error;
+       reginfo[1].value = (long long int)g_registers->ra;
 #endif // (defined __i386__) || (defined __x86_64__)
 
 out:
@@ -196,7 +207,7 @@ static GVariant *build_message_data(const struct NotifyParams *notify_params, co
                g_variant_builder_open(&md_builder, G_VARIANT_TYPE("{sv}"));
 
                g_variant_builder_add(&md_builder, "s", reg_info[i].name);
-#if (defined __x86_64__) || (defined __aarch64__)
+#if (defined __x86_64__) || (defined __aarch64__) || ((defined __riscv) && __riscv_xlen == 64)
                g_variant_builder_add(&md_builder, "v", g_variant_new_uint64(reg_info[i].value));
 #else
                g_variant_builder_add(&md_builder, "v", g_variant_new_uint32(reg_info[i].value));
index d2a8dd8..6e00e88 100644 (file)
@@ -16,7 +16,8 @@ elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l")
 elseif ((${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
      OR (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686"))
   set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-x86.c)
-
+elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "riscv64")
+  set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-riscv64.c)
 else()
   set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-stub.c)
 endif()
diff --git a/src/crash-stack/crash-stack-riscv64.c b/src/crash-stack/crash-stack-riscv64.c
new file mode 100644 (file)
index 0000000..084fee9
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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), &regs->pc, sizeof(regs->pc));
+  memcpy(_get_place_for_register_value("ra", REG_RISCV_RA), &regs->ra, sizeof(regs->ra));
+  memcpy(_get_place_for_register_value("sp", REG_RISCV_SP), &regs->sp, sizeof(regs->sp));
+  memcpy(_get_place_for_register_value("s0", REG_RISCV_S0), &regs->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);
+}
index ca1429c..b6ffbae 100644 (file)
@@ -1,3 +1,4 @@
+#include <stdio.h>
 #include "crash-stack.h"
 
 void *_crash_stack_get_memory_for_registers(size_t *size)
index 765a16e..e7cc7cd 100644 (file)
@@ -74,6 +74,8 @@
 #define REG_AARCH64_PC  32
 #define REG_ARM_SP      13
 #define REG_ARM_PC      12
+#define REG_RISCV_SP     2
+#define REG_RISCV_PC     0
 
 #define ADD_REG_TO_JSON_ARRAY(j_array, name, value) \
        { \
index 3a2b455..a3f15cd 100644 (file)
@@ -818,6 +818,9 @@ void _get_esp_and_eip() {
 #elif defined(__aarch64__)
     esp_i = REG_AARCH64_SP; // values from crash-stack-aarch64.c
     eip_i = REG_AARCH64_PC;
+#elif defined(__riscv) && __riscv_xlen == 64
+    esp_i = REG_RISCV_SP; // values from crash-stack-riscv64.c
+    eip_i = REG_RISCV_PC;
 #else
 #error "Not supported architecture"
 #endif
index 3c3b7d2..37a79db 100644 (file)
@@ -477,6 +477,8 @@ class Core {
                result = registers[task_nr].uregs[13];
 #elif defined(__aarch64__)
                result = registers[task_nr].sp;
+#elif defined(__riscv) && __riscv_xlen == 64
+               result = registers[task_nr].sp;
 #else
 #error Unsupported architecture
 #endif
index f7f0cb5..36f8e87 100644 (file)
@@ -21,6 +21,7 @@
 #include <elf.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <asm/ptrace.h>
 
 #include <functional>
 #include <string>
index 4b83703..01bcb1a 100644 (file)
@@ -29,6 +29,7 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/ptrace.h>
+#include <asm/ptrace.h>
 #include <sys/wait.h>
 
 #include <fstream>
@@ -107,7 +108,7 @@ class LiveDumper {
        }
 
        void GetRegs(user_regs_struct *registers, pid_t pid) const {
-#if defined(__aarch64__)
+#if defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64)
                struct iovec iov = { registers, sizeof *registers };
                if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov) == -1)
 #else
index b29b566..b98a264 100644 (file)
@@ -25,9 +25,9 @@
 #include <boost/exception_ptr.hpp>
 #include <exception>
 
-#if defined(__arm__) || defined(__i386__)
+#if defined(__arm__) || defined(__i386__) || (defined(__riscv) && __riscv_xlen == 32)
 #define ELF_TYPE Elf32
-#elif defined(__x86_64__) || defined(__aarch64__)
+#elif defined(__x86_64__) || defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64)
 #define ELF_TYPE Elf64
 #endif
 
index 9cc8f92..9758e76 100644 (file)
@@ -39,6 +39,8 @@ typedef user_regs user_regs_struct;
 #define MACHINE EM_X86_64
 #elif defined(__i386__)
 #define MACHINE EM_386
+#elif defined(__riscv) && __riscv_xlen == 64
+#define MACHINE EM_RISCV
 #else
 #error "architecture unsupported"
 #endif
index 6b5f1b1..bf51a8b 100644 (file)
@@ -16,6 +16,8 @@ char ill_buf[] = { 0xf0, 0x00, 0x00, 0xf0 };
 char ill_buf[] = { 0x22, 0x00, 0x00, 0xf9 };
 #elif defined(__i386__) || defined(__x86_64__)
 char ill_buf[] = { 0x06, 0x00, 0x00, 0x00 };
+#elif defined(__riscv) && __riscv_xlen == 64
+char ill_buf[] = { 0x06, 0x00, 0x00, 0x00 };
 #else
 #error "Unsupported architecture"
 #endif