From 235c64ec9ac4ed9868028e6d969e399b8aa470dc Mon Sep 17 00:00:00 2001 From: laokz Date: Tue, 2 Aug 2022 21:03:08 +0800 Subject: [PATCH] add initial riscv64 support Signed-off-by: laokz --- add-initial-riscv64-support.patch | 1413 +++++++++++++++++++++++++++++ ltrace.spec | 6 +- 2 files changed, 1418 insertions(+), 1 deletion(-) create mode 100644 add-initial-riscv64-support.patch diff --git a/add-initial-riscv64-support.patch b/add-initial-riscv64-support.patch new file mode 100644 index 0000000..2654104 --- /dev/null +++ b/add-initial-riscv64-support.patch @@ -0,0 +1,1413 @@ +commit d551196b272368a63477724bc83de386e507ca06 +Author: laokz +Date: Sat Jul 30 18:18:28 2022 +0800 + + riscv64: add initial riscv64 support + + Following RISC-V ISA and ABI spec, add basic ltrace function + support. Now, it can be built on RISC-V lp64d platform and + trace syscall, library and app functions. + + close: #7 #12 + + Signed-off-by: Kai Zhang + +diff --git a/README b/README +index c37b764..3d0cae1 100644 +--- a/README ++++ b/README +@@ -34,6 +34,7 @@ to test each release comprehensively on each target. + mips-*-linux-gnu + powerpc-*-linux-gnu + powerpc64-*-linux-gnu ++ riscv64-linux-gnu + s390-*-linux-gnu + s390x-*-linux-gnu + x86_64-*-linux-gnu +diff --git a/configure.ac b/configure.ac +index b9c39fa..8945a38 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -45,6 +45,7 @@ + cris*) HOST_CPU="cris" ;; + mips*) HOST_CPU="mips" ;; + powerpc|powerpc64) HOST_CPU="ppc" ;; ++ riscv64) HOST_CPU="riscv64" ;; + sun4u|sparc64) HOST_CPU="sparc" ;; + s390x) HOST_CPU="s390" ;; + i?86|x86_64) HOST_CPU="x86" ;; +@@ -216,6 +217,7 @@ + powerpc) UNWIND_ARCH="ppc32" ;; + powerpc64) UNWIND_ARCH="ppc64" ;; + mips*) UNWIND_ARCH="mips" ;; ++ riscv*) UNWIND_ARCH="riscv" ;; + *) UNWIND_ARCH="${host_cpu}" ;; + esac + +@@ -409,6 +411,7 @@ + sysdeps/linux-gnu/metag/Makefile + sysdeps/linux-gnu/mips/Makefile + sysdeps/linux-gnu/ppc/Makefile ++ sysdeps/linux-gnu/riscv64/Makefile + sysdeps/linux-gnu/s390/Makefile + sysdeps/linux-gnu/sparc/Makefile + sysdeps/linux-gnu/x86/Makefile +diff --git a/sysdeps/linux-gnu/Makefile.am b/sysdeps/linux-gnu/Makefile.am +index 857f2da..e681b2f 100644 +--- a/sysdeps/linux-gnu/Makefile.am ++++ b/sysdeps/linux-gnu/Makefile.am +@@ -18,7 +18,7 @@ + # 02110-1301 USA + + DIST_SUBDIRS = aarch64 alpha arm cris ia64 m68k metag mips ppc s390 \ +- sparc x86 ++ sparc x86 riscv64 + + SUBDIRS = \ + $(HOST_CPU) +diff --git a/sysdeps/linux-gnu/riscv64/Makefile.am b/sysdeps/linux-gnu/riscv64/Makefile.am +new file mode 100644 +index 0000000..f018dfc +--- /dev/null ++++ b/sysdeps/linux-gnu/riscv64/Makefile.am +@@ -0,0 +1,35 @@ ++# This file is part of ltrace. ++# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix ++# ++# This program is free software; you can redistribute it and/or ++# modify it under the terms of the GNU General Public License as ++# published by the Free Software Foundation; either version 2 of the ++# License, or (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++# 02110-1301 USA ++ ++noinst_LTLIBRARIES = \ ++ ../libcpu.la ++ ++___libcpu_la_SOURCES = \ ++ fetch.c \ ++ plt.c \ ++ regs.c \ ++ trace.c ++ ++noinst_HEADERS = \ ++ arch.h \ ++ ptrace.h \ ++ signalent.h \ ++ syscallent.h ++ ++MAINTAINERCLEANFILES = \ ++ Makefile.in +diff --git a/sysdeps/linux-gnu/riscv64/arch.h b/sysdeps/linux-gnu/riscv64/arch.h +new file mode 100644 +index 0000000..5f5b0fe +--- /dev/null ++++ b/sysdeps/linux-gnu/riscv64/arch.h +@@ -0,0 +1,47 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2022 Kai Zhang (laokz) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#ifndef LTRACE_RISCV64_ARCH_H ++#define LTRACE_RISCV64_ARCH_H ++ ++#include ++ ++#define ARCH_ENDIAN_LITTLE ++ ++/* ebreak */ ++#define BREAKPOINT_VALUE { 0x73, 0x00, 0x10, 0x00 } ++#define BREAKPOINT_LENGTH 4 ++#define DECR_PC_AFTER_BREAK 0 ++ ++#define LT_ELFCLASS ELFCLASS64 ++#define LT_ELF_MACHINE EM_RISCV ++ ++#define ARCH_HAVE_SW_SINGLESTEP ++ ++#define ARCH_HAVE_ADD_PLT_ENTRY ++ ++#define ARCH_HAVE_FETCH_ARG ++#define ARCH_HAVE_FETCH_PACK ++ ++#define ARCH_HAVE_LTELF_DATA ++struct arch_ltelf_data { ++}; ++ ++#endif +diff --git a/sysdeps/linux-gnu/riscv64/fetch.c b/sysdeps/linux-gnu/riscv64/fetch.c +new file mode 100644 +index 0000000..8ea943b +--- /dev/null ++++ b/sysdeps/linux-gnu/riscv64/fetch.c +@@ -0,0 +1,450 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2022 Kai Zhang (laokz) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "backend.h" ++#include "fetch.h" ++#include "type.h" ++#include "proc.h" ++#include "value.h" ++#include "ptrace.h" ++#include "param.h" ++ ++#define ARG_REG_FIRST 10 ++#define ARG_REG_LAST 17 ++ ++/* ++ * Where to fetch argument/return value. ++ * According to Integer Calling Convention(ICC) and Hardware ++ * Floating-point Calling Convention(FCC), at most 2×XLEN bits ++ * -- 2 words be fetched for one value. ++ */ ++enum fetch_class { ++ CLASS_G, /* only from one place, general register, */ ++ CLASS_F, /* float register, or stack, */ ++ CLASS_STACK, /* maybe 1 or 2 word(s) */ ++ CLASS_G_F, /* both from two places */ ++ CLASS_F_G, ++ CLASS_G_STACK, ++ CLASS_F_STACK, ++ CLASS_STACK_F, ++ CLASS_F_F, /* specific for struct {float;float} */ ++}; ++ ++struct fetch_context { ++ struct user_regs_struct gregs; ++ struct __riscv_d_ext_state fregs; ++ ++ int gidx; /* next argument register index */ ++ int fidx; /* into above regs */ ++ arch_addr_t sp; /* next argument stack address */ ++ int is_variadic; /* if variadic argument */ ++ struct value retval;/* used when return value > 128bit */ ++}; ++ ++static int ++fetch_register_banks(struct process *proc, struct fetch_context *ctx) ++{ ++ struct iovec data = {&ctx->gregs, sizeof(struct user_regs_struct)}; ++ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, &data) == -1) { ++ perror("PTRACE_GETREGSET NT_PRSTATUS"); ++ return -1; ++ } ++ ++ data.iov_base = &ctx->fregs.f; ++ data.iov_len = sizeof(struct __riscv_d_ext_state); ++ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRFPREG, &data) == -1) { ++ perror("PTRACE_GETREGSET NT_PRFPREG"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Same as type_get_fp_equivalent but for INTEGER. ++ * Note, pointer is not INTERGER. ++ */ ++static struct arg_type_info * ++type_get_int_equivalent(struct arg_type_info *info) ++{ ++ while (info->type == ARGTYPE_STRUCT) { ++ if (type_struct_size(info) != 1) ++ return NULL; ++ info = type_element(info, 0); ++ } ++ ++ switch (info->type) { ++ case ARGTYPE_CHAR: ++ case ARGTYPE_SHORT: ++ case ARGTYPE_INT: ++ case ARGTYPE_LONG: ++ case ARGTYPE_UINT: ++ case ARGTYPE_ULONG: ++ case ARGTYPE_USHORT: ++ return info; ++ default: ++ break; ++ } ++ ++ return NULL; ++} ++ ++static inline enum fetch_class ++icc_class(struct fetch_context *ctx, size_t sz) ++{ ++ if (ctx->gidx > ARG_REG_LAST) ++ return CLASS_STACK; ++ if ((ctx->gidx == ARG_REG_LAST) && (sz > 8)) ++ return CLASS_G_STACK; ++ return CLASS_G; ++} ++ ++/* ++ * Determine fetch_class which typesize > 0 and <= 128bits. ++ * Treat syscall exactly the same as function call, hope ++ * not break the system?? ++ */ ++static enum fetch_class ++get_fetch_class(struct fetch_context *ctx, struct process *proc, ++ struct arg_type_info *info) ++{ ++ size_t sz = type_sizeof(proc, info); ++ ++ /* variadic arguments are passed according to ICC */ ++ if (ctx->is_variadic) { ++ if (sz <= 8) ++ return (ctx->gidx > ARG_REG_LAST) ? CLASS_STACK : CLASS_G; ++ ++ /* 2×XLEN bits variadic must in an aligned register pair */ ++ if (ctx->gidx == ARG_REG_LAST) { ++ ctx->gidx++; ++ return CLASS_STACK; ++ } ++ if (ctx->gidx % 2) ++ ctx->gidx++; ++ return CLASS_G; ++ } ++ ++ switch (info->type) { ++ case ARGTYPE_INT: ++ case ARGTYPE_UINT: ++ case ARGTYPE_LONG: ++ case ARGTYPE_ULONG: ++ case ARGTYPE_CHAR: ++ case ARGTYPE_SHORT: ++ case ARGTYPE_USHORT: ++ case ARGTYPE_POINTER: ++ if (ctx->gidx > ARG_REG_LAST) ++ return CLASS_STACK; ++ return CLASS_G; ++ ++ case ARGTYPE_FLOAT: ++ case ARGTYPE_DOUBLE: ++ if ((ctx->gidx > ARG_REG_LAST) && (ctx->fidx > ARG_REG_LAST)) ++ return CLASS_STACK; ++ else if (ctx->fidx > ARG_REG_LAST) ++ return CLASS_G; ++ return CLASS_F; ++ ++ /* not support 'packed' 'aligned' attribute as ltrace doesn't */ ++ case ARGTYPE_STRUCT: ++ /* try FCC first */ ++ if (type_struct_size(info) == 2) { ++ struct arg_type_info *arg0 = type_struct_get(info, 0); ++ struct arg_type_info *arg1 = type_struct_get(info, 1); ++ ++ /* {float;float} */ ++ if ((type_get_fp_equivalent(arg0) != NULL) && ++ (type_get_fp_equivalent(arg1) != NULL)) { ++ if (ctx->fidx >= ARG_REG_LAST) ++ return icc_class(ctx, sz); ++ /* ++ * A struct containing two floating-point reals is passed ++ * in two floating-point registers, though its total size ++ * might be 8. ++ */ ++ return CLASS_F_F; ++ } ++ ++ /* {float;int} */ ++ if ((type_get_fp_equivalent(arg0) != NULL) && ++ (type_get_int_equivalent(arg1) != NULL)) { ++ if (ctx->fidx > ARG_REG_LAST) ++ return icc_class(ctx, sz); ++ if (ctx->gidx > ARG_REG_LAST) ++ return CLASS_F_STACK; ++ return CLASS_F_G; ++ } ++ ++ /* {int;float} */ ++ if ((type_get_int_equivalent(arg0) != NULL) && ++ (type_get_fp_equivalent(arg1) != NULL)) { ++ if (ctx->fidx > ARG_REG_LAST) ++ return icc_class(ctx, sz); ++ if (ctx->gidx > ARG_REG_LAST) ++ return CLASS_STACK_F; ++ return CLASS_G_F; ++ } ++ } else if (type_get_fp_equivalent(info) != NULL) { /* {float} */ ++ if (ctx->fidx > ARG_REG_LAST) { ++ if (ctx->gidx > ARG_REG_LAST) ++ return CLASS_STACK; ++ return CLASS_G; ++ } ++ return CLASS_F; ++ } ++ ++ return icc_class(ctx, sz); ++ ++ default: ++ abort(); ++ } ++} ++ ++static inline unsigned long ++fetch_stack_word(struct fetch_context *ctx, struct process *proc) ++{ ++ long v = ptrace(PTRACE_PEEKDATA, proc->pid, ctx->sp, 0); ++ if ((v == -1) && errno) { ++ perror("PTRACE_PEEKDATA"); ++ abort(); ++ } ++ ctx->sp += 8; ++ return (unsigned long)v; ++} ++ ++/* Fetch value whose size no more than 128 bits */ ++static int ++fetch_value(struct fetch_context *ctx, struct process *proc, ++ struct value *valp, enum fetch_class c, size_t sz) ++{ ++ unsigned long *p = (unsigned long *)value_reserve(valp, align(sz, 8)); ++ if (p == NULL) { ++ fprintf(stderr, "value_reserve failed\n"); ++ return -1; ++ } ++ ++ unsigned long *gr = &ctx->gregs.pc; ++ ++ switch (c) { ++ case CLASS_G: ++ p[0] = gr[ctx->gidx++]; ++ if (sz > 8) ++ p[1] = gr[ctx->gidx++]; ++ break; ++ ++ case CLASS_F: ++ p[0] = ctx->fregs.f[ctx->fidx++]; ++ if (sz > 8) ++ p[1] = ctx->fregs.f[ctx->fidx++]; ++ break; ++ ++ case CLASS_STACK: ++ p[0] = fetch_stack_word(ctx, proc); ++ if (sz > 8) ++ p[1] = fetch_stack_word(ctx, proc); ++ break; ++ ++ case CLASS_G_F: ++ p[0] = gr[ctx->gidx++]; ++ p[1] = ctx->fregs.f[ctx->fidx++]; ++ break; ++ ++ case CLASS_F_G: ++ p[0] = ctx->fregs.f[ctx->fidx++]; ++ p[1] = gr[ctx->gidx++]; ++ break; ++ ++ case CLASS_F_F: ++ p[0] = ctx->fregs.f[ctx->fidx++]; ++ unsigned long u = ctx->fregs.f[ctx->fidx++]; ++ if (sz > 8) ++ p[1] = u; ++ else /* struct{float;float;} use 2 fregs, occupy 1 word memory */ ++ p[0] = ((u & 0xFFFFFFFF) << 32) | (p[0] & 0xFFFFFFFF); ++ break; ++ ++ case CLASS_G_STACK: ++ p[0] = gr[ctx->gidx++]; ++ p[1] = fetch_stack_word(ctx, proc); ++ break; ++ ++ case CLASS_F_STACK: ++ p[0] = ctx->fregs.f[ctx->fidx++]; ++ p[1] = fetch_stack_word(ctx, proc); ++ break; ++ ++ case CLASS_STACK_F: ++ p[0] = fetch_stack_word(ctx, proc); ++ p[1] = ctx->fregs.f[ctx->fidx++]; ++ break; ++ } ++ ++ return 0; ++} ++ ++/* value larger than 128bit is transferred to reference */ ++static int ++fetch_larger(struct fetch_context *ctx, struct process *proc, ++ struct arg_type_info *info, struct value *valp) ++{ ++ value_init(valp, proc, NULL, info, 0); ++ if (value_pass_by_reference(valp) != 0) { ++ fprintf(stderr, "value_pass_by_reference failed\n"); ++ return -1; ++ } ++ ++ enum fetch_class c = get_fetch_class(ctx, proc, valp->type); ++ return fetch_value(ctx, proc, valp, c, 8); ++} ++ ++struct fetch_context * ++arch_fetch_arg_init(enum tof type, struct process *proc, ++ struct arg_type_info *ret_info) ++{ ++ struct fetch_context *ctx = malloc(sizeof(*ctx)); ++ if (ctx == NULL) { ++ perror("arch_fetch_arg_init"); ++ return NULL; ++ } ++ ++ if (fetch_register_banks(proc, ctx) == -1) ++ goto ERR_OUT; ++ ++ ctx->gidx = ARG_REG_FIRST; ++ ctx->fidx = ARG_REG_FIRST; ++ /* ++ * When hit this function, the stack pointer is pointing to the ++ * 1st argument, not the return address. ++ */ ++ ctx->sp = (arch_addr_t)ctx->gregs.sp; ++ ctx->is_variadic = 0; ++ ++ size_t sz = type_sizeof(proc, ret_info); ++ assert(sz != (size_t)-1); ++ if (sz > 16) { ++ /* ++ * Return value larger than 128bit will be passed by reference, ++ * and address stored as an implicit first parameter. ++ * We must fetch and save it first. ++ */ ++ if (fetch_larger(ctx, proc, ret_info, &ctx->retval) == -1) ++ goto ERR_OUT; ++ } else { ++ value_init_detached(&ctx->retval, NULL, NULL, 0); ++ } ++ ++ return ctx; ++ ++ERR_OUT: ++ free(ctx); ++ return NULL; ++} ++ ++struct fetch_context * ++arch_fetch_arg_clone(struct process *proc, struct fetch_context *ctx) ++{ ++ struct fetch_context *clone = malloc(sizeof(*ctx)); ++ if (clone == NULL) { ++ perror("arch_fetch_arg_clone"); ++ return NULL; ++ } ++ ++ *clone = *ctx; ++ return clone; ++} ++ ++int ++arch_fetch_retval(struct fetch_context *ctx, enum tof type, ++ struct process *proc, struct arg_type_info *info, ++ struct value *valp) ++{ ++ if (fetch_register_banks(proc, ctx) == -1) ++ return -1; ++ ++ /* if we already prefetched its reference address */ ++ if (ctx->retval.type != NULL) { ++ *valp = ctx->retval; ++ return 0; ++ } ++ ++ size_t sz = type_sizeof(proc, info); ++ assert(sz != (size_t)-1); ++ ++ if (sz == 0) ++ return 0; ++ ++ ctx->gidx = ARG_REG_FIRST; ++ ctx->fidx = ARG_REG_FIRST; ++ enum fetch_class c = get_fetch_class(ctx, proc, info); ++ return fetch_value(ctx, proc, valp, c, sz); ++} ++ ++int ++arch_fetch_arg_next(struct fetch_context *ctx, enum tof type, ++ struct process *proc, struct arg_type_info *info, ++ struct value *valp) ++{ ++ /* why we got ARGTYPE_ARRAY?? */ ++ assert(info->type != ARGTYPE_ARRAY); ++ ++ size_t sz = type_sizeof(proc, info); ++ assert(sz != (size_t)-1); ++ ++ if (sz == 0) ++ return 0; ++ ++ if (sz > 16) ++ return fetch_larger(ctx, proc, info, valp); ++ ++ enum fetch_class c = get_fetch_class(ctx, proc, info); ++ return fetch_value(ctx, proc, valp, c, sz); ++} ++ ++void ++arch_fetch_arg_done(struct fetch_context *ctx) ++{ ++ free(ctx); ++} ++ ++int ++arch_fetch_param_pack_start(struct fetch_context *ctx, ++ enum param_pack_flavor ppflavor) ++{ ++ /* ++ * Leave out PARAM_PACK_ARGS and return garbage if any. ++ * ++ * For PARAM_PACK_VARARGS - variable arguments, once met ++ * than all the left arguments are also variadic. ++ */ ++ if (!ctx->is_variadic && (ppflavor == PARAM_PACK_VARARGS)) ++ ctx->is_variadic = 1; ++ return 0; ++} ++ ++void ++arch_fetch_param_pack_end(struct fetch_context *ctx) ++{ ++} +diff --git a/sysdeps/linux-gnu/riscv64/plt.c b/sysdeps/linux-gnu/riscv64/plt.c +new file mode 100644 +index 0000000..abffe97 +--- /dev/null ++++ b/sysdeps/linux-gnu/riscv64/plt.c +@@ -0,0 +1,72 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2022 Kai Zhang (laokz) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include ++#include "ltrace-elf.h" ++#include "proc.h" ++#include "backend.h" ++#include "breakpoint.h" ++#include "ptrace.h" ++#include "library.h" ++#include "trace.h" ++ ++GElf_Addr ++arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela) ++{ ++ if (GELF_R_TYPE(rela->r_info) == R_RISCV_IRELATIVE) ++ return rela->r_addend;// what shall we return ?? ++ ++ return lte->plt_addr + 16 * 2 + (ndx * 16); ++} ++ ++void * ++sym2addr(struct process *proc, struct library_symbol *sym) ++{ ++ return sym->enter_addr; ++} ++ ++enum plt_status ++arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte, ++ const char *name, GElf_Rela *rela, ++ size_t i, struct library_symbol **ret) ++{ ++ if (GELF_R_TYPE(rela->r_info) == R_RISCV_IRELATIVE) ++ return linux_elf_add_plt_entry_irelative(proc, lte, rela, i, ret); ++ ++ return PLT_DEFAULT; ++} ++ ++int ++arch_elf_init(struct ltelf *lte, struct library *lib) ++{ ++ if ((lte->ehdr.e_flags & EF_RISCV_FLOAT_ABI) != ++ EF_RISCV_FLOAT_ABI_DOUBLE) { ++ fprintf(stderr, "failed: only LP64D ABI supported\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++void ++arch_elf_destroy(struct ltelf *lte) ++{ ++} +diff --git a/sysdeps/linux-gnu/riscv64/ptrace.h b/sysdeps/linux-gnu/riscv64/ptrace.h +new file mode 100644 +index 0000000..37b375c +--- /dev/null ++++ b/sysdeps/linux-gnu/riscv64/ptrace.h +@@ -0,0 +1,22 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2022 Kai Zhang (laokz) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include +diff --git a/sysdeps/linux-gnu/riscv64/regs.c b/sysdeps/linux-gnu/riscv64/regs.c +new file mode 100644 +index 0000000..ff29756 +--- /dev/null ++++ b/sysdeps/linux-gnu/riscv64/regs.c +@@ -0,0 +1,74 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2022 Kai Zhang (laokz) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include "proc.h" ++#include "ptrace.h" ++ ++/* read tracee general registers */ ++long ++riscv64_read_gregs(struct process *proc, struct user_regs_struct *regs) ++{ ++ struct iovec data = {regs, sizeof(*regs)}; ++ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, &data) == -1) { ++ perror("riscv64_read_gregs"); ++ return -1; ++ } ++ return 0; ++} ++ ++void * ++get_instruction_pointer(struct process *proc) ++{ ++ struct user_regs_struct regs; ++ /* RISC-V does not support PTRACE_PEEKUSER, PTRACE_GETREGS */ ++ if (riscv64_read_gregs(proc, ®s) == -1) ++ return NULL; ++ return (void *)regs.pc; ++} ++ ++void ++set_instruction_pointer(struct process *proc, void *addr) ++{ ++ struct user_regs_struct regs; ++ if (riscv64_read_gregs(proc, ®s) == -1) ++ return; ++ regs.pc = (unsigned long)addr; ++ struct iovec data = {®s, sizeof(regs)}; ++ ptrace(PTRACE_SETREGSET, proc->pid, NT_PRSTATUS, &data); ++} ++ ++void * ++get_stack_pointer(struct process *proc) ++{ ++ struct user_regs_struct regs; ++ if (riscv64_read_gregs(proc, ®s) == -1) ++ return NULL; ++ return (void *)regs.sp; ++} ++ ++void * ++get_return_addr(struct process *proc, void *stack_pointer) ++{ ++ struct user_regs_struct regs; ++ if (riscv64_read_gregs(proc, ®s) == -1) ++ return NULL; ++ return (void *)regs.ra; ++} +diff --git a/sysdeps/linux-gnu/riscv64/signalent.h b/sysdeps/linux-gnu/riscv64/signalent.h +new file mode 100644 +index 0000000..32a755a +--- /dev/null ++++ b/sysdeps/linux-gnu/riscv64/signalent.h +@@ -0,0 +1,52 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2022 Kai Zhang (laokz) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++/* from linux kernel 5.10 */ ++ "SIG_0", /* 0 */ ++ "SIGHUP", /* 1 */ ++ "SIGINT", /* 2 */ ++ "SIGQUIT", /* 3 */ ++ "SIGILL", /* 4 */ ++ "SIGTRAP", /* 5 */ ++ "SIGABRT", /* 6 */ ++ "SIGBUS", /* 7 */ ++ "SIGFPE", /* 8 */ ++ "SIGKILL", /* 9 */ ++ "SIGUSR1", /* 10 */ ++ "SIGSEGV", /* 11 */ ++ "SIGUSR2", /* 12 */ ++ "SIGPIPE", /* 13 */ ++ "SIGALRM", /* 14 */ ++ "SIGTERM", /* 15 */ ++ "SIGSTKFLT", /* 16 */ ++ "SIGCHLD", /* 17 */ ++ "SIGCONT", /* 18 */ ++ "SIGSTOP", /* 19 */ ++ "SIGTSTP", /* 20 */ ++ "SIGTTIN", /* 21 */ ++ "SIGTTOU", /* 22 */ ++ "SIGURG", /* 23 */ ++ "SIGXCPU", /* 24 */ ++ "SIGXFSZ", /* 25 */ ++ "SIGVTALRM", /* 26 */ ++ "SIGPROF", /* 27 */ ++ "SIGWINCH", /* 28 */ ++ "SIGIO", /* 29 */ ++ "SIGPWR", /* 30 */ ++ "SIGSYS", /* 31 */ +diff --git a/sysdeps/linux-gnu/riscv64/syscallent.h b/sysdeps/linux-gnu/riscv64/syscallent.h +new file mode 100644 +index 0000000..e4fba7f +--- /dev/null ++++ b/sysdeps/linux-gnu/riscv64/syscallent.h +@@ -0,0 +1,461 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2022 Kai Zhang (laokz) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++/* from linux kernel 5.10 */ ++ "io_setup", /* 0 */ ++ "io_destroy", /* 1 */ ++ "io_submit", /* 2 */ ++ "io_cancel", /* 3 */ ++ "io_getevents", /* 4 */ ++ "setxattr", /* 5 */ ++ "lsetxattr", /* 6 */ ++ "fsetxattr", /* 7 */ ++ "getxattr", /* 8 */ ++ "lgetxattr", /* 9 */ ++ "fgetxattr", /* 10 */ ++ "listxattr", /* 11 */ ++ "llistxattr", /* 12 */ ++ "flistxattr", /* 13 */ ++ "removexattr", /* 14 */ ++ "lremovexattr", /* 15 */ ++ "fremovexattr", /* 16 */ ++ "getcwd", /* 17 */ ++ "lookup_dcookie", /* 18 */ ++ "eventfd2", /* 19 */ ++ "epoll_create1", /* 20 */ ++ "epoll_ctl", /* 21 */ ++ "epoll_pwait", /* 22 */ ++ "dup", /* 23 */ ++ "dup3", /* 24 */ ++ "fcntl", /* 25 */ ++ "inotify_init1", /* 26 */ ++ "inotify_add_watch", /* 27 */ ++ "inotify_rm_watch", /* 28 */ ++ "ioctl", /* 29 */ ++ "ioprio_set", /* 30 */ ++ "ioprio_get", /* 31 */ ++ "flock", /* 32 */ ++ "mknodat", /* 33 */ ++ "mkdirat", /* 34 */ ++ "unlinkat", /* 35 */ ++ "symlinkat", /* 36 */ ++ "linkat", /* 37 */ ++ "renameat", /* 38 */ ++ "umount2", /* 39 */ ++ "mount", /* 40 */ ++ "pivot_root", /* 41 */ ++ "nfsservctl", /* 42 */ ++ "statfs", /* 43 */ ++ "fstatfs", /* 44 */ ++ "truncate", /* 45 */ ++ "ftruncate", /* 46 */ ++ "fallocate", /* 47 */ ++ "faccessat", /* 48 */ ++ "chdir", /* 49 */ ++ "fchdir", /* 50 */ ++ "chroot", /* 51 */ ++ "fchmod", /* 52 */ ++ "fchmodat", /* 53 */ ++ "fchownat", /* 54 */ ++ "fchown", /* 55 */ ++ "openat", /* 56 */ ++ "close", /* 57 */ ++ "vhangup", /* 58 */ ++ "pipe2", /* 59 */ ++ "quotactl", /* 60 */ ++ "getdents64", /* 61 */ ++ "lseek", /* 62 */ ++ "read", /* 63 */ ++ "write", /* 64 */ ++ "readv", /* 65 */ ++ "writev", /* 66 */ ++ "pread64", /* 67 */ ++ "pwrite64", /* 68 */ ++ "preadv", /* 69 */ ++ "pwritev", /* 70 */ ++ "sendfile", /* 71 */ ++ "pselect6", /* 72 */ ++ "ppoll", /* 73 */ ++ "signalfd4", /* 74 */ ++ "vmsplice", /* 75 */ ++ "splice", /* 76 */ ++ "tee", /* 77 */ ++ "readlinkat", /* 78 */ ++ "fstatat", /* 79 */ ++ "fstat", /* 80 */ ++ "sync", /* 81 */ ++ "fsync", /* 82 */ ++ "fdatasync", /* 83 */ ++ "sync_file_range", /* 84 */ ++ "timerfd_create", /* 85 */ ++ "timerfd_settime", /* 86 */ ++ "timerfd_gettime", /* 87 */ ++ "utimensat", /* 88 */ ++ "acct", /* 89 */ ++ "capget", /* 90 */ ++ "capset", /* 91 */ ++ "personality", /* 92 */ ++ "exit", /* 93 */ ++ "exit_group", /* 94 */ ++ "waitid", /* 95 */ ++ "set_tid_address", /* 96 */ ++ "unshare", /* 97 */ ++ "futex", /* 98 */ ++ "set_robust_list", /* 99 */ ++ "get_robust_list", /* 100 */ ++ "nanosleep", /* 101 */ ++ "getitimer", /* 102 */ ++ "setitimer", /* 103 */ ++ "kexec_load", /* 104 */ ++ "init_module", /* 105 */ ++ "delete_module", /* 106 */ ++ "timer_create", /* 107 */ ++ "timer_gettime", /* 108 */ ++ "timer_getoverrun", /* 109 */ ++ "timer_settime", /* 110 */ ++ "timer_delete", /* 111 */ ++ "clock_settime", /* 112 */ ++ "clock_gettime", /* 113 */ ++ "clock_getres", /* 114 */ ++ "clock_nanosleep", /* 115 */ ++ "syslog", /* 116 */ ++ "ptrace", /* 117 */ ++ "sched_setparam", /* 118 */ ++ "sched_setscheduler", /* 119 */ ++ "sched_getscheduler", /* 120 */ ++ "sched_getparam", /* 121 */ ++ "sched_setaffinity", /* 122 */ ++ "sched_getaffinity", /* 123 */ ++ "sched_yield", /* 124 */ ++ "sched_get_priority_max", /* 125 */ ++ "sched_get_priority_min", /* 126 */ ++ "sched_rr_get_interval", /* 127 */ ++ "restart_syscall", /* 128 */ ++ "kill", /* 129 */ ++ "tkill", /* 130 */ ++ "tgkill", /* 131 */ ++ "sigaltstack", /* 132 */ ++ "rt_sigsuspend", /* 133 */ ++ "rt_sigaction", /* 134 */ ++ "rt_sigprocmask", /* 135 */ ++ "rt_sigpending", /* 136 */ ++ "rt_sigtimedwait", /* 137 */ ++ "rt_sigqueueinfo", /* 138 */ ++ "rt_sigreturn", /* 139 */ ++ "setpriority", /* 140 */ ++ "getpriority", /* 141 */ ++ "reboot", /* 142 */ ++ "setregid", /* 143 */ ++ "setgid", /* 144 */ ++ "setreuid", /* 145 */ ++ "setuid", /* 146 */ ++ "setresuid", /* 147 */ ++ "getresuid", /* 148 */ ++ "setresgid", /* 149 */ ++ "getresgid", /* 150 */ ++ "setfsuid", /* 151 */ ++ "setfsgid", /* 152 */ ++ "times", /* 153 */ ++ "setpgid", /* 154 */ ++ "getpgid", /* 155 */ ++ "getsid", /* 156 */ ++ "setsid", /* 157 */ ++ "getgroups", /* 158 */ ++ "setgroups", /* 159 */ ++ "uname", /* 160 */ ++ "sethostname", /* 161 */ ++ "setdomainname", /* 162 */ ++ "getrlimit", /* 163 */ ++ "setrlimit", /* 164 */ ++ "getrusage", /* 165 */ ++ "umask", /* 166 */ ++ "prctl", /* 167 */ ++ "getcpu", /* 168 */ ++ "gettimeofday", /* 169 */ ++ "settimeofday", /* 170 */ ++ "adjtimex", /* 171 */ ++ "getpid", /* 172 */ ++ "getppid", /* 173 */ ++ "getuid", /* 174 */ ++ "geteuid", /* 175 */ ++ "getgid", /* 176 */ ++ "getegid", /* 177 */ ++ "gettid", /* 178 */ ++ "sysinfo", /* 179 */ ++ "mq_open", /* 180 */ ++ "mq_unlink", /* 181 */ ++ "mq_timedsend", /* 182 */ ++ "mq_timedreceive", /* 183 */ ++ "mq_notify", /* 184 */ ++ "mq_getsetattr", /* 185 */ ++ "msgget", /* 186 */ ++ "msgctl", /* 187 */ ++ "msgrcv", /* 188 */ ++ "msgsnd", /* 189 */ ++ "semget", /* 190 */ ++ "semctl", /* 191 */ ++ "semtimedop", /* 192 */ ++ "semop", /* 193 */ ++ "shmget", /* 194 */ ++ "shmctl", /* 195 */ ++ "shmat", /* 196 */ ++ "shmdt", /* 197 */ ++ "socket", /* 198 */ ++ "socketpair", /* 199 */ ++ "bind", /* 200 */ ++ "listen", /* 201 */ ++ "accept", /* 202 */ ++ "connect", /* 203 */ ++ "getsockname", /* 204 */ ++ "getpeername", /* 205 */ ++ "sendto", /* 206 */ ++ "recvfrom", /* 207 */ ++ "setsockopt", /* 208 */ ++ "getsockopt", /* 209 */ ++ "shutdown", /* 210 */ ++ "sendmsg", /* 211 */ ++ "recvmsg", /* 212 */ ++ "readahead", /* 213 */ ++ "brk", /* 214 */ ++ "munmap", /* 215 */ ++ "mremap", /* 216 */ ++ "add_key", /* 217 */ ++ "request_key", /* 218 */ ++ "keyctl", /* 219 */ ++ "clone", /* 220 */ ++ "execve", /* 221 */ ++ "mmap", /* 222 */ ++ "fadvise64", /* 223 */ ++ "swapon", /* 224 */ ++ "swapoff", /* 225 */ ++ "mprotect", /* 226 */ ++ "msync", /* 227 */ ++ "mlock", /* 228 */ ++ "munlock", /* 229 */ ++ "mlockall", /* 230 */ ++ "munlockall", /* 231 */ ++ "mincore", /* 232 */ ++ "madvise", /* 233 */ ++ "remap_file_pages", /* 234 */ ++ "mbind", /* 235 */ ++ "get_mempolicy", /* 236 */ ++ "set_mempolicy", /* 237 */ ++ "migrate_pages", /* 238 */ ++ "move_pages", /* 239 */ ++ "rt_tgsigqueueinfo", /* 240 */ ++ "perf_event_open", /* 241 */ ++ "accept4", /* 242 */ ++ "recvmmsg", /* 243 */ ++ "244", ++ "245", ++ "246", ++ "247", ++ "248", ++ "249", ++ "250", ++ "251", ++ "252", ++ "253", ++ "254", ++ "255", ++ "256", ++ "257", ++ "258", ++ "riscv_flush_icache", /* 259 */ ++ "wait4", /* 260 */ ++ "prlimit64", /* 261 */ ++ "fanotify_init", /* 262 */ ++ "fanotify_mark", /* 263 */ ++ "name_to_handle_at", /* 264 */ ++ "open_by_handle_at", /* 265 */ ++ "clock_adjtime", /* 266 */ ++ "syncfs", /* 267 */ ++ "setns", /* 268 */ ++ "sendmmsg", /* 269 */ ++ "process_vm_readv", /* 270 */ ++ "process_vm_writev", /* 271 */ ++ "kcmp", /* 272 */ ++ "finit_module", /* 273 */ ++ "sched_setattr", /* 274 */ ++ "sched_getattr", /* 275 */ ++ "renameat2", /* 276 */ ++ "seccomp", /* 277 */ ++ "getrandom", /* 278 */ ++ "memfd_create", /* 279 */ ++ "bpf", /* 280 */ ++ "execveat", /* 281 */ ++ "userfaultfd", /* 282 */ ++ "membarrier", /* 283 */ ++ "mlock2", /* 284 */ ++ "copy_file_range", /* 285 */ ++ "preadv2", /* 286 */ ++ "pwritev2", /* 287 */ ++ "pkey_mprotect", /* 288 */ ++ "pkey_alloc", /* 289 */ ++ "pkey_free", /* 290 */ ++ "statx", /* 291 */ ++ "io_pgetevents", /* 292 */ ++ "rseq", /* 293 */ ++ "kexec_file_load", /* 294 */ ++ "295", ++ "296", ++ "297", ++ "298", ++ "299", ++ "300", ++ "301", ++ "302", ++ "303", ++ "304", ++ "305", ++ "306", ++ "307", ++ "308", ++ "309", ++ "310", ++ "311", ++ "312", ++ "313", ++ "314", ++ "315", ++ "316", ++ "317", ++ "318", ++ "319", ++ "320", ++ "321", ++ "322", ++ "323", ++ "324", ++ "325", ++ "326", ++ "327", ++ "328", ++ "329", ++ "330", ++ "331", ++ "332", ++ "333", ++ "334", ++ "335", ++ "336", ++ "337", ++ "338", ++ "339", ++ "340", ++ "341", ++ "342", ++ "343", ++ "344", ++ "345", ++ "346", ++ "347", ++ "348", ++ "349", ++ "350", ++ "351", ++ "352", ++ "353", ++ "354", ++ "355", ++ "356", ++ "357", ++ "358", ++ "359", ++ "360", ++ "361", ++ "362", ++ "363", ++ "364", ++ "365", ++ "366", ++ "367", ++ "368", ++ "369", ++ "370", ++ "371", ++ "372", ++ "373", ++ "374", ++ "375", ++ "376", ++ "377", ++ "378", ++ "379", ++ "380", ++ "381", ++ "382", ++ "383", ++ "384", ++ "385", ++ "386", ++ "387", ++ "388", ++ "389", ++ "390", ++ "391", ++ "392", ++ "393", ++ "394", ++ "395", ++ "396", ++ "397", ++ "398", ++ "399", ++ "400", ++ "401", ++ "402", ++ "clock_gettime64", /* 403 */ ++ "clock_settime64", /* 404 */ ++ "clock_adjtime64", /* 405 */ ++ "clock_getres_time64", /* 406 */ ++ "clock_nanosleep_time64", /* 407 */ ++ "timer_gettime64", /* 408 */ ++ "timer_settime64", /* 409 */ ++ "timerfd_gettime64", /* 410 */ ++ "timerfd_settime64", /* 411 */ ++ "utimensat_time64", /* 412 */ ++ "pselect6_time64", /* 413 */ ++ "ppoll_time64", /* 414 */ ++ "415", ++ "io_pgetevents_time64", /* 416 */ ++ "recvmmsg_time64", /* 417 */ ++ "mq_timedsend_time64", /* 418 */ ++ "mq_timedreceive_time64", /* 419 */ ++ "semtimedop_time64", /* 420 */ ++ "rt_sigtimedwait_time64", /* 421 */ ++ "futex_time64", /* 422 */ ++ "sched_rr_get_interval_time64", /* 423 */ ++ "pidfd_send_signal", /* 424 */ ++ "io_uring_setup", /* 425 */ ++ "io_uring_enter", /* 426 */ ++ "io_uring_register", /* 427 */ ++ "open_tree", /* 428 */ ++ "move_mount", /* 429 */ ++ "fsopen", /* 430 */ ++ "fsconfig", /* 431 */ ++ "fsmount", /* 432 */ ++ "fspick", /* 433 */ ++ "pidfd_open", /* 434 */ ++ "clone3", /* 435 */ ++ "close_range", /* 436 */ ++ "openat2", /* 437 */ ++ "pidfd_getfd", /* 438 */ ++ "faccessat2", /* 439 */ ++ "process_madvise", /* 440 */ +diff --git a/sysdeps/linux-gnu/riscv64/trace.c b/sysdeps/linux-gnu/riscv64/trace.c +new file mode 100644 +index 0000000..0a861f2 +--- /dev/null ++++ b/sysdeps/linux-gnu/riscv64/trace.c +@@ -0,0 +1,79 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2022 Kai Zhang (laokz) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include ++#include "backend.h" ++#include "proc.h" ++#include "ptrace.h" ++ ++extern long ++riscv64_read_gregs(struct process *proc, struct user_regs_struct *regs); ++ ++void ++get_arch_dep(struct process *proc) ++{ ++} ++ ++int ++syscall_p(struct process *proc, int status, int *sysnum) ++{ ++ if (WIFSTOPPED(status) ++ && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { ++ ++ struct user_regs_struct regs; ++ if (riscv64_read_gregs(proc, ®s) == -1) ++ return -1; ++ ++ /* ecall has no compressed format */ ++ switch (ptrace(PTRACE_PEEKTEXT, proc->pid, regs.pc - 4, 0) & ++ 0xFFFFFFFF) { ++ case 0x73: ++ break; ++ case -1: ++ perror("PTRACE_PEEKTEXT"); ++ return -1; ++ default: ++ return 0; ++ } ++ ++ *sysnum = regs.a7; ++ size_t i = proc->callstack_depth - 1; ++ if (proc->callstack_depth > 0 ++ && proc->callstack[i].is_syscall ++ && proc->callstack[i].c_un.syscall == (int)regs.a7) { ++ return 2; ++ } ++ return 1; ++ } ++ return 0; ++} ++ ++/* how to deal with this logic?? lr/sc atomic pairs?? */ ++enum sw_singlestep_status arch_sw_singlestep(struct process *proc, ++ struct breakpoint *bp, ++ int (*add_cb)(arch_addr_t addr, ++ struct sw_singlestep_data *), ++ struct sw_singlestep_data *data) ++{ ++ if (!ptrace(PTRACE_SYSCALL, proc->pid, 0, 0)) ++ return SWS_OK; ++ return SWS_FAIL; ++} diff --git a/ltrace.spec b/ltrace.spec index 2e49541..57772f4 100644 --- a/ltrace.spec +++ b/ltrace.spec @@ -1,6 +1,6 @@ name: ltrace Version: 0.7.91 -Release: 31 +Release: 32 Summary: Trace the Library and System Calls a Program Makes License: GPLv2+ @@ -30,6 +30,7 @@ Patch9001: bugfix-0001-ltrace-byteswap-instruction-in-arm-be8-mode.patch Patch9002: bugfix-for-use-after-free-about-soname.patch Patch9003: fix-null-directive-argument.patch Patch9004: Initialize-nrhs-to-avoid-gcc-warning.patch +Patch9005: add-initial-riscv64-support.patch BuildRequires: elfutils-devel dejagnu libselinux-devel autoconf automake libtool @@ -75,6 +76,9 @@ autoreconf -i %{_mandir}/man5/ltrace.conf.5* %changelog +* Fri Aug 12 2022 laokz - 0.7.91-32 +- Initialize riscv64 support + * Mon Jan 11 2021 lingsheng - 0.7.91-31 - Initialize 'nrhs' to avoid gcc warning -- Gitee