diff --git a/Add-support-for-sw64.patch b/Add-support-for-sw64.patch new file mode 100644 index 0000000000000000000000000000000000000000..72a652aba5fd7280b103b6a3d4be95e1847260fc --- /dev/null +++ b/Add-support-for-sw64.patch @@ -0,0 +1,3648 @@ +From 22b72600401a61adcca429b536a7fc1c06d0f300 Mon Sep 17 00:00:00 2001 +From: lijm +Date: Thu, 13 Feb 2025 06:00:33 +0000 +Subject: [PATCH] Add support for SW64 + +--- + Makefile.am | 7 +- + README | 2 + + configure.ac | 17 +- + include/libunwind-sw_64.h | 166 ++++++++ + include/libunwind.h.in | 2 + + include/tdep-sw_64/dwarf-config.h | 51 +++ + include/tdep-sw_64/jmpbuf.h | 32 ++ + include/tdep-sw_64/libunwind_i.h | 338 ++++++++++++++++ + include/tdep/dwarf-config.h | 2 + + include/tdep/jmpbuf.h | 2 + + include/tdep/libunwind_i.h.in | 2 + + src/Makefile.am | 38 ++ + src/coredump/_UCD_access_reg_linux.c | 37 ++ + src/ptrace/_UPT_reg_offset.c | 66 ++++ + src/sw_64/Gapply_reg_state.c | 37 ++ + src/sw_64/Gcreate_addr_space.c | 51 +++ + src/sw_64/Gget_proc_info.c | 44 +++ + src/sw_64/Gget_save_loc.c | 132 +++++++ + src/sw_64/Gglobal.c | 57 +++ + src/sw_64/Ginit.c | 197 ++++++++++ + src/sw_64/Ginit_local.c | 77 ++++ + src/sw_64/Ginit_remote.c | 45 +++ + src/sw_64/Gis_signal_frame.c | 107 ++++++ + src/sw_64/Greg_states_iterate.c | 37 ++ + src/sw_64/Gregs.c | 130 +++++++ + src/sw_64/Gresume.c | 112 ++++++ + src/sw_64/Gstep.c | 230 +++++++++++ + src/sw_64/Gtrace.c.bak | 552 +++++++++++++++++++++++++++ + src/sw_64/Lapply_reg_state.c | 5 + + src/sw_64/Lcreate_addr_space.c | 5 + + src/sw_64/Lget_proc_info.c | 5 + + src/sw_64/Lget_save_loc.c | 5 + + src/sw_64/Lglobal.c | 5 + + src/sw_64/Linit.c | 5 + + src/sw_64/Linit_local.c | 5 + + src/sw_64/Linit_remote.c | 5 + + src/sw_64/Lis_signal_frame.c | 5 + + src/sw_64/Lreg_states_iterate.c | 5 + + src/sw_64/Lregs.c | 5 + + src/sw_64/Lresume.c | 5 + + src/sw_64/Lstep.c | 5 + + src/sw_64/Ltrace.c.bak | 5 + + src/sw_64/elfxx.c | 27 ++ + src/sw_64/gen-offsets.c | 32 ++ + src/sw_64/getcontext.S | 78 ++++ + src/sw_64/init.h | 65 ++++ + src/sw_64/is_fpreg.c | 41 ++ + src/sw_64/offsets.h | 59 +++ + src/sw_64/regname.c | 50 +++ + src/sw_64/siglongjmp.S | 8 + + src/sw_64/unwind_i.h | 43 +++ + tests/Makefile.am | 4 + + tests/check-namespace.sh.in | 20 + + 53 files changed, 3063 insertions(+), 4 deletions(-) + create mode 100644 include/libunwind-sw_64.h + create mode 100644 include/tdep-sw_64/dwarf-config.h + create mode 100644 include/tdep-sw_64/jmpbuf.h + create mode 100644 include/tdep-sw_64/libunwind_i.h + create mode 100644 src/sw_64/Gapply_reg_state.c + create mode 100644 src/sw_64/Gcreate_addr_space.c + create mode 100644 src/sw_64/Gget_proc_info.c + create mode 100644 src/sw_64/Gget_save_loc.c + create mode 100644 src/sw_64/Gglobal.c + create mode 100644 src/sw_64/Ginit.c + create mode 100644 src/sw_64/Ginit_local.c + create mode 100644 src/sw_64/Ginit_remote.c + create mode 100644 src/sw_64/Gis_signal_frame.c + create mode 100644 src/sw_64/Greg_states_iterate.c + create mode 100644 src/sw_64/Gregs.c + create mode 100644 src/sw_64/Gresume.c + create mode 100644 src/sw_64/Gstep.c + create mode 100644 src/sw_64/Gtrace.c.bak + create mode 100644 src/sw_64/Lapply_reg_state.c + create mode 100644 src/sw_64/Lcreate_addr_space.c + create mode 100644 src/sw_64/Lget_proc_info.c + create mode 100644 src/sw_64/Lget_save_loc.c + create mode 100644 src/sw_64/Lglobal.c + create mode 100644 src/sw_64/Linit.c + create mode 100644 src/sw_64/Linit_local.c + create mode 100644 src/sw_64/Linit_remote.c + create mode 100644 src/sw_64/Lis_signal_frame.c + create mode 100644 src/sw_64/Lreg_states_iterate.c + create mode 100644 src/sw_64/Lregs.c + create mode 100644 src/sw_64/Lresume.c + create mode 100644 src/sw_64/Lstep.c + create mode 100644 src/sw_64/Ltrace.c.bak + create mode 100644 src/sw_64/elfxx.c + create mode 100644 src/sw_64/gen-offsets.c + create mode 100644 src/sw_64/getcontext.S + create mode 100644 src/sw_64/init.h + create mode 100644 src/sw_64/is_fpreg.c + create mode 100644 src/sw_64/offsets.h + create mode 100644 src/sw_64/regname.c + create mode 100644 src/sw_64/siglongjmp.S + create mode 100644 src/sw_64/unwind_i.h + +diff --git a/Makefile.am b/Makefile.am +index 0d5eee0..06f4328 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -51,7 +51,9 @@ endif + if ARCH_LOONGARCH64 + include_HEADERS += include/libunwind-loongarch64.h + endif +- ++if ARCH_SW_64 ++include_HEADERS += include/libunwind-sw_64.h ++endif + if !REMOTE_ONLY + include_HEADERS += include/libunwind.h + if BUILD_UNWIND_HEADER +@@ -104,6 +106,9 @@ noinst_HEADERS = include/dwarf.h include/dwarf_i.h include/dwarf-eh.h \ + include/tdep-loongarch64/dwarf-config.h \ + include/tdep-loongarch64/jmpbuf.h \ + include/tdep-loongarch64/libunwind_i.h \ ++ include/tdep-sw_64/dwarf-config.h \ ++ include/tdep-sw_64/jmpbuf.h \ ++ include/tdep-sw_64/libunwind_i.h \ + include/tdep/libunwind_i.h \ + include/tdep/jmpbuf.h include/tdep/dwarf-config.h + +diff --git a/README b/README +index 26e1a96..8098245 100644 +--- a/README ++++ b/README +@@ -18,6 +18,7 @@ This library supports several architecture/operating-system combinations: + | Linux | PARISC | Works well, but C library missing unwind-info | + | Linux | Tilegx | 64-bit mode only | + | Linux | MIPS | ✓ | ++| Linux | SW_64 | 64-bit only | + | Linux | RISC-V | 64-bit only | + | Linux | LoongArch | 64-bit only | + | HP-UX | IA-64 | Mostly works, but known to have serious limitations | +@@ -47,6 +48,7 @@ such dependencies + | ia64 | p | r | + | loongarch | p | | + | mips | p | | ++| sw_64 | p | p | + | ppc32 | r | | + | ppc64 | r | r | + | riscv | p | p | +diff --git a/configure.ac b/configure.ac +index fc69543..0b4c7bd 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -37,7 +37,15 @@ case "$ac_cv_search_dlopen" in + esac + + dnl Checks for header files. +-AC_HEADER_STDC ++m4_warn([obsolete], ++[The preprocessor macro `STDC_HEADERS' is obsolete. ++ Except in unusual embedded environments, you can safely include all ++ ISO C90 headers unconditionally.])dnl ++# Autoupdate added the next two lines to ensure that your configure ++# script's behavior did not change. They are probably safe to remove. ++##AC_CHECK_INCLUDES_DEFAULT // LIJM20250217: this macro does not define on sw6a and sw6b ++AC_PROG_EGREP ++ + AC_CHECK_HEADERS(asm/ptrace_offsets.h asm/ptrace.h asm/vsyscall.h endian.h sys/endian.h \ + sys/param.h execinfo.h ia64intrin.h sys/uc_access.h unistd.h signal.h \ + sys/types.h sys/procfs.h sys/ptrace.h sys/syscall.h byteswap.h elf.h \ +@@ -103,6 +111,7 @@ AC_DEFUN([SET_ARCH],[ + [tile*],[$2=tilegx], + [riscv*],[$2=riscv], + [loongarch64*],[$2=loongarch64], ++ [sw_64*],[$2=sw_64], + [$2=$1]) + ]) dnl SET_ARCH + +@@ -125,7 +134,7 @@ esac + + AC_ARG_ENABLE(coredump, + AS_HELP_STRING([--enable-coredump],[building libunwind-coredump library]),, +- [AS_CASE([$host_arch], [aarch64*|arm*|mips*|sh*|x86*|tile*|riscv*|loongarch64], [enable_coredump=yes], [enable_coredump=no])] ++ [AS_CASE([$host_arch], [aarch64*|arm*|mips*|sh*|x86*|tile*|riscv*|loongarch64|sw_64*], [enable_coredump=yes], [enable_coredump=no])] + ) + + AC_MSG_CHECKING([if we should build libunwind-coredump]) +@@ -195,6 +204,7 @@ AM_CONDITIONAL(ARCH_TILEGX, test x$target_arch = xtilegx) + AM_CONDITIONAL(ARCH_S390X, test x$target_arch = xs390x) + AM_CONDITIONAL(ARCH_RISCV, test x$target_arch = xriscv) + AM_CONDITIONAL(ARCH_LOONGARCH64, test x$target_arch = xloongarch64) ++AM_CONDITIONAL(ARCH_SW_64, test x$target_arch = xsw_64) + AM_CONDITIONAL(OS_LINUX, expr x$target_os : xlinux >/dev/null) + AM_CONDITIONAL(OS_HPUX, expr x$target_os : xhpux >/dev/null) + AM_CONDITIONAL(OS_FREEBSD, expr x$target_os : xfreebsd >/dev/null) +@@ -205,7 +215,7 @@ AC_MSG_CHECKING([for ELF helper width]) + case "${target_arch}" in + (arm|hppa|ppc32|x86|sh) use_elf32=yes; AC_MSG_RESULT([32]);; + (aarch64|ia64|ppc64|x86_64|s390x|tilegx) use_elf64=yes; AC_MSG_RESULT([64]);; +-(mips|riscv|loongarch64) use_elfxx=yes; AC_MSG_RESULT([xx]);; ++(mips|riscv|loongarch64|sw_64) use_elfxx=yes; AC_MSG_RESULT([xx]);; + *) AC_MSG_ERROR([Unknown ELF target: ${target_arch}]) + esac + AM_CONDITIONAL(USE_ELF32, [test x$use_elf32 = xyes]) +@@ -253,6 +263,7 @@ case $target_arch in + tile*) enable_cxx_exceptions=no;; + s390x*) enable_cxx_exceptions=no;; + loongarch*) enable_cxx_exceptions=no;; ++ sw_64*) enable_cxx_exceptions=no;; + *) enable_cxx_exceptions=yes;; + esac + ]) +diff --git a/include/libunwind-sw_64.h b/include/libunwind-sw_64.h +new file mode 100644 +index 0000000..e082eb0 +--- /dev/null ++++ b/include/libunwind-sw_64.h +@@ -0,0 +1,166 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#ifndef LIBUNWIND_H ++#define LIBUNWIND_H ++ ++#if defined(__cplusplus) || defined(c_plusplus) ++extern "C" { ++#endif ++ ++#include ++#include ++ ++#define UNW_TARGET sw_64 ++#define UNW_TARGET_SW_64 1 ++ ++#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ ++ ++/* This needs to be big enough to accommodate "struct cursor", while ++ leaving some slack for future expansion. Changing this value will ++ require recompiling all users of this library. Stack allocation is ++ relatively cheap and unwind-state copying is relatively rare, so we ++ want to err on making it rather too big than too small. */ ++ ++/* FIXME for SW_64. Too big? What do other things use for similar tasks? */ ++#define UNW_TDEP_CURSOR_LEN 4096 ++ ++typedef uint64_t unw_word_t; ++typedef int32_t unw_sword_t; ++ ++typedef long double unw_tdep_fpreg_t; ++ ++typedef enum ++ { ++ UNW_SW_64_R0, ++ UNW_SW_64_R1, ++ UNW_SW_64_R2, ++ UNW_SW_64_R3, ++ UNW_SW_64_R4, ++ UNW_SW_64_R5, ++ UNW_SW_64_R6, ++ UNW_SW_64_R7, ++ UNW_SW_64_R8, ++ UNW_SW_64_R9, ++ UNW_SW_64_R10, ++ UNW_SW_64_R11, ++ UNW_SW_64_R12, ++ UNW_SW_64_R13, ++ UNW_SW_64_R14, ++ UNW_SW_64_R15, ++ UNW_SW_64_R16, ++ UNW_SW_64_R17, ++ UNW_SW_64_R18, ++ UNW_SW_64_R19, ++ UNW_SW_64_R20, ++ UNW_SW_64_R21, ++ UNW_SW_64_R22, ++ UNW_SW_64_R23, ++ UNW_SW_64_R24, ++ UNW_SW_64_R25, ++ UNW_SW_64_R26, ++ UNW_SW_64_R27, ++ UNW_SW_64_R28, ++ UNW_SW_64_R29, ++ UNW_SW_64_R30, ++ UNW_SW_64_R31, ++ UNW_SW_64_F0, ++ UNW_SW_64_F1, ++ UNW_SW_64_F2, ++ UNW_SW_64_F3, ++ UNW_SW_64_F4, ++ UNW_SW_64_F5, ++ UNW_SW_64_F6, ++ UNW_SW_64_F7, ++ UNW_SW_64_F8, ++ UNW_SW_64_F9, ++ UNW_SW_64_F10, ++ UNW_SW_64_F11, ++ UNW_SW_64_F12, ++ UNW_SW_64_F13, ++ UNW_SW_64_F14, ++ UNW_SW_64_F15, ++ UNW_SW_64_F16, ++ UNW_SW_64_F17, ++ UNW_SW_64_F18, ++ UNW_SW_64_F19, ++ UNW_SW_64_F20, ++ UNW_SW_64_F21, ++ UNW_SW_64_F22, ++ UNW_SW_64_F23, ++ UNW_SW_64_F24, ++ UNW_SW_64_F25, ++ UNW_SW_64_F26, ++ UNW_SW_64_F27, ++ UNW_SW_64_F28, ++ UNW_SW_64_F29, ++ UNW_SW_64_F30, ++ UNW_SW_64_F31, ++ UNW_SW_64_PC = 64, ++ ++ UNW_TDEP_LAST_REG = UNW_SW_64_PC, ++ ++ UNW_TDEP_IP = UNW_SW_64_R26, ++ UNW_TDEP_SP = UNW_SW_64_R30, ++ UNW_TDEP_EH = UNW_SW_64_R0 /* FIXME. */ ++ } ++sw_64_regnum_t; ++ ++ ++#define UNW_TDEP_NUM_EH_REGS 2 /* FIXME for SW_64. */ ++ ++typedef struct unw_tdep_save_loc ++ { ++ /* Additional target-dependent info on a save location. */ ++ } ++unw_tdep_save_loc_t; ++ ++/* On x86, we can directly use ucontext_t as the unwind context. FIXME for ++ SW_64. */ ++typedef ucontext_t unw_tdep_context_t; ++ ++#include "libunwind-dynamic.h" ++ ++typedef struct ++ { ++ /* no sw_64-specific auxiliary proc-info */ ++ } ++unw_tdep_proc_info_t; ++ ++#include "libunwind-common.h" ++ ++/* There is no getcontext() on SW_64. Use a stub version which only saves GP ++ registers. FIXME: Not ideal, may not be sufficient for all libunwind ++ use cases. */ ++#define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext) ++extern int unw_tdep_getcontext (ucontext_t *uc); ++ ++#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) ++extern int unw_tdep_is_fpreg (int); ++ ++#if defined(__cplusplus) || defined(c_plusplus) ++} ++#endif ++ ++#endif /* LIBUNWIND_H */ +diff --git a/include/libunwind.h.in b/include/libunwind.h.in +index 0ac692b..6593ed3 100644 +--- a/include/libunwind.h.in ++++ b/include/libunwind.h.in +@@ -31,6 +31,8 @@ + # include "libunwind-riscv.h" + #elif defined __loongarch64 + # include "libunwind-loongarch64.h" ++#elif defined __sw_64__ ++# include "libunwind-sw_64.h" + #else + # error "Unsupported arch" + #endif +diff --git a/include/tdep-sw_64/dwarf-config.h b/include/tdep-sw_64/dwarf-config.h +new file mode 100644 +index 0000000..3aa620d +--- /dev/null ++++ b/include/tdep-sw_64/dwarf-config.h +@@ -0,0 +1,51 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ Copyright (C) 2012 Tommi Rantala ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#ifndef dwarf_config_h ++#define dwarf_config_h ++ ++/* This is FIRST_PSEUDO_REGISTER in GCC, since DWARF_FRAME_REGISTERS is not ++ explicitly defined. */ ++#define DWARF_NUM_PRESERVED_REGS 65 ++ ++#define dwarf_to_unw_regnum(reg) (((reg) < 32) ? (reg) : 0) ++ ++/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ ++#define dwarf_is_big_endian(addr_space) 0//((addr_space)->big_endian) ++ ++/* Convert a pointer to a dwarf_cursor structure to a pointer to ++ unw_cursor_t. */ ++#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) ++ ++typedef struct dwarf_loc ++ { ++ unw_word_t val; ++#ifndef UNW_LOCAL_ONLY ++ unw_word_t type; /* see DWARF_LOC_TYPE_* macros. */ ++#endif ++ } ++dwarf_loc_t; ++ ++#endif /* dwarf_config_h */ +diff --git a/include/tdep-sw_64/jmpbuf.h b/include/tdep-sw_64/jmpbuf.h +new file mode 100644 +index 0000000..8174525 +--- /dev/null ++++ b/include/tdep-sw_64/jmpbuf.h +@@ -0,0 +1,32 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ ++ ++/* LIJM20250106:fix for sw_64 ! loongarch was fix it by glibc,but it seems not used in sw_64 ,reference by 1.8.0*/ ++ ++#define JB_SP 4 ++#define JB_RP 5 ++#define JB_MASK_SAVED 6 ++#define JB_MASK 7 +diff --git a/include/tdep-sw_64/libunwind_i.h b/include/tdep-sw_64/libunwind_i.h +new file mode 100644 +index 0000000..423bc5c +--- /dev/null ++++ b/include/tdep-sw_64/libunwind_i.h +@@ -0,0 +1,338 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#ifndef SW_64_LIBUNWIND_I_H ++#define SW_64_LIBUNWIND_I_H ++ ++/* Target-dependent definitions that are internal to libunwind but need ++ to be shared with target-independent code. */ ++ ++#include ++#include ++#include ++# include "elf64.h" ++#include "mempool.h" ++#include "dwarf.h" ++ ++typedef struct ++ { ++ /* no sw_64-specific fast trace */ ++ uint64_t virtual_address; ++ int64_t frame_type : 2; /* unw_tdep_frame_type_t classification */ ++ int64_t last_frame : 1; /* non-zero if last frame in chain */ ++ int64_t cfa_reg_sp : 1; /* cfa dwarf base register is rsp vs. rbp */ ++ int64_t cfa_reg_offset: 30; ++ int64_t fp_cfa_offset : 15; /* fp saved at this offset from cfa (-1 = not saved) */ ++ int64_t lr_cfa_offset : 26; /* lr saved at this offset from cfa (-1 = not saved) */ ++ int64_t sp_cfa_offset : 30; /* sp saved at this offset from cfa (-1 = not saved) */ ++ } ++unw_tdep_frame_t; ++ ++struct unw_addr_space ++ { ++ struct unw_accessors acc; ++ ++ unsigned int addr_size; ++ ++ unw_caching_policy_t caching_policy; ++ _Atomic uint32_t cache_generation; ++ unw_word_t dyn_generation; /* see dyn-common.h */ ++ unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ ++ struct dwarf_rs_cache global_cache; ++ struct unw_debug_frame_list *debug_frames; ++}; ++ ++#define tdep_big_endian(as) 0//((as)->big_endian) ++ ++struct cursor ++ { ++ struct dwarf_cursor dwarf; /* must be first */ ++ unw_tdep_frame_t frame_info; ++ ++ enum ++ { ++ SW_SCF_NONE, /* no signal frame */ ++ SW_SCF_LINUX_SIGFRAME, /* non-RT signal frame */ ++ SW_SCF_LINUX_RT_SIGFRAME, /* RT signal frame */ ++ } ++ ++ sigcontext_format; ++ unw_word_t sigcontext_addr; ++ unw_word_t sigcontext_sp; ++ unw_word_t sigcontext_pc; ++ unw_word_t ucontext_addr; ++ int validate; ++ }; ++ ++#define DWARF_GET_LOC(l) ((l).val) ++ ++#ifndef UNW_REMOTE_ONLY ++typedef long sw_64_reg_t; ++#endif ++ ++#ifdef UNW_LOCAL_ONLY ++# define DWARF_NULL_LOC DWARF_LOC (0, 0) ++# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) ++# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) ++# define DWARF_IS_REG_LOC(l) 0 ++# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) (intptr_t) \ ++ tdep_uc_addr((c)->as_arg, (r)), 0)) ++# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) ++# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) (intptr_t) \ ++ tdep_uc_addr((c)->as_arg, (r)), 0)) ++ ++/* FIXME: Implement these for the SW_64 FPU. */ ++static inline int ++dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) ++{ ++ if (!DWARF_GET_LOC (loc)) ++ return -1; ++ *val = *(unw_fpreg_t *) (intptr_t) DWARF_GET_LOC (loc); ++ return 0; ++} ++ ++static inline int ++dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) ++{ ++ if (!DWARF_GET_LOC (loc)) ++ return -1; ++ *(unw_fpreg_t *) (intptr_t) DWARF_GET_LOC (loc) = val; ++ return 0; ++} ++ ++static inline int ++dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) ++{ ++ if (!DWARF_GET_LOC (loc)) ++ return -1; ++ *val = *(sw_64_reg_t *) (intptr_t) DWARF_GET_LOC (loc); ++ return 0; ++} ++ ++static inline int ++dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) ++{ ++ if (!DWARF_GET_LOC (loc)) ++ return -1; ++ *(sw_64_reg_t *) (intptr_t) DWARF_GET_LOC (loc) = val; ++ return 0; ++} ++ ++#else /* !UNW_LOCAL_ONLY */ ++# define DWARF_LOC_TYPE_FP (1 << 0) ++# define DWARF_LOC_TYPE_REG (1 << 1) ++# define DWARF_NULL_LOC DWARF_LOC (0, 0) ++# define DWARF_IS_NULL_LOC(l) \ ++ ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) ++# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) ++# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) ++# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) ++# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) ++# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) ++# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ ++ | DWARF_LOC_TYPE_FP)) ++ ++static inline int ++read_s32 (struct dwarf_cursor *c, unw_word_t addr, unw_word_t *val) ++{ ++ int offset = addr & 4; ++ int ret; ++ unw_word_t memval; ++ ++ ret = (*c->as->acc.access_mem) (c->as, addr - offset, &memval, 0, c->as_arg); ++ if (ret < 0) ++ return ret; ++ ++ *val = (int32_t) (memval >> 32); ++ ++ return 0; ++} ++ ++static inline int ++write_s32 (struct dwarf_cursor *c, unw_word_t addr, const unw_word_t *val) ++{ ++ int offset = addr & 4; ++ int ret; ++ unw_word_t memval; ++ ++ ret = (*c->as->acc.access_mem) (c->as, addr - offset, &memval, 0, c->as_arg); ++ if (ret < 0) ++ return ret; ++ ++ memval = (memval & 0xffffffffLL) | (uint32_t) (*val << 32); ++ ++ return (*c->as->acc.access_mem) (c->as, addr - offset, &memval, 1, c->as_arg); ++} ++ ++/* FIXME: Implement these for the SW_64 FPU. */ ++static inline int ++dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) ++{ ++ char *valp = (char *) &val; ++ unw_word_t addr; ++ ++ if (DWARF_IS_NULL_LOC (loc)) ++ return -UNW_EBADREG; ++ ++ if (DWARF_IS_REG_LOC (loc)) ++ return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), ++ val, 0, c->as_arg); ++ ++ addr = DWARF_GET_LOC (loc); ++#if 0 ++ int ret; ++ if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, ++ 0, c->as_arg)) < 0) ++ return ret; ++ ++ return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, 0, ++ c->as_arg); ++#else ++ return (*c->as->acc.access_mem) (c->as, addr,(unw_word_t *) valp,0,c->as_arg); ++#endif ++} ++ ++static inline int ++dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) ++{ ++ char *valp = (char *) &val; ++ unw_word_t addr; ++ ++ if (DWARF_IS_NULL_LOC (loc)) ++ return -UNW_EBADREG; ++ ++ if (DWARF_IS_REG_LOC (loc)) ++ return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), ++ &val, 1, c->as_arg); ++ ++ addr = DWARF_GET_LOC (loc); ++#if 0 ++ int ret; ++ if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, ++ 1, c->as_arg)) < 0) ++ return ret; ++ ++ return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, ++ 1, c->as_arg); ++#else ++ return (*c->as->acc.access_mem) (c->as, addr, (unw_word_t *) valp,1, c->as_arg); ++#endif ++} ++ ++static inline int ++dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) ++{ ++ if (DWARF_IS_NULL_LOC (loc)) ++ return -UNW_EBADREG; ++ ++ /* If a code-generator were to save a value of type unw_word_t in a ++ floating-point register, we would have to support this case. I ++ suppose it could happen with MMX registers, but does it really ++ happen? */ ++ assert (!DWARF_IS_FP_LOC (loc)); ++ ++ if (DWARF_IS_REG_LOC (loc)) ++ return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, ++ 0, c->as_arg); ++ else ++ return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, ++ 0, c->as_arg); ++} ++ ++static inline int ++dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) ++{ ++ if (DWARF_IS_NULL_LOC (loc)) ++ return -UNW_EBADREG; ++ ++ /* If a code-generator were to save a value of type unw_word_t in a ++ floating-point register, we would have to support this case. I ++ suppose it could happen with MMX registers, but does it really ++ happen? */ ++ assert (!DWARF_IS_FP_LOC (loc)); ++ ++ if (DWARF_IS_REG_LOC (loc)) ++ return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, ++ 1, c->as_arg); ++ else ++ return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, ++ 1, c->as_arg); ++} ++ ++#endif /* !UNW_LOCAL_ONLY */ ++ ++#define tdep_getcontext_trace unw_getcontext ++#define tdep_init_done UNW_OBJ(init_done) ++#define tdep_init UNW_OBJ(init) ++/* Platforms that support UNW_INFO_FORMAT_TABLE need to define ++ tdep_search_unwind_table. */ ++#define tdep_search_unwind_table dwarf_search_unwind_table ++#define tdep_find_unwind_table dwarf_find_unwind_table ++#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr) ++#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) ++#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) ++#define tdep_access_reg UNW_OBJ(access_reg) ++#define tdep_access_fpreg UNW_OBJ(access_fpreg) ++#define tdep_fetch_frame(c,ip,n) do {} while(0) ++#define tdep_cache_frame(c) 0 ++#define tdep_reuse_frame(c,frame) do {} while(0) ++#define tdep_stash_frame(c,rs) do {} while(0) ++#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) ++ ++#ifdef UNW_LOCAL_ONLY ++# define tdep_find_proc_info(c,ip,n) \ ++ dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ ++ (c)->as_arg) ++# define tdep_put_unwind_info(as,pi,arg) \ ++ dwarf_put_unwind_info((as), (pi), (arg)) ++#else ++# define tdep_find_proc_info(c,ip,n) \ ++ (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ ++ (c)->as_arg) ++# define tdep_put_unwind_info(as,pi,arg) \ ++ (*(as)->acc.put_unwind_info)((as), (pi), (arg)) ++#endif ++ ++#define tdep_get_as(c) ((c)->dwarf.as) ++#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) ++#define tdep_get_ip(c) ((c)->dwarf.ip) ++ ++extern atomic_bool tdep_init_done; ++//extern int tdep_init_done; ++ ++extern void tdep_init (void); ++extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, ++ unw_dyn_info_t *di, unw_proc_info_t *pi, ++ int need_unwind_info, void *arg); ++extern void *tdep_uc_addr (ucontext_t *uc, int reg); ++extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, ++ unsigned long *segbase, unsigned long *mapoff, ++ char *path, size_t pathlen); ++extern void tdep_get_exe_image_path (char *path); ++extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, ++ unw_word_t *valp, int write); ++extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, ++ unw_fpreg_t *valp, int write); ++//extern int tdep_trace (unw_cursor_t *cursor, void **addresses, int *n); ++#endif /* SW_64_LIBUNWIND_I_H */ +diff --git a/include/tdep/dwarf-config.h b/include/tdep/dwarf-config.h +index a37f422..ce21344 100644 +--- a/include/tdep/dwarf-config.h ++++ b/include/tdep/dwarf-config.h +@@ -29,6 +29,8 @@ + # include "tdep-riscv/dwarf-config.h" + #elif defined __loongarch64 + # include "tdep-loongarch64/dwarf-config.h" ++#elif defined __sw_64__ ++# include "tdep-sw_64/dwarf-config.h" + #else + # error "Unsupported arch" + #endif +diff --git a/include/tdep/jmpbuf.h b/include/tdep/jmpbuf.h +index 01b9ee0..d9c9f1b 100644 +--- a/include/tdep/jmpbuf.h ++++ b/include/tdep/jmpbuf.h +@@ -27,6 +27,8 @@ + # include "tdep-riscv/jmpbuf.h" + #elif defined __loongarch64 + # include "tdep-loongarch64/jmpbuf.h" ++#elif defined __sw_64__ ++# include "tdep-sw_64/jmpbuf.h" + #else + # error "Unsupported arch" + #endif +diff --git a/include/tdep/libunwind_i.h.in b/include/tdep/libunwind_i.h.in +index 1bacc3a..5a75d7b 100644 +--- a/include/tdep/libunwind_i.h.in ++++ b/include/tdep/libunwind_i.h.in +@@ -31,6 +31,8 @@ + # include "tdep-riscv/libunwind_i.h" + #elif defined __loongarch64 + # include "tdep-loongarch64/libunwind_i.h" ++#elif defined __sw_64__ ++# include "tdep-sw_64/libunwind_i.h" + #else + # error "Unsupported arch" + #endif +diff --git a/src/Makefile.am b/src/Makefile.am +index 35c7f68..2f7478c 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -31,6 +31,9 @@ endif + if ARCH_LOONGARCH64 + lib_LTLIBRARIES += libunwind-loongarch64.la + endif ++if ARCH_SW_64 ++ lib_LTLIBRARIES += libunwind-sw_64.la ++endif + if ARCH_MIPS + lib_LTLIBRARIES += libunwind-mips.la + endif +@@ -375,6 +378,27 @@ libunwind_mips_la_SOURCES_mips = $(libunwind_la_SOURCES_mips_common) \ + mips/Gglobal.c mips/Ginit.c mips/Ginit_local.c mips/Ginit_remote.c \ + mips/Gis_signal_frame.c mips/Gregs.c mips/Gresume.c mips/Gstep.c + ++# The list of files that go info libunwind and libunwind-sw_64: ++noinst_HEADERS += sw_64/init.h sw_64/offsets.h sw_64/unwind_i.h ++libunwind_la_SOURCES_sw_64_common = $(libunwind_la_SOURCES_common) \ ++ sw_64/is_fpreg.c sw_64/regname.c ++ ++# The list of files that go into libunwind: ++libunwind_la_SOURCES_sw_64 = $(libunwind_la_SOURCES_sw_64_common) \ ++ $(libunwind_la_SOURCES_local) \ ++ sw_64/getcontext.S \ ++ sw_64/Lapply_reg_state.c sw_64/Lreg_states_iterate.c \ ++ sw_64/Lcreate_addr_space.c sw_64/Lget_proc_info.c sw_64/Lget_save_loc.c \ ++ sw_64/Lglobal.c sw_64/Linit.c sw_64/Linit_local.c sw_64/Linit_remote.c \ ++ sw_64/Lis_signal_frame.c sw_64/Lregs.c sw_64/Lresume.c sw_64/Lstep.c ++ ++libunwind_sw_64_la_SOURCES_sw_64 = $(libunwind_la_SOURCES_sw_64_common) \ ++ $(libunwind_la_SOURCES_generic) \ ++ sw_64/Gapply_reg_state.c sw_64/Greg_states_iterate.c \ ++ sw_64/Gcreate_addr_space.c sw_64/Gget_proc_info.c sw_64/Gget_save_loc.c \ ++ sw_64/Gglobal.c sw_64/Ginit.c sw_64/Ginit_local.c sw_64/Ginit_remote.c \ ++ sw_64/Gis_signal_frame.c sw_64/Gregs.c sw_64/Gresume.c sw_64/Gstep.c ++ + # The list of files that go info libunwind and libunwind-tilegx: + noinst_HEADERS += tilegx/init.h tilegx/offsets.h tilegx/unwind_i.h + libunwind_la_SOURCES_tilegx_common = $(libunwind_la_SOURCES_common) \ +@@ -727,6 +751,17 @@ if !REMOTE_ONLY + endif + libunwind_setjmp_la_SOURCES += mips/siglongjmp.S + else ++if ARCH_SW_64 ++ libunwind_la_SOURCES = $(libunwind_la_SOURCES_sw_64) ++ libunwind_sw_64_la_SOURCES = $(libunwind_sw_64_la_SOURCES_sw_64) ++ libunwind_sw_64_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) ++ libunwind_sw_64_la_LIBADD = libunwind-dwarf-generic.la ++ libunwind_sw_64_la_LIBADD += libunwind-elfxx.la ++if !REMOTE_ONLY ++ libunwind_sw_64_la_LIBADD += libunwind.la -lc ++endif ++ libunwind_setjmp_la_SOURCES += sw_64/siglongjmp.S ++else + if ARCH_TILEGX + libunwind_la_SOURCES = $(libunwind_la_SOURCES_tilegx) + libunwind_tilegx_la_SOURCES = $(libunwind_tilegx_la_SOURCES_tilegx) +@@ -835,6 +870,7 @@ endif # ARCH_LOONGARCH64 + endif # ARCH_RISCV + endif # ARCH_TILEGX + endif # ARCH_MIPS ++endif # ARCH_SW_64 + endif # ARCH_HPPA + endif # ARCH_IA64 + endif # ARCH_ARM +@@ -860,6 +896,7 @@ EXTRA_DIST = $(libunwind_la_SOURCES_aarch64) \ + $(libunwind_la_SOURCES_ia64) \ + $(libunwind_la_EXTRAS_ia64) \ + $(libunwind_la_SOURCES_mips) \ ++ $(libunwind_la_SOURCES_sw_64) \ + $(libunwind_la_SOURCES_sh) \ + $(libunwind_la_SOURCES_x86) \ + $(libunwind_la_SOURCES_os_freebsd) \ +@@ -875,6 +912,7 @@ EXTRA_DIST = $(libunwind_la_SOURCES_aarch64) \ + $(libunwind_hppa_la_SOURCES_hppa) \ + $(libunwind_ia64_la_SOURCES_ia64) \ + $(libunwind_mips_la_SOURCES_mips) \ ++ $(libunwind_sw_64_la_SOURCES_sw_64) \ + $(libunwind_sh_la_SOURCES_sh) \ + $(libunwind_x86_la_SOURCES_x86) \ + $(libunwind_x86_64_la_SOURCES_x86_64) +diff --git a/src/coredump/_UCD_access_reg_linux.c b/src/coredump/_UCD_access_reg_linux.c +index bb68261..c70f571 100644 +--- a/src/coredump/_UCD_access_reg_linux.c ++++ b/src/coredump/_UCD_access_reg_linux.c +@@ -185,6 +185,43 @@ _UCD_access_reg (unw_addr_space_t as, + [UNW_X86_64_RSP] = offsetof(struct user_regs_struct, rsp) / sizeof(long), + [UNW_X86_64_RIP] = offsetof(struct user_regs_struct, rip) / sizeof(long), + }; ++#elif defined(UNW_TARGET_SW_64) ++ static const uint8_t remap_regs[] = ++ { ++ [UNW_SW_64_R0] = 0, ++ [UNW_SW_64_R1] = 1, ++ [UNW_SW_64_R2] = 2, ++ [UNW_SW_64_R3] = 3, ++ [UNW_SW_64_R4] = 4, ++ [UNW_SW_64_R5] = 5, ++ [UNW_SW_64_R6] = 6, ++ [UNW_SW_64_R7] = 7, ++ [UNW_SW_64_R8] = 8, ++ [UNW_SW_64_R9] = 9, ++ [UNW_SW_64_R10] = 10, ++ [UNW_SW_64_R11] = 11, ++ [UNW_SW_64_R12] = 12, ++ [UNW_SW_64_R13] = 13, ++ [UNW_SW_64_R14] = 14, ++ [UNW_SW_64_R15] = 15, ++ [UNW_SW_64_R16] = 16, ++ [UNW_SW_64_R17] = 17, ++ [UNW_SW_64_R18] = 18, ++ [UNW_SW_64_R19] = 19, ++ [UNW_SW_64_R20] = 20, ++ [UNW_SW_64_R21] = 21, ++ [UNW_SW_64_R22] = 22, ++ [UNW_SW_64_R23] = 23, ++ [UNW_SW_64_R24] = 24, ++ [UNW_SW_64_R25] = 25, ++ [UNW_SW_64_R26] = 26, ++ [UNW_SW_64_R27] = 27, ++ [UNW_SW_64_R28] = 28, ++ [UNW_SW_64_R29] = 29, ++ [UNW_SW_64_R30] = 30, ++ [UNW_SW_64_R31] = 31, ++ [UNW_SW_64_PC] = 32, ++ }; + #else + #error Port me + #endif +diff --git a/src/ptrace/_UPT_reg_offset.c b/src/ptrace/_UPT_reg_offset.c +index ea13e6d..da63d4f 100644 +--- a/src/ptrace/_UPT_reg_offset.c ++++ b/src/ptrace/_UPT_reg_offset.c +@@ -681,6 +681,72 @@ const int _UPT_reg_offset[UNW_REG_LAST + 1] = + [UNW_TILEGX_R54] = 0x1b0, + [UNW_TILEGX_R55] = 0x1b8, + [UNW_TILEGX_PC] = 0x1a0 ++#elif defined(UNW_TARGET_SW_64) ++ [UNW_SW_64_R0] = 0x00, ++ [UNW_SW_64_R1] = 0x1, ++ [UNW_SW_64_R2] = 0x2, ++ [UNW_SW_64_R3] = 0x3, ++ [UNW_SW_64_R4] = 0x4, ++ [UNW_SW_64_R5] = 0x5, ++ [UNW_SW_64_R6] = 0x6, ++ [UNW_SW_64_R7] = 0x7, ++ [UNW_SW_64_R8] = 0x8, ++ [UNW_SW_64_R9] = 0x9, ++ [UNW_SW_64_R10] = 10, ++ [UNW_SW_64_R11] = 11, ++ [UNW_SW_64_R12] = 12, ++ [UNW_SW_64_R13] = 13, ++ [UNW_SW_64_R14] = 14, ++ [UNW_SW_64_R15] = 0xf, ++ [UNW_SW_64_R16] = 0x10, ++ [UNW_SW_64_R17] = 0x11, ++ [UNW_SW_64_R18] = 0x12, ++ [UNW_SW_64_R19] = 0x13, ++ [UNW_SW_64_R20] = 0x14, ++ [UNW_SW_64_R21] = 0x15, ++ [UNW_SW_64_R22] = 0x16, ++ [UNW_SW_64_R23] = 0x17, ++ [UNW_SW_64_R24] = 0x18, ++ [UNW_SW_64_R25] = 0x19, ++ [UNW_SW_64_R26] = 0x1a, ++ [UNW_SW_64_R27] = 0x1b, ++ [UNW_SW_64_R28] = 0x1c, ++ [UNW_SW_64_R29] = 0x1d, ++ [UNW_SW_64_R30] = 0x1e, ++ [UNW_SW_64_R31] = 0x1f, ++ [UNW_SW_64_F0] = 0x20, ++ [UNW_SW_64_F1] = 0x21, ++ [UNW_SW_64_F2] = 0x22, ++ [UNW_SW_64_F3] = 0x23, ++ [UNW_SW_64_F4] = 0x24, ++ [UNW_SW_64_F5] = 0x25, ++ [UNW_SW_64_F6] = 0x26, ++ [UNW_SW_64_F7] = 0x27, ++ [UNW_SW_64_F8] = 0x28, ++ [UNW_SW_64_F9] = 0x29, ++ [UNW_SW_64_F10] = 0x2a, ++ [UNW_SW_64_F11] = 0x2b, ++ [UNW_SW_64_F12] = 0x2c, ++ [UNW_SW_64_F13] = 0x2d, ++ [UNW_SW_64_F14] = 0x2e, ++ [UNW_SW_64_F15] = 0x2f, ++ [UNW_SW_64_F16] = 0x30, ++ [UNW_SW_64_F17] = 0x31, ++ [UNW_SW_64_F18] = 0x32, ++ [UNW_SW_64_F19] = 0x33, ++ [UNW_SW_64_F20] = 0x34, ++ [UNW_SW_64_F21] = 0x35, ++ [UNW_SW_64_F22] = 0x36, ++ [UNW_SW_64_F23] = 0x37, ++ [UNW_SW_64_F24] = 0x38, ++ [UNW_SW_64_F25] = 0x39, ++ [UNW_SW_64_F26] = 0x3a, ++ [UNW_SW_64_F27] = 0x3b, ++ [UNW_SW_64_F28] = 0x3c, ++ [UNW_SW_64_F29] = 0x3d, ++ [UNW_SW_64_F30] = 0x3e, ++ [UNW_SW_64_F31] = 0x3f, ++ [UNW_SW_64_PC] = 0x40, + #elif defined(UNW_TARGET_S390X) + [UNW_S390X_R0] = 0x10, + [UNW_S390X_R1] = 0x18, +diff --git a/src/sw_64/Gapply_reg_state.c b/src/sw_64/Gapply_reg_state.c +new file mode 100644 +index 0000000..82f056d +--- /dev/null ++++ b/src/sw_64/Gapply_reg_state.c +@@ -0,0 +1,37 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. ++ Contributed by David Mosberger-Tang ++ ++ Modified for x86_64 by Max Asbock ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++ ++int ++unw_apply_reg_state (unw_cursor_t *cursor, ++ void *reg_states_data) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ ++ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); ++} +diff --git a/src/sw_64/Gcreate_addr_space.c b/src/sw_64/Gcreate_addr_space.c +new file mode 100644 +index 0000000..a9690c8 +--- /dev/null ++++ b/src/sw_64/Gcreate_addr_space.c +@@ -0,0 +1,51 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include ++ ++#include "unwind_i.h" ++ ++unw_addr_space_t ++unw_create_addr_space (unw_accessors_t *a, int byte_order) ++{ ++#ifdef UNW_LOCAL_ONLY ++ return NULL; ++#else ++ unw_addr_space_t as; ++ ++ /* Sw_64 supports only little-endian. */ ++ if (byte_order != 0 && byte_order != __LITTLE_ENDIAN) ++ return NULL; ++ ++ as = malloc (sizeof (*as)); ++ if (!as) ++ return NULL; ++ ++ memset (as, 0, sizeof (*as)); ++ ++ as->acc = *a; ++ ++ return as; ++#endif ++} +diff --git a/src/sw_64/Gget_proc_info.c b/src/sw_64/Gget_proc_info.c +new file mode 100644 +index 0000000..04c4326 +--- /dev/null ++++ b/src/sw_64/Gget_proc_info.c +@@ -0,0 +1,44 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++ ++int ++unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ int ret; ++ ++ ret = dwarf_make_proc_info (&c->dwarf); ++ if (ret < 0) { ++ /* Construct a dummy proc info if Dwarf failed */ ++ memset (pi, 0, sizeof (*pi)); ++ pi->start_ip = c->dwarf.ip; ++ pi->end_ip = c->dwarf.ip + 4; ++ return 0; ++ } ++ ++ *pi = c->dwarf.pi; ++ return 0; ++} +diff --git a/src/sw_64/Gget_save_loc.c b/src/sw_64/Gget_save_loc.c +new file mode 100644 +index 0000000..e46da9f +--- /dev/null ++++ b/src/sw_64/Gget_save_loc.c +@@ -0,0 +1,132 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++ ++/* FIXME for SW_64. */ ++ ++int ++unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ dwarf_loc_t loc; ++ ++ loc = DWARF_NULL_LOC; /* default to "not saved" */ ++ ++ switch (reg) ++ { ++ case UNW_SW_64_R0: ++ case UNW_SW_64_R1: ++ case UNW_SW_64_R2: ++ case UNW_SW_64_R3: ++ case UNW_SW_64_R4: ++ case UNW_SW_64_R5: ++ case UNW_SW_64_R6: ++ case UNW_SW_64_R7: ++ case UNW_SW_64_R8: ++ case UNW_SW_64_R9: ++ case UNW_SW_64_R10: ++ case UNW_SW_64_R11: ++ case UNW_SW_64_R12: ++ case UNW_SW_64_R13: ++ case UNW_SW_64_R14: ++ case UNW_SW_64_R15: ++ case UNW_SW_64_R16: ++ case UNW_SW_64_R17: ++ case UNW_SW_64_R18: ++ case UNW_SW_64_R19: ++ case UNW_SW_64_R20: ++ case UNW_SW_64_R21: ++ case UNW_SW_64_R22: ++ case UNW_SW_64_R23: ++ case UNW_SW_64_R24: ++ case UNW_SW_64_R25: ++ case UNW_SW_64_R26: ++ case UNW_SW_64_R27: ++ case UNW_SW_64_R28: ++ case UNW_SW_64_R29: ++ case UNW_SW_64_R30: ++ case UNW_SW_64_R31: ++ case UNW_SW_64_F0: ++ case UNW_SW_64_F1: ++ case UNW_SW_64_F2: ++ case UNW_SW_64_F3: ++ case UNW_SW_64_F4: ++ case UNW_SW_64_F5: ++ case UNW_SW_64_F6: ++ case UNW_SW_64_F7: ++ case UNW_SW_64_F8: ++ case UNW_SW_64_F9: ++ case UNW_SW_64_F10: ++ case UNW_SW_64_F11: ++ case UNW_SW_64_F12: ++ case UNW_SW_64_F13: ++ case UNW_SW_64_F14: ++ case UNW_SW_64_F15: ++ case UNW_SW_64_F16: ++ case UNW_SW_64_F17: ++ case UNW_SW_64_F18: ++ case UNW_SW_64_F19: ++ case UNW_SW_64_F20: ++ case UNW_SW_64_F21: ++ case UNW_SW_64_F22: ++ case UNW_SW_64_F23: ++ case UNW_SW_64_F24: ++ case UNW_SW_64_F25: ++ case UNW_SW_64_F26: ++ case UNW_SW_64_F27: ++ case UNW_SW_64_F28: ++ case UNW_SW_64_F29: ++ case UNW_SW_64_F30: ++ case UNW_SW_64_F31: ++ case UNW_SW_64_PC: ++ loc = c->dwarf.loc[reg - UNW_SW_64_R0]; ++ break; ++ ++ default: ++ break; ++ } ++ ++ memset (sloc, 0, sizeof (*sloc)); ++ ++ if (DWARF_IS_NULL_LOC (loc)) ++ { ++ sloc->type = UNW_SLT_NONE; ++ return 0; ++ } ++ ++#if !defined(UNW_LOCAL_ONLY) ++ if (DWARF_IS_REG_LOC (loc)) ++ { ++ sloc->type = UNW_SLT_REG; ++ sloc->u.regnum = DWARF_GET_LOC (loc); ++ } ++ else ++#endif ++ { ++ sloc->type = UNW_SLT_MEMORY; ++ sloc->u.addr = DWARF_GET_LOC (loc); ++ } ++ return 0; ++} +diff --git a/src/sw_64/Gglobal.c b/src/sw_64/Gglobal.c +new file mode 100644 +index 0000000..71fdabf +--- /dev/null ++++ b/src/sw_64/Gglobal.c +@@ -0,0 +1,57 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++#include "dwarf_i.h" ++ ++HIDDEN define_lock (sw_64_lock); ++HIDDEN atomic_bool tdep_init_done = 0; ++ ++HIDDEN void ++tdep_init (void) ++{ ++ intrmask_t saved_mask; ++ ++ sigfillset (&unwi_full_mask); ++// sigdelset(&unwi_full_mask, 5); /* LIJM20250210 */ ++ lock_acquire (&sw_64_lock, saved_mask); ++ { ++// if (atomic_load(&tdep_init_done)) ++ if (tdep_init_done) ++ /* another thread else beat us to it... */ ++ goto out; ++ ++ mi_init (); ++ ++ dwarf_init (); ++ ++#ifndef UNW_REMOTE_ONLY ++ sw_64_local_addr_space_init (); ++#endif ++ atomic_store(&tdep_init_done, 1); /* signal that we're initialized... */ ++ //tdep_init_done = 1; /* signal that we're initialized... */ ++ } ++ out: ++ lock_release (&sw_64_lock, saved_mask); ++} +diff --git a/src/sw_64/Ginit.c b/src/sw_64/Ginit.c +new file mode 100644 +index 0000000..45a2911 +--- /dev/null ++++ b/src/sw_64/Ginit.c +@@ -0,0 +1,197 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include ++#include ++ ++#include "unwind_i.h" ++ ++#ifdef UNW_REMOTE_ONLY ++ ++/* unw_local_addr_space is a NULL pointer in this case. */ ++unw_addr_space_t unw_local_addr_space; ++ ++#else /* !UNW_REMOTE_ONLY */ ++ ++static struct unw_addr_space local_addr_space; ++ ++unw_addr_space_t unw_local_addr_space = &local_addr_space; ++ ++/* Return the address of the 64-bit slot in UC for REG (even for o32, ++ where registers are 32-bit, the slots are still 64-bit). */ ++ ++static inline void * ++uc_addr (ucontext_t *uc, int reg) ++{ ++ if (reg >= UNW_SW_64_R0 && reg < UNW_SW_64_R0 + 32) ++ return &uc->uc_mcontext.sc_regs[reg - UNW_SW_64_R0]; ++ else if (reg >= UNW_SW_64_F0 && reg < UNW_SW_64_F0 + 32) ++ return &uc->uc_mcontext.sc_fpregs[reg - UNW_SW_64_F0]; ++ else if (reg == UNW_SW_64_PC) ++ return &uc->uc_mcontext.sc_pc; ++ else ++ return NULL; ++} ++ ++# ifdef UNW_LOCAL_ONLY ++ ++HIDDEN void * ++tdep_uc_addr (ucontext_t *uc, int reg) ++{ ++ return uc_addr (uc, reg); ++} ++ ++# endif /* UNW_LOCAL_ONLY */ ++ ++static void ++put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) ++{ ++ /* it's a no-op */ ++} ++ ++static int ++get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, ++ void *arg) ++{ ++#ifndef UNW_LOCAL_ONLY ++# pragma weak _U_dyn_info_list_addr ++ if (!_U_dyn_info_list_addr) ++ return -UNW_ENOINFO; ++#endif ++ // Access the `_U_dyn_info_list` from `LOCAL_ONLY` library, i.e. libunwind.so. ++ *dyn_info_list_addr = _U_dyn_info_list_addr (); ++ return 0; ++} ++ ++static int ++access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, ++ void *arg) ++{ ++ if (write) ++ { ++ Debug (16, "mem[%llx] <- %llx\n", (long long) addr, (long long) *val); ++ *(unw_word_t *) (intptr_t) addr = *val; ++ } ++ else ++ { ++ *val = *(unw_word_t *) (intptr_t) addr; ++ Debug (16, "mem[%llx] -> %llx\n", (long long) addr, (long long) *val); ++ } ++ return 0; ++} ++ ++static int ++access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, ++ void *arg) ++{ ++ unw_word_t *addr; ++ ucontext_t *uc = arg; ++ ++ if (unw_is_fpreg (reg)) ++ goto badreg; ++ ++ Debug (16, "reg = %s\n", unw_regname (reg)); ++ if (!(addr = uc_addr (uc, reg))) ++ goto badreg; ++ ++ if (write) ++ { ++ //*(unw_word_t *) (intptr_t) addr = (sw_64_reg_t) *val; ++ *addr = *val; ++ Debug (12, "%s <- %llx\n", unw_regname (reg), (long long) *val); ++ } ++ else ++ { ++ //*val = (sw_64_reg_t) *(unw_word_t *) (intptr_t) addr; ++ *val = *(unw_word_t *) addr; ++ Debug (12, "%s -> %llx\n", unw_regname (reg), (long long) *val); ++ } ++ return 0; ++ ++ badreg: ++ Debug (1, "bad register number %u\n", reg); ++ return -UNW_EBADREG; ++} ++ ++static int ++access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, ++ int write, void *arg) ++{ ++ ucontext_t *uc = arg; ++ unw_fpreg_t *addr; ++ ++ if (!unw_is_fpreg (reg)) ++ goto badreg; ++ ++ if (!(addr = uc_addr (uc, reg))) ++ goto badreg; ++ ++ if (write) ++ { ++ Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg), ++ ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); ++ *(unw_fpreg_t *) (intptr_t) addr = *val; ++ } ++ else ++ { ++ *val = *(unw_fpreg_t *) (intptr_t) addr; ++ Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg), ++ ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); ++ } ++ return 0; ++ ++ badreg: ++ Debug (1, "bad register number %u\n", reg); ++ /* attempt to access a non-preserved register */ ++ return -UNW_EBADREG; ++} ++ ++static int ++get_static_proc_name (unw_addr_space_t as, unw_word_t ip, ++ char *buf, size_t buf_len, unw_word_t *offp, ++ void *arg) ++{ ++ ++ return elf_w (get_proc_name) (as, getpid (), ip, buf, buf_len, offp); ++} ++ ++HIDDEN void ++sw_64_local_addr_space_init (void) ++{ ++ memset (&local_addr_space, 0, sizeof (local_addr_space)); ++ ++ local_addr_space.addr_size = sizeof (void *); ++ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY; ++ local_addr_space.acc.find_proc_info = dwarf_find_proc_info; ++ local_addr_space.acc.put_unwind_info = put_unwind_info; ++ local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; ++ local_addr_space.acc.access_mem = access_mem; ++ local_addr_space.acc.access_reg = access_reg; ++ local_addr_space.acc.access_fpreg = access_fpreg; ++ local_addr_space.acc.resume = sw_64_local_resume; /* sw_64_local_resume? FIXME! */ ++ local_addr_space.acc.get_proc_name = get_static_proc_name; ++ unw_flush_cache (&local_addr_space, 0, 0); ++} ++ ++#endif /* !UNW_REMOTE_ONLY */ +diff --git a/src/sw_64/Ginit_local.c b/src/sw_64/Ginit_local.c +new file mode 100644 +index 0000000..d8d0c9e +--- /dev/null ++++ b/src/sw_64/Ginit_local.c +@@ -0,0 +1,77 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++#include "init.h" ++ ++#ifdef UNW_REMOTE_ONLY ++ ++int ++unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) ++{ ++ return -UNW_EINVAL; ++} ++ ++#else /* !UNW_REMOTE_ONLY */ ++ ++static int ++unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ ++// if (!atomic_load(&tdep_init_done)) ++ if (!tdep_init_done) ++ tdep_init (); ++ ++ Debug (1, "(cursor=%p)\n", c); ++ ++ c->dwarf.as = unw_local_addr_space; ++ c->dwarf.as_arg = uc; ++ return common_init (c, use_prev_instr); ++} ++ ++int ++unw_init_local(unw_cursor_t *cursor, ucontext_t *uc) ++{ ++ return unw_init_local_common(cursor, uc, 1); ++} ++ ++int ++unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag) ++{ ++ if (!flag) ++ { ++ return unw_init_local_common(cursor, uc, 1); ++ } ++ else if (flag == UNW_INIT_SIGNAL_FRAME) ++ { ++ return unw_init_local_common(cursor, uc, 0); ++ } ++ else ++ { ++ return -UNW_EINVAL; ++ } ++} ++ ++#endif /* !UNW_REMOTE_ONLY */ +diff --git a/src/sw_64/Ginit_remote.c b/src/sw_64/Ginit_remote.c +new file mode 100644 +index 0000000..26d11ba +--- /dev/null ++++ b/src/sw_64/Ginit_remote.c +@@ -0,0 +1,45 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "init.h" ++#include "unwind_i.h" ++ ++int ++unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) ++{ ++#ifdef UNW_LOCAL_ONLY ++ return -UNW_EINVAL; ++#else /* !UNW_LOCAL_ONLY */ ++ struct cursor *c = (struct cursor *) cursor; ++ ++ if (!atomic_load(&tdep_init_done)) ++ tdep_init (); ++ ++ Debug (1, "(cursor=%p)\n", c); ++ ++ c->dwarf.as = as; ++ c->dwarf.as_arg = as_arg; ++ return common_init (c, 0); ++#endif /* !UNW_LOCAL_ONLY */ ++} +diff --git a/src/sw_64/Gis_signal_frame.c b/src/sw_64/Gis_signal_frame.c +new file mode 100644 +index 0000000..5af5652 +--- /dev/null ++++ b/src/sw_64/Gis_signal_frame.c +@@ -0,0 +1,107 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2015 Imagination Technologies Limited ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++#if 0 ++#include "unwind_i.h" ++#include ++ ++int ++unw_is_signal_frame (unw_cursor_t *cursor) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ unw_word_t w0, w1, ip; ++ unw_addr_space_t as; ++ unw_accessors_t *a; ++ void *arg; ++ int ret; ++ ++ as = c->dwarf.as; ++ a = unw_get_accessors_int (as); ++ arg = c->dwarf.as_arg; ++ ++ ip = c->dwarf.ip; ++ ++ /* syscall */ ++ if ((ret = (*a->access_mem) (as, ip + 4, &w1, 0, arg)) < 0) ++ return 0; ++ if ((w1 & 0xffffffff) != 0x0c) ++ return 0; ++ ++ /* li v0, 0x1061 (rt) or li v0, 0x1017 */ ++ if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0) ++ return 0; ++ ++ switch (c->dwarf.as->abi) ++ { ++ case UNW_SW_64_ABI_N64: ++ switch (w0 & 0xffffffff) ++ { ++ case 0x2402145b: ++ return 1; ++ default: ++ return 0; ++ } ++ default: ++ return 0; ++ } ++} ++#endif ++#include "unwind_i.h" ++#include "offsets.h" ++#include ++ ++ ++int ++unw_is_signal_frame (unw_cursor_t *cursor) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ unw_word_t w1, ip; ++ unw_addr_space_t as; ++ unw_accessors_t *a; ++ void *arg; ++ int ret; ++ ++ as = c->dwarf.as; ++ a = unw_get_accessors_int (as); ++ arg = c->dwarf.as_arg; ++ ++ ip = c->dwarf.ip; ++ ++ /* syscall */ ++ if ((ret = (*a->access_mem) (as, ip + 4, &w1, 0, arg)) < 0) ++ return 0; ++ ++ if ( w1 == 0x2000083f81f0067UL) { // __NR_sigreturn = 0x67 ++ c->sigcontext_format = SW_SCF_LINUX_SIGFRAME; ++ return 2; ++ } ++ else{ ++ if ( w1 == 0x2000083f81f015fUL) // __NR_rt_sigreturn = 0x15f ++ c->sigcontext_format = SW_SCF_LINUX_RT_SIGFRAME; ++ else ++ c->sigcontext_format = SW_SCF_NONE; ++ } ++ return c->sigcontext_format > SW_SCF_NONE; ++ ++} +diff --git a/src/sw_64/Greg_states_iterate.c b/src/sw_64/Greg_states_iterate.c +new file mode 100644 +index 0000000..a17dc1b +--- /dev/null ++++ b/src/sw_64/Greg_states_iterate.c +@@ -0,0 +1,37 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. ++ Contributed by David Mosberger-Tang ++ ++ Modified for x86_64 by Max Asbock ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++ ++int ++unw_reg_states_iterate (unw_cursor_t *cursor, ++ unw_reg_states_callback cb, void *token) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ ++ return dwarf_reg_states_iterate (&c->dwarf, cb, token); ++} +diff --git a/src/sw_64/Gregs.c b/src/sw_64/Gregs.c +new file mode 100644 +index 0000000..9a88d3e +--- /dev/null ++++ b/src/sw_64/Gregs.c +@@ -0,0 +1,130 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++ ++/* FIXME: The following is probably unfinished and/or at least partly bogus. */ ++ ++HIDDEN int ++tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, ++ int write) ++{ ++ dwarf_loc_t loc = DWARF_NULL_LOC; ++ ++ switch (reg) ++ { ++ case UNW_SW_64_R0: ++ case UNW_SW_64_R1: ++ case UNW_SW_64_R2: ++ case UNW_SW_64_R3: ++ case UNW_SW_64_R4: ++ case UNW_SW_64_R5: ++ case UNW_SW_64_R6: ++ case UNW_SW_64_R7: ++ case UNW_SW_64_R8: ++ case UNW_SW_64_R9: ++ case UNW_SW_64_R10: ++ case UNW_SW_64_R11: ++ case UNW_SW_64_R12: ++ case UNW_SW_64_R13: ++ case UNW_SW_64_R14: ++ case UNW_SW_64_R15: ++ case UNW_SW_64_R16: ++ case UNW_SW_64_R17: ++ case UNW_SW_64_R18: ++ case UNW_SW_64_R19: ++ case UNW_SW_64_R20: ++ case UNW_SW_64_R21: ++ case UNW_SW_64_R22: ++ case UNW_SW_64_R23: ++ case UNW_SW_64_R24: ++ case UNW_SW_64_R25: ++ case UNW_SW_64_R26: ++ case UNW_SW_64_R27: ++ case UNW_SW_64_R28: ++ case UNW_SW_64_R29: ++ case UNW_SW_64_R30: ++ case UNW_SW_64_R31: ++ loc = c->dwarf.loc[reg - UNW_SW_64_R0]; ++ break; ++#if 1 //LIJM20250211 ++ case UNW_SW_64_PC: ++ if (!write) ++ { ++ *valp = c->dwarf.ip; ++ return 0; ++ } ++ c->dwarf.ip = *valp; ++ loc = c->dwarf.loc[reg - UNW_SW_64_R0]; ++ break; ++ default: ++ Debug (1, "bad register number %u\n", reg); ++ return -UNW_EBADREG; ++ } ++ ++ if (write) ++ return dwarf_put (&c->dwarf, loc, *valp); ++ else ++ return dwarf_get (&c->dwarf, loc, valp); ++} ++HIDDEN int ++tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, ++ int write) ++{ ++ dwarf_loc_t loc = DWARF_NULL_LOC; ++ if (reg >= UNW_SW_64_F0 && reg <= UNW_SW_64_F31 ) ++ loc = c->dwarf.loc[reg - UNW_SW_64_R0]; ++ if (write) ++ return dwarf_putfp (&c->dwarf, loc, *valp); ++ else ++ return dwarf_getfp (&c->dwarf, loc, valp); ++} ++#else ++ case UNW_SW_64_PC: ++ if (write) ++ c->dwarf.ip = *valp; /* update the IP cache */ ++ loc = c->dwarf.loc[reg]; ++ break; ++ ++ default: ++ Debug (1, "bad register number %u\n", reg); ++ return -UNW_EBADREG; ++ } ++ ++ if (write) ++ return dwarf_put (&c->dwarf, loc, *valp); ++ else ++ return dwarf_get (&c->dwarf, loc, valp); ++} ++ ++/* FIXME for SW_64. */ ++ ++HIDDEN int ++tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, ++ int write) ++{ ++ Debug (1, "bad register number %u\n", reg); ++ return -UNW_EBADREG; ++} ++#endif +diff --git a/src/sw_64/Gresume.c b/src/sw_64/Gresume.c +new file mode 100644 +index 0000000..f21e825 +--- /dev/null ++++ b/src/sw_64/Gresume.c +@@ -0,0 +1,112 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++ ++#include ++ ++#include "unwind_i.h" ++ ++#ifndef UNW_REMOTE_ONLY ++ ++HIDDEN inline int ++sw_64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ ucontext_t *uc = (ucontext_t *)c->dwarf.as_arg; ++ ++ /* Ensure c->pi is up-to-date. On sw_64, it's relatively common to be ++ missing DWARF unwind info. We don't want to fail in that case, ++ because the frame-chain still would let us do a backtrace at ++ least. */ ++ dwarf_make_proc_info (&c->dwarf); ++ ++ if (unlikely (c->sigcontext_format != SW_SCF_NONE)) ++ { ++ struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; ++ ++ Debug (8, "resuming at ip=%#lx cfa=%#lx via sigreturn(%p)\n", ++ c->dwarf.ip, c->dwarf.cfa, sc); ++ sigreturn (sc); ++ } ++ else ++ { ++ Debug (8, "resuming at ip=%#lx cfa=%#lx sp= %#lx via setcontext()\n", ++ c->dwarf.ip, c->dwarf.cfa, uc->uc_mcontext.sc_regs[30]); ++ setcontext (uc); ++ } ++ return -UNW_EINVAL; ++} ++ ++#endif /* !UNW_REMOTE_ONLY */ ++ ++static inline int ++establish_machine_state (struct cursor *c) ++{ ++ int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *, ++ int write, void *); ++ int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *, ++ int write, void *); ++ unw_addr_space_t as = c->dwarf.as; ++ void *arg = c->dwarf.as_arg; ++ unw_fpreg_t fpval; ++ unw_word_t val; ++ int reg; ++ ++ access_reg = as->acc.access_reg; ++ access_fpreg = as->acc.access_fpreg; ++ ++ Debug (8, "copying out cursor state\n"); ++ ++ for (reg = 0; reg <= UNW_SW_64_PC; ++reg) ++ { ++ Debug (16, "copying %s %d\n", unw_regname (reg), reg); ++ if (unw_is_fpreg (reg)) ++ { ++ if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0) ++ (*access_fpreg) (as, reg, &fpval, 1, arg); ++ } ++ else ++ { ++ if (tdep_access_reg (c, reg, &val, 0) >= 0) ++ (*access_reg) (as, reg, &val, 1, arg); ++ } ++ } ++ (*access_reg) (as, UNW_SW_64_R30, &c->dwarf.cfa, 1, arg); ++ return 0; ++} ++ ++int ++unw_resume (unw_cursor_t *cursor) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ int ret; ++ ++ Debug (1, "(cursor=%p)\n", c); ++ ++ if ((ret = establish_machine_state (c)) < 0) ++ return ret; ++ ++ return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c, ++ c->dwarf.as_arg); ++} +diff --git a/src/sw_64/Gstep.c b/src/sw_64/Gstep.c +new file mode 100644 +index 0000000..6a88bcc +--- /dev/null ++++ b/src/sw_64/Gstep.c +@@ -0,0 +1,230 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2015 Imagination Technologies Limited ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++#include "offsets.h" ++ ++static int ++sw_64_handle_signal_frame (unw_cursor_t *cursor) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ unw_word_t sc_addr, sp_addr = c->dwarf.cfa; ++ unw_word_t ra, fp; ++ int i, ret; ++ ++ switch (unw_is_signal_frame (cursor)) { ++ case 1: ++ sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF; ++ break; ++ case 2: ++ sc_addr = sp_addr; ++ break; ++ default: ++ return -UNW_EUNSPEC; ++ } ++ ++ c->sigcontext_addr = sc_addr; ++ ++ ++ c->sigcontext_sp = c->dwarf.cfa; ++ c->sigcontext_pc = c->dwarf.ip; ++ c->sigcontext_format = SW_SCF_LINUX_RT_SIGFRAME; ++ ++ for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) ++ c->dwarf.loc[i] = DWARF_NULL_LOC; ++ ++ /* Update the dwarf cursor. */ ++ c->dwarf.loc[UNW_SW_64_R0] = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R1] = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R2] = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R3] = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R4] = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R5] = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R6] = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R7] = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R8] = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R9] = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R11] = DWARF_LOC (sc_addr + LINUX_SC_R11_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R12] = DWARF_LOC (sc_addr + LINUX_SC_R12_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R13] = DWARF_LOC (sc_addr + LINUX_SC_R13_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R14] = DWARF_LOC (sc_addr + LINUX_SC_R14_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R15] = DWARF_LOC (sc_addr + LINUX_SC_R15_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R16] = DWARF_LOC (sc_addr + LINUX_SC_R16_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R17] = DWARF_LOC (sc_addr + LINUX_SC_R17_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R18] = DWARF_LOC (sc_addr + LINUX_SC_R18_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R19] = DWARF_LOC (sc_addr + LINUX_SC_R19_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R20] = DWARF_LOC (sc_addr + LINUX_SC_R20_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R21] = DWARF_LOC (sc_addr + LINUX_SC_R21_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R22] = DWARF_LOC (sc_addr + LINUX_SC_R22_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R23] = DWARF_LOC (sc_addr + LINUX_SC_R23_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R24] = DWARF_LOC (sc_addr + LINUX_SC_R24_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R25] = DWARF_LOC (sc_addr + LINUX_SC_R25_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R26] = DWARF_LOC (sc_addr + LINUX_SC_R26_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R27] = DWARF_LOC (sc_addr + LINUX_SC_R27_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R28] = DWARF_LOC (sc_addr + LINUX_SC_R28_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R29] = DWARF_LOC (sc_addr + LINUX_SC_R29_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R30] = DWARF_LOC (sc_addr + LINUX_SC_R30_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_R31] = DWARF_LOC (sc_addr + LINUX_SC_R31_OFF, 0); ++ c->dwarf.loc[UNW_SW_64_PC] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0); ++ ++ /* Set SP/CFA and PC/IP. */ ++ dwarf_get (&c->dwarf, c->dwarf.loc[UNW_SW_64_R30], &c->dwarf.cfa); ++ ++ if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_PC_OFF, 0), ++ &c->dwarf.ip)) < 0) ++ return ret; ++ ++ if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_R26_OFF, 0), ++ &ra)) < 0) ++ return ret; ++ if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_R15_OFF, 0), ++ &fp)) < 0) ++ return ret; ++ ++ Debug (2, "SH (ip=0x%016llx, ra=0x%016llx, sp=0x%016llx, fp=0x%016llx)\n", ++ (unsigned long long)c->dwarf.ip, (unsigned long long)ra, ++ (unsigned long long)c->dwarf.cfa, (unsigned long long)fp); ++ ++ c->dwarf.pi_valid = 0; ++ c->dwarf.use_prev_instr = 0; ++ ++ return 1; ++} ++ ++ ++static inline ++int is_valid_fp_val(unw_word_t cfa_val, unw_word_t fp_val) ++{ ++ return fp_val > 0 && cfa_val > 0 && fp_val >cfa_val && (fp_val - cfa_val < 0x4000); ++} ++ ++static int _step_n64(struct cursor *c) ++{ ++ #define FP_REG UNW_SW_64_R15 ++ #define SP_REG UNW_SW_64_R30 ++ #define RA_REG UNW_SW_64_R26 ++ ++ //TODO:handle plt entry ++ int ret; ++ unw_word_t current_fp_val = 0; ++ unw_word_t current_ra_val = 0; ++ unw_word_t current_sp_val = 0; ++ struct dwarf_loc up_fp_loc = DWARF_NULL_LOC; ++ struct dwarf_loc up_ra_loc = DWARF_NULL_LOC; ++ ++ ret = dwarf_get (&c->dwarf, c->dwarf.loc[SP_REG], ¤t_sp_val); ++ if (ret < 0) ++ { ++ Debug (2, "returning %d [SP=0x%lx]\n", ret, ++ DWARF_GET_LOC (c->dwarf.loc[FP_REG])); ++ return ret; ++ } ++ ret = dwarf_get (&c->dwarf, c->dwarf.loc[FP_REG], ¤t_fp_val); ++ if (ret < 0) ++ { ++ Debug (2, "returning %d [FP=0x%lx]\n", ret, ++ DWARF_GET_LOC (c->dwarf.loc[FP_REG])); ++ return ret; ++ } ++ ret = dwarf_get (&c->dwarf, c->dwarf.loc[RA_REG], ¤t_ra_val); ++ if (ret < 0) ++ { ++ Debug (2, "returning %d [RA=0x%lx]\n", ret, ++ DWARF_GET_LOC (c->dwarf.loc[RA_REG])); ++ return ret; ++ } ++ ++ Debug(2, "BEGIN GUESSING WITH SP:%p FP:%p CFA:%p at %p, RA:%p\n", ++ current_sp_val, current_fp_val, c->dwarf.cfa, ++ c->dwarf.ip, current_ra_val ++ ); ++ ++ if (current_fp_val == current_sp_val) { ++ // Don't adjust FP ++ up_fp_loc = c->dwarf.loc[FP_REG]; ++ up_ra_loc = c->dwarf.loc[RA_REG]; ++ } else if (is_valid_fp_val(c->dwarf.cfa, current_fp_val)) { ++ /* Heuristic to determine incorrect guess. For FP to be a ++ valid frame it needs to be above current CFA, but don't ++ let it go more than a little. Note that we can't deduce ++ anything about new FP (fp1) since it may not be a frame ++ pointer in the frame above. Just check we get the value. */ ++ up_fp_loc = DWARF_MEM_LOC (c, current_fp_val+16); ++ up_ra_loc = DWARF_MEM_LOC (c, current_fp_val+24); ++ unw_word_t up_fp_val = 0; ++ ret = dwarf_get (&c->dwarf, up_fp_loc, &up_fp_val); ++ if (ret > 0 && is_valid_fp_val(current_fp_val, up_fp_val)) { ++ c->dwarf.loc[FP_REG] = up_fp_loc; ++ } ++ } ++ ++ if (DWARF_IS_NULL_LOC (up_fp_loc)) ++ { ++ ret = 0; ++ Debug (2, "NULL %%fp loc, returning %d\n", ret); ++ return ret; ++ } ++ ++ c->dwarf.loc[UNW_SW_64_PC] = c->dwarf.loc[RA_REG]; ++ c->dwarf.loc[RA_REG] = up_ra_loc; ++ c->dwarf.loc[SP_REG] = up_fp_loc; ++ c->dwarf.loc[FP_REG] = up_fp_loc; ++ c->dwarf.use_prev_instr = 1; ++ ++ if (c->dwarf.ip == current_ra_val && current_fp_val == current_sp_val) { ++ // Backtrace stopped: frame did not save the PC ++ c->dwarf.ip = 0; ++ } else { ++ c->dwarf.ip = current_ra_val; ++ } ++ return (c->dwarf.ip == 0) ? 0 : 1; ++} ++ ++int ++unw_step (unw_cursor_t *cursor) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ int ret; ++ ++ ret = sw_64_handle_signal_frame (cursor); ++ if (ret < 0) ++ /* Not a signal frame, try DWARF-based unwinding. */ ++ ret = dwarf_step (&c->dwarf); ++ ++ if (unlikely (ret == -UNW_ESTOPUNWIND)) ++ return ret; ++ ++ if (unlikely (ret < 0)) ++ { ++#if _SW_64_SIM == _ABI64 ++ return _step_n64(c); ++#else ++ return ret; ++#endif ++ } ++ ++ return (c->dwarf.ip == 0) ? 0 : 1; ++} +diff --git a/src/sw_64/Gtrace.c.bak b/src/sw_64/Gtrace.c.bak +new file mode 100644 +index 0000000..e1c7150 +--- /dev/null ++++ b/src/sw_64/Gtrace.c.bak +@@ -0,0 +1,552 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY ++ Copyright (C) 2014 CERN and Aalto University ++ Contributed by Filip Nyback ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++#include "offsets.h" ++#include ++#include ++ ++#pragma weak pthread_once ++#pragma weak pthread_key_create ++#pragma weak pthread_getspecific ++#pragma weak pthread_setspecific ++ ++/* Initial hash table size. Table expands by 2 bits (times four). */ ++#define HASH_MIN_BITS 14 ++#define UNW_SW_64_FRAME_OTHER 0 ++#define UNW_SW_64_FRAME_STANDARD -2 /* regular fp, sp +/- offset */ ++#define UNW_SW_64_FRAME_SIGRETURN -1 /* special sigreturn frame */ ++#define UNW_SW_64_FRAME_OTHER 0 /* not cacheable (special or unrecognised) */ ++#define UNW_SW_64_FRAME_GUESSED 1 /* guessed it was regular, but not known */ ++typedef struct ++{ ++ unw_tdep_frame_t *frames; ++ size_t log_size; ++ size_t used; ++ size_t dtor_count; /* Counts how many times our destructor has already ++ been called. */ ++} unw_trace_cache_t; ++ ++static const unw_tdep_frame_t empty_frame = { 0, UNW_SW_64_FRAME_OTHER, -1, -1, 0, -1, -1, -1 }; ++static define_lock (trace_init_lock); ++static pthread_once_t trace_cache_once = PTHREAD_ONCE_INIT; ++static sig_atomic_t trace_cache_once_happen; ++static pthread_key_t trace_cache_key; ++static struct mempool trace_cache_pool; ++static _Thread_local unw_trace_cache_t *tls_cache; ++static _Thread_local int tls_cache_destroyed; ++ ++/* Free memory for a thread's trace cache. */ ++static void ++trace_cache_free (void *arg) ++{ ++ unw_trace_cache_t *cache = arg; ++ if (++cache->dtor_count < PTHREAD_DESTRUCTOR_ITERATIONS) ++ { ++ /* Not yet our turn to get destroyed. Re-install ourselves into the key. */ ++ pthread_setspecific(trace_cache_key, cache); ++ Debug(5, "delayed freeing cache %p (%zx to go)\n", cache, ++ PTHREAD_DESTRUCTOR_ITERATIONS - cache->dtor_count); ++ return; ++ } ++ tls_cache_destroyed = 1; ++ tls_cache = NULL; ++ munmap (cache->frames, (1u << cache->log_size) * sizeof(unw_tdep_frame_t)); ++ mempool_free (&trace_cache_pool, cache); ++ Debug(5, "freed cache %p\n", cache); ++} ++ ++/* Initialise frame tracing for threaded use. */ ++static void ++trace_cache_init_once (void) ++{ ++ pthread_key_create (&trace_cache_key, &trace_cache_free); ++ mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0); ++ trace_cache_once_happen = 1; ++} ++ ++static unw_tdep_frame_t * ++trace_cache_buckets (size_t n) ++{ ++ unw_tdep_frame_t *frames; ++ size_t i; ++ ++ GET_MEMORY(frames, n * sizeof (unw_tdep_frame_t)); ++ if (likely(frames != NULL)) ++ for (i = 0; i < n; ++i) ++ frames[i] = empty_frame; ++ ++ return frames; ++} ++ ++/* Allocate and initialise hash table for frame cache lookups. ++ Returns the cache initialised with (1u << HASH_LOW_BITS) hash ++ buckets, or NULL if there was a memory allocation problem. */ ++static unw_trace_cache_t * ++trace_cache_create (void) ++{ ++ unw_trace_cache_t *cache; ++ ++ if (tls_cache_destroyed) ++ { ++ /* The current thread is in the process of exiting. Don't recreate ++ cache, as we wouldn't have another chance to free it. */ ++ Debug(5, "refusing to reallocate cache: " ++ "thread-locals are being deallocated\n"); ++ return NULL; ++ } ++ ++ if (! (cache = mempool_alloc(&trace_cache_pool))) ++ { ++ Debug(5, "failed to allocate cache\n"); ++ return NULL; ++ } ++ ++ if (! (cache->frames = trace_cache_buckets(1u << HASH_MIN_BITS))) ++ { ++ Debug(5, "failed to allocate buckets\n"); ++ mempool_free(&trace_cache_pool, cache); ++ return NULL; ++ } ++ ++ cache->log_size = HASH_MIN_BITS; ++ cache->used = 0; ++ cache->dtor_count = 0; ++ tls_cache_destroyed = 0; /* Paranoia: should already be 0. */ ++ Debug(5, "allocated cache %p\n", cache); ++ return cache; ++} ++ ++/* Expand the hash table in the frame cache if possible. This always ++ quadruples the hash size, and clears all previous frame entries. */ ++static int ++trace_cache_expand (unw_trace_cache_t *cache) ++{ ++ size_t old_size = (1u << cache->log_size); ++ size_t new_log_size = cache->log_size + 2; ++ unw_tdep_frame_t *new_frames = trace_cache_buckets (1u << new_log_size); ++ ++ if (unlikely(! new_frames)) ++ { ++ Debug(5, "failed to expand cache to 2^%lu buckets\n", new_log_size); ++ return -UNW_ENOMEM; ++ } ++ ++ Debug(5, "expanded cache from 2^%lu to 2^%lu buckets\n", cache->log_size, new_log_size); ++ munmap(cache->frames, old_size * sizeof(unw_tdep_frame_t)); ++ cache->frames = new_frames; ++ cache->log_size = new_log_size; ++ cache->used = 0; ++ return 0; ++} ++ ++static unw_trace_cache_t * ++trace_cache_get_unthreaded (void) ++{ ++ unw_trace_cache_t *cache; ++ intrmask_t saved_mask; ++ static unw_trace_cache_t *global_cache = NULL; ++ lock_acquire (&trace_init_lock, saved_mask); ++ if (! global_cache) ++ { ++ mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0); ++ global_cache = trace_cache_create (); ++ } ++ cache = global_cache; ++ lock_release (&trace_init_lock, saved_mask); ++ Debug(5, "using cache %p\n", cache); ++ return cache; ++} ++ ++/* Get the frame cache for the current thread. Create it if there is none. */ ++static unw_trace_cache_t * ++trace_cache_get (void) ++{ ++ unw_trace_cache_t *cache; ++ if (likely (pthread_once != NULL)) ++ { ++ pthread_once(&trace_cache_once, &trace_cache_init_once); ++ if (!trace_cache_once_happen) ++ { ++ return trace_cache_get_unthreaded(); ++ } ++ if (! (cache = tls_cache)) ++ { ++ cache = trace_cache_create(); ++ pthread_setspecific(trace_cache_key, cache); ++ tls_cache = cache; ++ } ++ Debug(5, "using cache %p\n", cache); ++ return cache; ++ } ++ else ++ { ++ return trace_cache_get_unthreaded(); ++ } ++} ++ ++/* Initialise frame properties for address cache slot F at address ++ PC using current CFA, FP and SP values. Modifies CURSOR to ++ that location, performs one unw_step(), and fills F with what ++ was discovered about the location. Returns F. ++ ++ FIXME: This probably should tell DWARF handling to never evaluate ++ or use registers other than FP, SP and PC in case there is ++ highly unusual unwind info which uses these creatively. */ ++static unw_tdep_frame_t * ++trace_init_addr (unw_tdep_frame_t *f, ++ unw_cursor_t *cursor, ++ unw_word_t cfa, ++ unw_word_t pc, ++ unw_word_t fp, ++ unw_word_t sp) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ struct dwarf_cursor *d = &c->dwarf; ++ int ret = -UNW_EINVAL; ++ ++ /* Initialise frame properties: unknown, not last. */ ++ f->virtual_address = pc; ++ f->frame_type = UNW_SW_64_FRAME_OTHER; ++ f->last_frame = 0; ++ f->cfa_reg_sp = -1; ++ f->cfa_reg_offset = 0; ++ f->fp_cfa_offset = -1; ++ f->lr_cfa_offset = -1; ++ f->sp_cfa_offset = -1; ++ ++ /* Reinitialise cursor to this instruction - but undo next/prev PC ++ adjustment because unw_step will redo it - and force PC, FP and ++ SP into register locations (=~ ucontext we keep), then set ++ their desired values. Then perform the step. */ ++ d->ip = pc + d->use_prev_instr; ++ d->cfa = cfa; ++ d->loc[UNW_SW_64_R15] = DWARF_REG_LOC (d, UNW_SW_64_R15); ++ d->loc[UNW_SW_64_R30] = DWARF_REG_LOC (d, UNW_SW_64_R30); ++ d->loc[UNW_SW_64_PC] = DWARF_REG_LOC (d, UNW_SW_64_PC); ++ c->frame_info = *f; ++ ++ if (likely(dwarf_put (d, d->loc[UNW_SW_64_R15], fp) >= 0) ++ && likely(dwarf_put (d, d->loc[UNW_SW_64_R30], sp) >= 0) ++ && likely(dwarf_put (d, d->loc[UNW_SW_64_PC], pc) >= 0) ++ && likely((ret = unw_step (cursor)) >= 0)) ++ *f = c->frame_info; ++ ++ /* If unw_step() stopped voluntarily, remember that, even if it ++ otherwise could not determine anything useful. This avoids ++ failing trace if we hit frames without unwind info, which is ++ common for the outermost frame (CRT stuff) on many systems. ++ This avoids failing trace in very common circumstances; failing ++ to unw_step() loop wouldn't produce any better result. */ ++ if (ret == 0) ++ f->last_frame = -1; ++ ++ Debug (3, "frame va %lx type %d last %d cfa %s+%d fp @ cfa%+d lr @ cfa%+d sp @ cfa%+d\n", ++ f->virtual_address, f->frame_type, f->last_frame, ++ f->cfa_reg_sp ? "sp" : "fp", f->cfa_reg_offset, ++ f->fp_cfa_offset, f->lr_cfa_offset, f->sp_cfa_offset); ++ ++ return f; ++} ++ ++/* Look up and if necessary fill in frame attributes for address PC ++ in CACHE using current CFA, FP and SP values. Uses CURSOR to ++ perform any unwind steps necessary to fill the cache. Returns the ++ frame cache slot which describes RIP. */ ++static unw_tdep_frame_t * ++trace_lookup (unw_cursor_t *cursor, ++ unw_trace_cache_t *cache, ++ unw_word_t cfa, ++ unw_word_t pc, ++ unw_word_t fp, ++ unw_word_t sp) ++{ ++ /* First look up for previously cached information using cache as ++ linear probing hash table with probe step of 1. Majority of ++ lookups should be completed within few steps, but it is very ++ important the hash table does not fill up, or performance falls ++ off the cliff. */ ++ uint64_t i, addr; ++ uint64_t cache_size = 1u << cache->log_size; ++ uint64_t slot = ((pc * 0x9e3779b97f4a7c16) >> 43) & (cache_size-1); ++ unw_tdep_frame_t *frame; ++ ++ for (i = 0; i < 16; ++i) ++ { ++ frame = &cache->frames[slot]; ++ addr = frame->virtual_address; ++ ++ /* Return if we found the address. */ ++ if (likely(addr == pc)) ++ { ++ Debug (4, "found address after %ld steps\n", i); ++ return frame; ++ } ++ ++ /* If slot is empty, reuse it. */ ++ if (likely(! addr)) ++ break; ++ ++ /* Linear probe to next slot candidate, step = 1. */ ++ if (++slot >= cache_size) ++ slot -= cache_size; ++ } ++ ++ /* If we collided after 16 steps, or if the hash is more than half ++ full, force the hash to expand. Fill the selected slot, whether ++ it's free or collides. Note that hash expansion drops previous ++ contents; further lookups will refill the hash. */ ++ Debug (4, "updating slot %lu after %ld steps, replacing 0x%lx\n", slot, i, addr); ++ if (unlikely(addr || cache->used >= cache_size / 2)) ++ { ++ if (unlikely(trace_cache_expand (cache) < 0)) ++ return NULL; ++ ++ cache_size = 1u << cache->log_size; ++ slot = ((pc * 0x9e3779b97f4a7c16) >> 43) & (cache_size-1); ++ frame = &cache->frames[slot]; ++ addr = frame->virtual_address; ++ } ++ ++ if (! addr) ++ ++cache->used; ++ ++ return trace_init_addr (frame, cursor, cfa, pc, fp, sp); ++} ++ ++/* Fast stack backtrace for AArch64. ++ ++ This is used by backtrace() implementation to accelerate frequent ++ queries for current stack, without any desire to unwind. It fills ++ BUFFER with the call tree from CURSOR upwards for at most SIZE ++ stack levels. The first frame, backtrace itself, is omitted. When ++ called, SIZE should give the maximum number of entries that can be ++ stored into BUFFER. Uses an internal thread-specific cache to ++ accelerate queries. ++ ++ The caller should fall back to a unw_step() loop if this function ++ fails by returning -UNW_ESTOPUNWIND, meaning the routine hit a ++ stack frame that is too complex to be traced in the fast path. ++ ++ This function is tuned for clients which only need to walk the ++ stack to get the call tree as fast as possible but without any ++ other details, for example profilers sampling the stack thousands ++ to millions of times per second. The routine handles the most ++ common AArch64 ABI stack layouts: CFA is FP or SP plus/minus ++ constant offset, return address is in LR, and FP, LR and SP are ++ either unchanged or saved on stack at constant offset from the CFA; ++ the signal return frame; and frames without unwind info provided ++ they are at the outermost (final) frame or can conservatively be ++ assumed to be frame-pointer based. ++ ++ Any other stack layout will cause the routine to give up. There ++ are only a handful of relatively rarely used functions which do ++ not have a stack in the standard form: vfork, longjmp, setcontext ++ and _dl_runtime_profile on common linux systems for example. ++ ++ On success BUFFER and *SIZE reflect the trace progress up to *SIZE ++ stack levels or the outermost frame, which ever is less. It may ++ stop short of outermost frame if unw_step() loop would also do so, ++ e.g. if there is no more unwind information; this is not reported ++ as an error. ++ ++ The function returns a negative value for errors, -UNW_ESTOPUNWIND ++ if tracing stopped because of an unusual frame unwind info. The ++ BUFFER and *SIZE reflect tracing progress up to the error frame. ++ ++ Callers of this function would normally look like this: ++ ++ unw_cursor_t cur; ++ unw_context_t ctx; ++ void addrs[128]; ++ int depth = 128; ++ int ret; ++ ++ unw_getcontext(&ctx); ++ unw_init_local(&cur, &ctx); ++ if ((ret = unw_tdep_trace(&cur, addrs, &depth)) < 0) ++ { ++ depth = 0; ++ unw_getcontext(&ctx); ++ unw_init_local(&cur, &ctx); ++ while ((ret = unw_step(&cur)) > 0 && depth < 128) ++ { ++ unw_word_t ip; ++ unw_get_reg(&cur, UNW_REG_IP, &ip); ++ addresses[depth++] = (void *) ip; ++ } ++ } ++*/ ++HIDDEN int ++tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) ++{ ++ struct cursor *c = (struct cursor *) cursor; ++ struct dwarf_cursor *d = &c->dwarf; ++ unw_trace_cache_t *cache; ++ unw_word_t fp, sp, pc, cfa, lr; ++ int maxdepth = 0; ++ int depth = 0; ++ int ret; ++ ++ /* Check input parametres. */ ++ if (unlikely(! cursor || ! buffer || ! size || (maxdepth = *size) <= 0)) ++ return -UNW_EINVAL; ++ ++ Debug (1, "begin ip 0x%lx cfa 0x%lx\n", d->ip, d->cfa); ++ ++ /* Tell core dwarf routines to call back to us. */ ++ d->stash_frames = 1; ++ ++ /* Determine initial register values. These are direct access safe ++ because we know they come from the initial machine context. */ ++ pc = d->ip; ++ sp = cfa = d->cfa; ++ ACCESS_MEM_FAST(ret, 0, d, DWARF_GET_LOC(d->loc[UNW_SW_64_R15]), fp); ++ assert(ret == 0); ++ lr = 0; ++ ++ /* Get frame cache. */ ++ if (unlikely(! (cache = trace_cache_get()))) ++ { ++ Debug (1, "returning %d, cannot get trace cache\n", -UNW_ENOMEM); ++ *size = 0; ++ d->stash_frames = 0; ++ return -UNW_ENOMEM; ++ } ++ ++ /* Trace the stack upwards, starting from current RIP. Adjust ++ the RIP address for previous/next instruction as the main ++ unwinding logic would also do. We undo this before calling ++ back into unw_step(). */ ++ while (depth < maxdepth) ++ { ++ pc -= d->use_prev_instr; ++ Debug (2, "depth %d cfa 0x%lx pc 0x%lx sp 0x%lx fp 0x%lx\n", ++ depth, cfa, pc, sp, fp); ++ ++ /* See if we have this address cached. If not, evaluate enough of ++ the dwarf unwind information to fill the cache line data, or to ++ decide this frame cannot be handled in fast trace mode. We ++ cache negative results too to prevent unnecessary dwarf parsing ++ for common failures. */ ++ unw_tdep_frame_t *f = trace_lookup (cursor, cache, cfa, pc, fp, sp); ++ ++ /* If we don't have information for this frame, give up. */ ++ if (unlikely(! f)) ++ { ++ ret = -UNW_ENOINFO; ++ break; ++ } ++ ++ Debug (3, "frame va %lx type %d last %d cfa %s+%d fp @ cfa%+d lr @ cfa%+d sp @ cfa%+d\n", ++ f->virtual_address, f->frame_type, f->last_frame, ++ f->cfa_reg_sp ? "sp" : "fp", f->cfa_reg_offset, ++ f->fp_cfa_offset, f->lr_cfa_offset, f->sp_cfa_offset); ++ ++ assert (f->virtual_address == pc); ++ ++ /* Stop if this was the last frame. In particular don't evaluate ++ new register values as it may not be safe - we don't normally ++ run with full validation on, and do not want to - and there's ++ enough bad unwind info floating around that we need to trust ++ what unw_step() previously said, in potentially bogus frames. */ ++ if (f->last_frame) ++ break; ++ ++ /* Evaluate CFA and registers for the next frame. */ ++ switch (f->frame_type) ++ { ++ case UNW_SW_64_FRAME_GUESSED: ++ /* Fall thru to standard processing after forcing validation. */ ++ c->validate = 1; ++ ++ case UNW_SW_64_FRAME_STANDARD: ++ /* Advance standard traceable frame. */ ++ cfa = (f->cfa_reg_sp ? sp : fp) + f->cfa_reg_offset; ++ if (likely(f->lr_cfa_offset != -1)) ++ ACCESS_MEM_FAST(ret, c->validate, d, cfa + f->lr_cfa_offset, pc); ++ else if (lr != 0) ++ { ++ /* Use the saved link register as the new pc. */ ++ pc = lr; ++ lr = 0; ++ } ++ if (likely(ret >= 0) && likely(f->fp_cfa_offset != -1)) ++ ACCESS_MEM_FAST(ret, c->validate, d, cfa + f->fp_cfa_offset, fp); ++ ++ /* Don't bother reading SP from DWARF, CFA becomes new SP. */ ++ sp = cfa; ++ ++ /* Next frame needs to back up for unwind info lookup. */ ++ d->use_prev_instr = 1; ++ break; ++ ++ case UNW_SW_64_FRAME_SIGRETURN: ++ cfa = cfa + f->cfa_reg_offset; /* cfa now points to ucontext_t. */ ++ ++ ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_PC_OFF, pc); ++ if (likely(ret >= 0)) ++ ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_R15_OFF, fp); ++ if (likely(ret >= 0)) ++ ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_SP_OFF, sp); ++ /* Save the link register here in case we end up in a function that ++ doesn't save the link register in the prologue, e.g. kill. */ ++ if (likely(ret >= 0)) ++ ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_R26_OFF, lr); ++ ++ /* Resume stack at signal restoration point. The stack is not ++ necessarily continuous here, especially with sigaltstack(). */ ++ cfa = sp; ++ ++ /* Next frame should not back up. */ ++ d->use_prev_instr = 0; ++ break; ++ ++ default: ++ /* We cannot trace through this frame, give up and tell the ++ caller we had to stop. Data collected so far may still be ++ useful to the caller, so let it know how far we got. */ ++ ret = -UNW_ESTOPUNWIND; ++ break; ++ } ++ ++ Debug (4, "new cfa 0x%lx pc 0x%lx sp 0x%lx fp 0x%lx\n", ++ cfa, pc, sp, fp); ++ ++ /* If we failed or ended up somewhere bogus, stop. */ ++ if (unlikely(ret < 0 || pc < 0x4000)) ++ break; ++ ++ /* Record this address in stack trace. We skipped the first address. */ ++ buffer[depth++] = (void *) (pc - d->use_prev_instr); ++ } ++ ++#if UNW_DEBUG ++ Debug (1, "returning %d, depth %d\n", ret, depth); ++#endif ++ *size = depth; ++ return ret; ++} +diff --git a/src/sw_64/Lapply_reg_state.c b/src/sw_64/Lapply_reg_state.c +new file mode 100644 +index 0000000..7ebada4 +--- /dev/null ++++ b/src/sw_64/Lapply_reg_state.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Gapply_reg_state.c" ++#endif +diff --git a/src/sw_64/Lcreate_addr_space.c b/src/sw_64/Lcreate_addr_space.c +new file mode 100644 +index 0000000..0f2dc6b +--- /dev/null ++++ b/src/sw_64/Lcreate_addr_space.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Gcreate_addr_space.c" ++#endif +diff --git a/src/sw_64/Lget_proc_info.c b/src/sw_64/Lget_proc_info.c +new file mode 100644 +index 0000000..69028b0 +--- /dev/null ++++ b/src/sw_64/Lget_proc_info.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Gget_proc_info.c" ++#endif +diff --git a/src/sw_64/Lget_save_loc.c b/src/sw_64/Lget_save_loc.c +new file mode 100644 +index 0000000..9ea048a +--- /dev/null ++++ b/src/sw_64/Lget_save_loc.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Gget_save_loc.c" ++#endif +diff --git a/src/sw_64/Lglobal.c b/src/sw_64/Lglobal.c +new file mode 100644 +index 0000000..6d7b489 +--- /dev/null ++++ b/src/sw_64/Lglobal.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Gglobal.c" ++#endif +diff --git a/src/sw_64/Linit.c b/src/sw_64/Linit.c +new file mode 100644 +index 0000000..e9abfdd +--- /dev/null ++++ b/src/sw_64/Linit.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Ginit.c" ++#endif +diff --git a/src/sw_64/Linit_local.c b/src/sw_64/Linit_local.c +new file mode 100644 +index 0000000..68a1687 +--- /dev/null ++++ b/src/sw_64/Linit_local.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Ginit_local.c" ++#endif +diff --git a/src/sw_64/Linit_remote.c b/src/sw_64/Linit_remote.c +new file mode 100644 +index 0000000..58cb04a +--- /dev/null ++++ b/src/sw_64/Linit_remote.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Ginit_remote.c" ++#endif +diff --git a/src/sw_64/Lis_signal_frame.c b/src/sw_64/Lis_signal_frame.c +new file mode 100644 +index 0000000..b9a7c4f +--- /dev/null ++++ b/src/sw_64/Lis_signal_frame.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Gis_signal_frame.c" ++#endif +diff --git a/src/sw_64/Lreg_states_iterate.c b/src/sw_64/Lreg_states_iterate.c +new file mode 100644 +index 0000000..f1eb1e7 +--- /dev/null ++++ b/src/sw_64/Lreg_states_iterate.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Greg_states_iterate.c" ++#endif +diff --git a/src/sw_64/Lregs.c b/src/sw_64/Lregs.c +new file mode 100644 +index 0000000..2c9c75c +--- /dev/null ++++ b/src/sw_64/Lregs.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Gregs.c" ++#endif +diff --git a/src/sw_64/Lresume.c b/src/sw_64/Lresume.c +new file mode 100644 +index 0000000..41a8cf0 +--- /dev/null ++++ b/src/sw_64/Lresume.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Gresume.c" ++#endif +diff --git a/src/sw_64/Lstep.c b/src/sw_64/Lstep.c +new file mode 100644 +index 0000000..c1ac3c7 +--- /dev/null ++++ b/src/sw_64/Lstep.c +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Gstep.c" ++#endif +diff --git a/src/sw_64/Ltrace.c.bak b/src/sw_64/Ltrace.c.bak +new file mode 100644 +index 0000000..fcd3f23 +--- /dev/null ++++ b/src/sw_64/Ltrace.c.bak +@@ -0,0 +1,5 @@ ++#define UNW_LOCAL_ONLY ++#include ++#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) ++#include "Gtrace.c" ++#endif +diff --git a/src/sw_64/elfxx.c b/src/sw_64/elfxx.c +new file mode 100644 +index 0000000..07d3d12 +--- /dev/null ++++ b/src/sw_64/elfxx.c +@@ -0,0 +1,27 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "libunwind_i.h" ++ ++#include "../src/elfxx.c" +diff --git a/src/sw_64/gen-offsets.c b/src/sw_64/gen-offsets.c +new file mode 100644 +index 0000000..ea1f995 +--- /dev/null ++++ b/src/sw_64/gen-offsets.c +@@ -0,0 +1,32 @@ ++#include ++#include ++#include ++#include ++ ++#define UC(N,X) \ ++ printf ("#define LINUX_UC_" N "_OFF\t0x%X\n", offsetof (ucontext_t, X)) ++ ++#define SC(N,X) \ ++ printf ("#define LINUX_SC_" N "_OFF\t0x%X\n", offsetof (struct sigcontext, X)) ++ ++int ++main (void) ++{ ++ printf ( ++"/* Linux-specific definitions: */\n\n" ++ ++"/* Define various structure offsets to simplify cross-compilation. */\n\n" ++ ++"/* Offsets for SW_64 Linux \"ucontext_t\": */\n\n"); ++ ++ UC ("FLAGS", uc_flags); ++ UC ("LINK", uc_link); ++ UC ("STACK", uc_stack); ++ UC ("MCONTEXT", uc_mcontext); ++ UC ("SIGMASK", uc_sigmask); ++ ++ UC ("MCONTEXT_GREGS", uc_mcontext.gregs); ++ UC ("MCONTEXT_PC", uc_mcontext.sc_pc); ++ ++ return 0; ++} +diff --git a/src/sw_64/getcontext.S b/src/sw_64/getcontext.S +new file mode 100644 +index 0000000..72bc8f7 +--- /dev/null ++++ b/src/sw_64/getcontext.S +@@ -0,0 +1,78 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ Copyright (C) 2012 Tommi Rantala ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "offsets.h" ++#include ++ ++ .text ++#define OFFSET 80 ++ .global _Usw_64_getcontext ++ .type _Usw_64_getcontext, %function ++ .ent _Usw_64_getcontext ++ # This is a stub version of getcontext() for SW_64 which only stores core ++ # registers. ++_Usw_64_getcontext: ++ .set noat ++ stl $0, (0 + OFFSET)($16) ++ stl $1, (8 + OFFSET)($16) ++ stl $2, (16 + OFFSET)($16) ++ stl $3, (24 + OFFSET)($16) ++ stl $4, (32 + OFFSET)($16) ++ stl $5, (40 + OFFSET)($16) ++ stl $6, (48 + OFFSET)($16) ++ stl $7, (56 + OFFSET)($16) ++ stl $8, (64 + OFFSET)($16) ++ stl $9, (72 + OFFSET)($16) ++ stl $10, (80 + OFFSET)($16) ++ stl $11, (88 + OFFSET)($16) ++ stl $12, (96 + OFFSET)($16) ++ stl $13, (104 + OFFSET)($16) ++ stl $14, (112 + OFFSET)($16) ++ stl $15, (120 + OFFSET)($16) ++ stl $16, (128 + OFFSET)($16) ++ stl $17, (136 + OFFSET)($16) ++ stl $18, (144 + OFFSET)($16) ++ stl $19, (152 + OFFSET)($16) ++ stl $20, (160 + OFFSET)($16) ++ stl $21, (168 + OFFSET)($16) ++ stl $22, (176 + OFFSET)($16) ++ stl $23, (184 + OFFSET)($16) ++ stl $24, (192 + OFFSET)($16) ++ stl $25, (200 + OFFSET)($16) ++ stl $26, (208 + OFFSET)($16) ++ stl $27, (216 + OFFSET)($16) ++ stl $28, (224 + OFFSET)($16) ++ stl $29, (232 + OFFSET)($16) ++ stl $30, (240 + OFFSET)($16) ++ stl $31, (248 + OFFSET)($16) ++# br $0,2f ++2: ++# stl $0, (OFFSET-16)($16) ++ stl $26, (OFFSET-16)($16) ++ ldl $0, (0 + OFFSET)($16) ++ bis $31,$31,$0 ++ ret ++ .end _Usw_64_getcontext ++ .size _Usw_64_getcontext, .-_Usw_64_getcontext +diff --git a/src/sw_64/init.h b/src/sw_64/init.h +new file mode 100644 +index 0000000..7b61009 +--- /dev/null ++++ b/src/sw_64/init.h +@@ -0,0 +1,65 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++ ++static inline int ++common_init (struct cursor *c, unsigned use_prev_instr) ++{ ++ int ret, i; ++ ++ for (i = 0; i < 32; i++) ++ c->dwarf.loc[i] = DWARF_REG_LOC (&c->dwarf, UNW_SW_64_R0 + i); ++ ++ for (i = 32; i < DWARF_NUM_PRESERVED_REGS; ++i) ++ c->dwarf.loc[i] = DWARF_NULL_LOC; ++ ++ c->dwarf.loc[UNW_SW_64_PC] = DWARF_REG_LOC (&c->dwarf, UNW_SW_64_PC); ++ ++ ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_SW_64_PC], &c->dwarf.ip); ++ if (ret < 0) ++ return ret; ++ ++ ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_SW_64_R29), ++ &c->dwarf.cfa); ++ if (ret < 0) ++ return ret; ++ ++ /* FIXME: Initialisation for other registers. */ ++ ++ c->sigcontext_format = SW_SCF_NONE; ++ c->sigcontext_addr = 0; ++ c->sigcontext_sp = 0; ++ c->sigcontext_pc = 0; ++ ++ c->dwarf.args_size = 0; ++ c->dwarf.stash_frames = 0; ++ c->dwarf.use_prev_instr = use_prev_instr; ++ c->dwarf.pi_valid = 0; ++ c->dwarf.pi_is_dynamic = 0; ++ c->dwarf.hint = 0; ++ c->dwarf.prev_rs = 0; ++ ++ return 0; ++} +diff --git a/src/sw_64/is_fpreg.c b/src/sw_64/is_fpreg.c +new file mode 100644 +index 0000000..e5216c4 +--- /dev/null ++++ b/src/sw_64/is_fpreg.c +@@ -0,0 +1,41 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "libunwind_i.h" ++ ++/* FIXME: I'm not sure if libunwind's GP/FP register distinction is very useful ++ on SW_64. */ ++ ++int ++unw_is_fpreg (int regnum) ++{ ++ /* FIXME: Support FP. */ ++#if 1 ++ return (regnum >= UNW_SW_64_F0 && regnum <= UNW_SW_64_F31); ++#else ++ if (regnum >= UNW_SW_64_F0 && regnum < UNW_SW_64_PC) ++ return 1; ++ return 0; ++#endif ++} +diff --git a/src/sw_64/offsets.h b/src/sw_64/offsets.h +new file mode 100644 +index 0000000..0e2b7ae +--- /dev/null ++++ b/src/sw_64/offsets.h +@@ -0,0 +1,59 @@ ++/* Linux-specific definitions: */ ++ ++/* Define various structure offsets to simplify cross-compilation. */ ++ ++/* FIXME: Currently these are only used in getcontext.S, which is only used ++ for a local unwinder, so we can use the compile-time ABI. At a later date ++ we will want all three here, to use for signal handlers. Also, because ++ of the three ABIs, gen-offsets.c can not quite generate this file. */ ++ ++/* Offsets for SW_64 Linux "ucontext_t": */ ++ ++/* First 24 bytes in sigframe are argument save space and padding for ++what used to be signal trampolines. Ref: arch/sw_64/kernel/signal.c */ ++#define LINUX_SF_TRAMP_SIZE 0x18 ++ ++# define LINUX_UC_FLAGS_OFF 0x0 ++# define LINUX_UC_LINK_OFF 0x8 ++# define LINUX_UC_STACK_OFF 0x18 ++# define LINUX_UC_MCONTEXT_OFF 0x30 ++# define LINUX_UC_SIGMASK_OFF 0x5B8 ++# define LINUX_UC_MCONTEXT_PC 0x40 ++# define LINUX_UC_MCONTEXT_GREGS 0x50 ++ ++ ++#define LINUX_SC_R0_OFF (LINUX_UC_MCONTEXT_GREGS - LINUX_UC_MCONTEXT_OFF) ++#define LINUX_SC_R1_OFF (LINUX_SC_R0_OFF + 1*8) ++#define LINUX_SC_R2_OFF (LINUX_SC_R0_OFF + 2*8) ++#define LINUX_SC_R3_OFF (LINUX_SC_R0_OFF + 3*8) ++#define LINUX_SC_R4_OFF (LINUX_SC_R0_OFF + 4*8) ++#define LINUX_SC_R5_OFF (LINUX_SC_R0_OFF + 5*8) ++#define LINUX_SC_R6_OFF (LINUX_SC_R0_OFF + 6*8) ++#define LINUX_SC_R7_OFF (LINUX_SC_R0_OFF + 7*8) ++#define LINUX_SC_R8_OFF (LINUX_SC_R0_OFF + 8*8) ++#define LINUX_SC_R9_OFF (LINUX_SC_R0_OFF + 9*8) ++#define LINUX_SC_R10_OFF (LINUX_SC_R0_OFF + 10*8) ++#define LINUX_SC_R11_OFF (LINUX_SC_R0_OFF + 11*8) ++#define LINUX_SC_R12_OFF (LINUX_SC_R0_OFF + 12*8) ++#define LINUX_SC_R13_OFF (LINUX_SC_R0_OFF + 13*8) ++#define LINUX_SC_R14_OFF (LINUX_SC_R0_OFF + 14*8) ++#define LINUX_SC_R15_OFF (LINUX_SC_R0_OFF + 15*8) ++#define LINUX_SC_R16_OFF (LINUX_SC_R0_OFF + 16*8) ++#define LINUX_SC_R17_OFF (LINUX_SC_R0_OFF + 17*8) ++#define LINUX_SC_R18_OFF (LINUX_SC_R0_OFF + 18*8) ++#define LINUX_SC_R19_OFF (LINUX_SC_R0_OFF + 19*8) ++#define LINUX_SC_R20_OFF (LINUX_SC_R0_OFF + 20*8) ++#define LINUX_SC_R21_OFF (LINUX_SC_R0_OFF + 21*8) ++#define LINUX_SC_R22_OFF (LINUX_SC_R0_OFF + 22*8) ++#define LINUX_SC_R23_OFF (LINUX_SC_R0_OFF + 23*8) ++#define LINUX_SC_R24_OFF (LINUX_SC_R0_OFF + 24*8) ++#define LINUX_SC_R25_OFF (LINUX_SC_R0_OFF + 25*8) ++#define LINUX_SC_R26_OFF (LINUX_SC_R0_OFF + 26*8) ++#define LINUX_SC_R27_OFF (LINUX_SC_R0_OFF + 27*8) ++#define LINUX_SC_R28_OFF (LINUX_SC_R0_OFF + 28*8) ++#define LINUX_SC_R29_OFF (LINUX_SC_R0_OFF + 29*8) ++#define LINUX_SC_R30_OFF (LINUX_SC_R0_OFF + 30*8) ++#define LINUX_SC_R31_OFF (LINUX_SC_R0_OFF + 31*8) ++ ++#define LINUX_SC_SP_OFF LINUX_SC_R30_OFF ++#define LINUX_SC_PC_OFF (LINUX_UC_MCONTEXT_PC - LINUX_UC_MCONTEXT_OFF) +diff --git a/src/sw_64/regname.c b/src/sw_64/regname.c +new file mode 100644 +index 0000000..ee5f73f +--- /dev/null ++++ b/src/sw_64/regname.c +@@ -0,0 +1,50 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#include "unwind_i.h" ++ ++static const char *regname[] = ++ { ++ "v0", ++ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", ++ "s0", "s1", "s2", "s3", "s4", "s5", "fp", ++ "a0", "a1", "a2", "a3", "a4", "a5", ++ "t8", "t9", "t10", "t11", ++ "ra", "pv", "at", "gp", "sp", "zero", ++ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", ++ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", ++ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", ++ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", ++ }; ++ ++const char * ++unw_regname (unw_regnum_t reg) ++{ ++ if (reg < (unw_regnum_t) ARRAY_SIZE (regname)) ++ return regname[reg]; ++ else if (reg == UNW_SW_64_PC) ++ return "pc"; ++ else ++ return "???"; ++} +diff --git a/src/sw_64/siglongjmp.S b/src/sw_64/siglongjmp.S +new file mode 100644 +index 0000000..cd80043 +--- /dev/null ++++ b/src/sw_64/siglongjmp.S +@@ -0,0 +1,8 @@ ++ /* Dummy implementation for now. */ ++ ++ .globl _UI_siglongjmp_cont ++ .globl _UI_longjmp_cont ++ ++_UI_siglongjmp_cont: ++_UI_longjmp_cont: ++ ret +diff --git a/src/sw_64/unwind_i.h b/src/sw_64/unwind_i.h +new file mode 100644 +index 0000000..c2e109d +--- /dev/null ++++ b/src/sw_64/unwind_i.h +@@ -0,0 +1,43 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright (C) 2008 CodeSourcery ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++#ifndef unwind_i_h ++#define unwind_i_h ++ ++#include ++ ++#include ++ ++#include "libunwind_i.h" ++ ++#define sw_64_lock UNW_OBJ(lock) ++#define sw_64_local_resume UNW_OBJ(local_resume) ++#define sw_64_local_addr_space_init UNW_OBJ(local_addr_space_init) ++ ++extern int sw_64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, ++ void *arg); ++ ++extern void sw_64_local_addr_space_init (void); ++ ++#endif /* unwind_i_h */ +diff --git a/tests/Makefile.am b/tests/Makefile.am +index c074107..1fd8b17 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -127,6 +127,10 @@ if ARCH_MIPS + XFAIL_TESTS += $(XFAIL_TESTS_PTRACE_SINGLESTEP) + endif + ++if ARCH_SW_64 ++XFAIL_TESTS += $(XFAIL_TESTS_PTRACE_SINGLESTEP) ++endif ++ + if ARCH_RISCV + XFAIL_TESTS += $(XFAIL_TESTS_PTRACE_SINGLESTEP) + endif +diff --git a/tests/check-namespace.sh.in b/tests/check-namespace.sh.in +index a1b28a7..ec71bca 100644 +--- a/tests/check-namespace.sh.in ++++ b/tests/check-namespace.sh.in +@@ -86,6 +86,13 @@ filter_misc () { + ignore _gp + fi + ++ if [ ${plat} = "sw_64" ]; then ++ ignore _fbss ++ ignore _fdata ++ ignore _ftext ++ ignore _gp ++ fi ++ + if [ ${plat} = "loongarch64" ]; then + ignore _fbss + ignore _fdata +@@ -205,6 +212,12 @@ check_local_unw_abi () { + match _UL${plat}_dwarf_search_unwind_table + match _UL${plat}_dwarf_find_unwind_table + ;; ++ sw_64) ++ match _U${plat}_getcontext ++ match _U${plat}_is_fpreg ++ match _UL${plat}_dwarf_search_unwind_table ++ match _UL${plat}_dwarf_find_unwind_table ++ ;; + *) + match _U${plat}_is_fpreg + match _UL${plat}_dwarf_search_unwind_table +@@ -327,6 +340,13 @@ check_generic_unw_abi () { + match _U${plat}_dwarf_search_unwind_table + match _U${plat}_dwarf_find_unwind_table + ;; ++ sw_64) ++ match _U${plat}_get_elf_image ++ match _U${plat}_get_exe_image_path ++ match _U${plat}_is_fpreg ++ match _U${plat}_dwarf_search_unwind_table ++ match _U${plat}_dwarf_find_unwind_table ++ ;; + *) + match _U${plat}_is_fpreg + match _U${plat}_dwarf_search_unwind_table +-- +2.33.0 + diff --git a/libunwind.spec b/libunwind.spec index bbc2463b8a3ebced665d95b8328cdd07a5ef83b1..4884c3971761ff31c4cf2735d0971fcb0ee0ec69 100644 --- a/libunwind.spec +++ b/libunwind.spec @@ -1,7 +1,7 @@ Name: libunwind Epoch: 2 Version: 1.7.2 -Release: 3 +Release: 4 Summary: Libunwind provides a C ABI to determine the call-chain of a program License: BSD URL: http://savannah.nongnu.org/projects/libunwind @@ -12,8 +12,9 @@ Patch2: backport-aarch64-unw_step-validates-address-before-calling-dwarf_get.pat Patch3: backport-avoid-calling-printf-because-OE-glibc-2.34-used-mno-.patch Patch4: backport-fix-run-ptrace-mapper-test-case-failed.patch Patch9000: riscv.patch +Patch5: Add-support-for-sw64.patch -ExclusiveArch: aarch64 %{ix86} x86_64 riscv64 ppc64le loongarch64 +ExclusiveArch: aarch64 %{ix86} x86_64 riscv64 ppc64le loongarch64 sw_64 BuildRequires: automake libtool autoconf texlive-latex2man gcc-c++ @@ -89,6 +90,9 @@ make check || true %{_mandir}/*/* %changelog +* Thu Feb 20 2025 Liu Hanxu - 2:1.7.2-4 +- add support for sw64 + * Thu Apr 11 2024 shafeipaozi - 2:1.7.2-3 - add support riscv64