| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- From f2acb06970522a9563d82490f2f1b8fc0bb5b720 Mon Sep 17 00:00:00 2001
- From: Ying Huang <[email protected]>
- Date: Tue, 5 Mar 2024 17:51:21 +0800
- Subject: [PATCH] stack: Fix stack unwind failure on mips
- Add abi_cfi, set_initial_registers_tid, unwind on mips.
- * backends/Makefile.am (mips_SRCS): Add mips_initreg.c,
- mips_cfi.c and mips_unwind.c.
- * backends/mips_init.c (mips_init): HOOK abi_cfi, unwind and
- set_initial_registers_tid. Set frame_nregs to 71.
- * backends/mips_cfi.c: New file.
- * backends/mips_initreg.c: Likewise.
- * backends/mips_unwind.c: Likewise.
- Signed-off-by: Ying Huang <[email protected]>
- ---
- backends/Makefile.am | 3 +-
- backends/mips_cfi.c | 68 +++++++++++++++++++++++++++++++++
- backends/mips_init.c | 4 ++
- backends/mips_initreg.c | 61 ++++++++++++++++++++++++++++++
- backends/mips_unwind.c | 84 +++++++++++++++++++++++++++++++++++++++++
- 5 files changed, 219 insertions(+), 1 deletion(-)
- create mode 100644 backends/mips_cfi.c
- create mode 100644 backends/mips_initreg.c
- create mode 100644 backends/mips_unwind.c
- --- a/backends/Makefile.am
- +++ b/backends/Makefile.am
- @@ -102,7 +102,8 @@ loongarch_SRCS = loongarch_init.c loonga
-
- arc_SRCS = arc_init.c arc_symbol.c
-
- -mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c
- +mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c mips_initreg.c \
- + mips_cfi.c mips_unwind.c
-
- libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \
- $(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \
- --- /dev/null
- +++ b/backends/mips_cfi.c
- @@ -0,0 +1,68 @@
- +/* MIPS ABI-specified defaults for DWARF CFI.
- + Copyright (C) 2009 Red Hat, Inc.
- + Copyright (C) 2024 CIP United Inc.
- + This file is part of elfutils.
- +
- + This file is free software; you can redistribute it and/or modify
- + it under the terms of either
- +
- + * the GNU Lesser General Public License as published by the Free
- + Software Foundation; either version 3 of the License, or (at
- + your option) any later version
- +
- + or
- +
- + * the GNU General Public License as published by the Free
- + Software Foundation; either version 2 of the License, or (at
- + your option) any later version
- +
- + or both in parallel, as here.
- +
- + elfutils is distributed in the hope that it will be useful, but
- + WITHOUT ANY WARRANTY; without even the implied warranty of
- + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + General Public License for more details.
- +
- + You should have received copies of the GNU General Public License and
- + the GNU Lesser General Public License along with this program. If
- + not, see <http://www.gnu.org/licenses/>. */
- +
- +#ifdef HAVE_CONFIG_H
- +# include <config.h>
- +#endif
- +
- +#include <dwarf.h>
- +
- +#define BACKEND mips_
- +#include "libebl_CPU.h"
- +
- +int
- +mips_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info)
- +{
- + static const uint8_t abi_cfi[] =
- + {
- + DW_CFA_def_cfa, ULEB128_7 (31), ULEB128_7 (0),
- + /* Callee-saved regs. */
- + DW_CFA_same_value, ULEB128_7 (16), /* s0 */
- + DW_CFA_same_value, ULEB128_7 (17), /* s1 */
- + DW_CFA_same_value, ULEB128_7 (18), /* s2 */
- + DW_CFA_same_value, ULEB128_7 (19), /* s3 */
- + DW_CFA_same_value, ULEB128_7 (20), /* s4 */
- + DW_CFA_same_value, ULEB128_7 (21), /* s5 */
- + DW_CFA_same_value, ULEB128_7 (22), /* s6 */
- + DW_CFA_same_value, ULEB128_7 (23), /* s7 */
- + DW_CFA_same_value, ULEB128_7 (28), /* gp */
- + DW_CFA_same_value, ULEB128_7 (29), /* sp */
- + DW_CFA_same_value, ULEB128_7 (30), /* fp */
- +
- + DW_CFA_val_offset, ULEB128_7 (29), ULEB128_7 (0),
- + };
- +
- + abi_info->initial_instructions = abi_cfi;
- + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi];
- + abi_info->data_alignment_factor = 8;
- +
- + abi_info->return_address_register = 31; /* %ra */
- +
- + return 0;
- +}
- --- a/backends/mips_init.c
- +++ b/backends/mips_init.c
- @@ -58,5 +58,9 @@ mips_init (Elf *elf __attribute__ ((unus
- HOOK (eh, check_object_attribute);
- HOOK (eh, check_special_symbol);
- HOOK (eh, check_reloc_target_type);
- + HOOK (eh, set_initial_registers_tid);
- + HOOK (eh, abi_cfi);
- + HOOK (eh, unwind);
- + eh->frame_nregs = 71;
- return eh;
- }
- --- /dev/null
- +++ b/backends/mips_initreg.c
- @@ -0,0 +1,61 @@
- +/* Fetch live process registers from TID.
- + Copyright (C) 2024 CIP United Inc.
- + This file is part of elfutils.
- +
- + This file is free software; you can redistribute it and/or modify
- + it under the terms of either
- +
- + * the GNU Lesser General Public License as published by the Free
- + Software Foundation; either version 3 of the License, or (at
- + your option) any later version
- +
- + or
- +
- + * the GNU General Public License as published by the Free
- + Software Foundation; either version 2 of the License, or (at
- + your option) any later version
- +
- + or both in parallel, as here.
- +
- + elfutils is distributed in the hope that it will be useful, but
- + WITHOUT ANY WARRANTY; without even the implied warranty of
- + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + General Public License for more details.
- +
- + You should have received copies of the GNU General Public License and
- + the GNU Lesser General Public License along with this program. If
- + not, see <http://www.gnu.org/licenses/>. */
- +
- +#ifdef HAVE_CONFIG_H
- +# include <config.h>
- +#endif
- +
- +#include <stdlib.h>
- +#if (defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)) && defined(__linux__)
- +# include <sys/user.h>
- +# include <sys/ptrace.h>
- +#include <asm/ptrace.h>
- +#endif
- +
- +#define BACKEND mips_
- +#include "libebl_CPU.h"
- +
- +
- +bool
- +mips_set_initial_registers_tid (pid_t tid __attribute__ ((unused)),
- + ebl_tid_registers_t *setfunc __attribute__ ((unused)),
- + void *arg __attribute__ ((unused)))
- +{
- +#if (!defined(mips) && !defined(__mips) && !defined(__mips__) && !defined(MIPS) && !defined(__MIPS__)) || !defined(__linux__)
- + return false;
- +#else /* __mips__ */
- +/* For PTRACE_GETREGS */
- +
- + struct pt_regs gregs;
- + if (ptrace (PTRACE_GETREGS, tid, 0, &gregs) != 0)
- + return false;
- + if (! setfunc (-1, 1, (Dwarf_Word *) &gregs.cp0_epc, arg))
- + return false;
- + return setfunc (0, 32, (Dwarf_Word *) &gregs.regs[0], arg);
- +#endif /* __mips__ */
- +}
- --- /dev/null
- +++ b/backends/mips_unwind.c
- @@ -0,0 +1,84 @@
- +/* Get previous frame state for an existing frame state.
- + Copyright (C) 2016 The Qt Company Ltd.
- + Copyright (C) 2024 CIP United Inc.
- + This file is part of elfutils.
- +
- + This file is free software; you can redistribute it and/or modify
- + it under the terms of either
- +
- + * the GNU Lesser General Public License as published by the Free
- + Software Foundation; either version 3 of the License, or (at
- + your option) any later version
- +
- + or
- +
- + * the GNU General Public License as published by the Free
- + Software Foundation; either version 2 of the License, or (at
- + your option) any later version
- +
- + or both in parallel, as here.
- +
- + elfutils is distributed in the hope that it will be useful, but
- + WITHOUT ANY WARRANTY; without even the implied warranty of
- + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + General Public License for more details.
- +
- + You should have received copies of the GNU General Public License and
- + the GNU Lesser General Public License along with this program. If
- + not, see <http://www.gnu.org/licenses/>. */
- +
- +#ifdef HAVE_CONFIG_H
- +# include <config.h>
- +#endif
- +
- +#define BACKEND mips_
- +#define SP_REG 29
- +#define FP_REG 30
- +#define LR_REG 31
- +#define FP_OFFSET 0
- +#define LR_OFFSET 8
- +#define SP_OFFSET 16
- +
- +#include "libebl_CPU.h"
- +
- +/* There was no CFI. Maybe we happen to have a frame pointer and can unwind from that? */
- +
- +bool
- +EBLHOOK(unwind) (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr pc __attribute__ ((unused)),
- + ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t *getfunc,
- + ebl_pid_memory_read_t *readfunc, void *arg,
- + bool *signal_framep __attribute__ ((unused)))
- +{
- + Dwarf_Word fp, lr, sp;
- +
- + if (!getfunc(LR_REG, 1, &lr, arg))
- + return false;
- +
- + if (lr == 0 || !setfunc(-1, 1, &lr, arg))
- + return false;
- +
- + if (!getfunc(FP_REG, 1, &fp, arg))
- + fp = 0;
- +
- + if (!getfunc(SP_REG, 1, &sp, arg))
- + sp = 0;
- +
- + Dwarf_Word newLr, newFp, newSp;
- +
- + if (!readfunc(fp + LR_OFFSET, &newLr, arg))
- + newLr = 0;
- +
- + if (!readfunc(fp + FP_OFFSET, &newFp, arg))
- + newFp = 0;
- +
- + newSp = fp + SP_OFFSET;
- +
- + // These are not fatal if they don't work. They will just prevent unwinding at the next frame.
- + setfunc(LR_REG, 1, &newLr, arg);
- + setfunc(FP_REG, 1, &newFp, arg);
- + setfunc(SP_REG, 1, &newSp, arg);
- +
- + // If the fp is invalid, we might still have a valid lr.
- + // But if the fp is valid, then the stack should be moving in the right direction.
- + return fp == 0 || newSp > sp;
- +}
|