binutils-gdb/gdb/tramp-frame.h

89 lines
3.2 KiB
C
Raw Normal View History

/* Signal trampoline unwinder.
Copyright (C) 2004-2024 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef TRAMP_FRAME_H
#define TRAMP_FRAME_H
#include "frame.h"
sme: Fixup sigframe gdbarch when vg/svg changes With SME, where you have two different vector lengths (vl and svl), it may be the case that the current frame has a set of vector lengths (A) but the signal context has a distinct set of vector lengths (B). In this case, we may run into a situation where GDB attempts to use a gdbarch created for set A, but it is really dealing with a frame that was using set B. This is problematic, specially with SME, because now we have a different number of pseudo-registers and types that gets cached on creation of each gdbarch variation. For AArch64 we really need to be able to use the correct gdbarch for each frame, and I noticed the signal frame (tramp-frame) doesn't have a settable prev_arch field. So it ends up using the default frame_unwind_arch function and eventually calling get_frame_arch (next_frame). That means the previous frame will always have the same gdbarch as the current frame. This patch first refactors the AArch64/Linux signal context code, simplifying it and making it reusable for our purposes of calculating the previous frame's gdbarch. I introduced a struct that holds information that we have found in the signal context, and with which we can make various decisions. Finally, a small change to tramp-frame.c and tramp-frame.h to expose a prev_arch hook that the architecture can set. With this new field, AArch64/Linux can implement a hook that looks at the signal context and infers the gdbarch for the previous frame. Regression-tested on aarch64-linux Ubuntu 22.04/20.04. Approved-By: Simon Marchi <simon.marchi@efficios.com> Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-02 22:00:58 +08:00
#include "frame-unwind.h" /* For frame_prev_arch_ftype. */
class frame_info_ptr;
struct trad_frame_cache;
/* A trampoline consists of a small sequence of instructions placed at
an unspecified location in the inferior's address space. The only
identifying attribute of the trampoline's address is that it does
not fall inside an object file's section.
The only way to identify a trampoline is to perform a brute force
examination of the instructions at and around the PC.
This module provides a convenient interface for performing that
operation. */
/* A trampoline descriptor. */
/* Magic instruction that to mark the end of the signal trampoline
instruction sequence. */
Avoid -Wnarrowing warnings in struct tramp_frame instances This avoids -Wnarrowing warnings in struct tramp_frame instances, replacing uses of -1 with a new ULONGEST_MAX. It also redefined TRAMP_SENTINEL_INSN to avoid the same warning. gdb/ChangeLog 2018-08-27 Tom Tromey <tom@tromey.com> * tramp-frame.h (TRAMP_SENTINEL_INSN): Redefine. * tilegx-linux-tdep.c (tilegx_linux_rt_sigframe): Use ULONGEST_MAX. * tic6x-linux-tdep.c (tic6x_linux_rt_sigreturn_tramp_frame): Use ULONGEST_MAX. * sparc64-linux-tdep.c (sparc64_linux_rt_sigframe): Use ULONGEST_MAX. * sparc-linux-tdep.c (sparc32_linux_sigframe) (sparc32_linux_rt_sigframe): Use ULONGEST_MAX. * ppc-nbsd-tdep.c (ppcnbsd_sigtramp, ppcnbsd2_sigtramp): Use ULONGEST_MAX. * ppc-linux-tdep.c (ppc32_linux_sigaction_tramp_frame) (ppc64_linux_sigaction_tramp_frame) (ppc32_linux_sighandler_tramp_frame) (ppc64_linux_sighandler_tramp_frame): Use ULONGEST_MAX. * nios2-linux-tdep.c (nios2_r1_linux_rt_sigreturn_tramp_frame) (nios2_r2_linux_rt_sigreturn_tramp_frame): Use ULONGEST_MAX. * mn10300-linux-tdep.c (am33_linux_sigframe) (am33_linux_rt_sigframe): Use ULONGEST_MAX. * mips64-obsd-tdep.c (mips64obsd_sigframe): Use ULONGEST_MAX. * mips-linux-tdep.c (mips_linux_o32_sigframe) (mips_linux_o32_rt_sigframe, mips_linux_n32_rt_sigframe) (mips_linux_n64_rt_sigframe, micromips_linux_o32_sigframe) (micromips_linux_o32_rt_sigframe, micromips_linux_n32_rt_sigframe) (micromips_linux_n64_rt_sigframe): Use ULONGEST_MAX. * mips-fbsd-tdep.c (mips_fbsd_sigframe, mipsn32_fbsd_sigframe) (mips64_fbsd_sigframe): Use ULONGEST_MAX. * microblaze-linux-tdep.c (microblaze_linux_sighandler_tramp_frame): Use ULONGEST_MAX. * i386-nbsd-tdep.c (i386nbsd_sigtramp_sc16, i386nbsd_sigtramp_sc2) (i386nbsd_sigtramp_si2, i386nbsd_sigtramp_si31) (i386nbsd_sigtramp_si4): Use ULONGEST_MAX. * hppa-nbsd-tdep.c (hppanbsd_sigtramp_si4): Use ULONGEST_MAX. * common/common-types.h (ULONGEST_MAX): New define. (CORE_ADDR_MAX): Fix formatting. * bfin-linux-tdep.c (bfin_linux_sigframe): Use ULONGEST_MAX. * arm-obsd-tdep.c (armobsd_sigframe): Use ULONGEST_MAX. * arm-linux-tdep.c (arm_linux_sigreturn_tramp_frame) (arm_linux_rt_sigreturn_tramp_frame) (arm_eabi_linux_sigreturn_tramp_frame) (arm_eabi_linux_rt_sigreturn_tramp_frame) (thumb2_eabi_linux_sigreturn_tramp_frame) (thumb2_eabi_linux_rt_sigreturn_tramp_frame) (arm_linux_restart_syscall_tramp_frame) (arm_kernel_linux_restart_syscall_tramp_frame): Use ULONGEST_MAX. * arm-fbsd-tdep.c (arm_fbsd_sigframe): Use ULONGEST_MAX. * aarch64-linux-tdep.c (aarch64_linux_rt_sigframe): Use ULONGEST_MAX. * aarch64-fbsd-tdep.c (aarch64_fbsd_sigframe): Use ULONGEST_MAX.
2018-08-08 03:04:05 +08:00
#define TRAMP_SENTINEL_INSN ULONGEST_MAX
struct tramp_frame
{
/* The trampoline's type, some a signal trampolines, some are normal
call-frame trampolines (aka thunks). */
enum frame_type frame_type;
/* The trampoline's entire instruction sequence. It consists of a
bytes/mask pair. Search for this in the inferior at or around
the frame's PC. It is assumed that the PC is INSN_SIZE aligned,
and that each element of TRAMP contains one INSN_SIZE
instruction. It is also assumed that INSN[0] contains the first
instruction of the trampoline and hence the address of the
instruction matching INSN[0] is the trampoline's "func" address.
The instruction sequence is terminated by
TRAMP_SENTINEL_INSN. */
int insn_size;
struct
{
ULONGEST bytes;
ULONGEST mask;
} insn[48];
/* Initialize a trad-frame cache corresponding to the tramp-frame.
FUNC is the address of the instruction TRAMP[0] in memory. */
void (*init) (const struct tramp_frame *self,
gdb: pass frames as `const frame_info_ptr &` We currently pass frames to function by value, as `frame_info_ptr`. This is somewhat expensive: - the size of `frame_info_ptr` is 64 bytes, which is a bit big to pass by value - the constructors and destructor link/unlink the object in the global `frame_info_ptr::frame_list` list. This is an `intrusive_list`, so it's not so bad: it's just assigning a few points, there's no memory allocation as if it was `std::list`, but still it's useless to do that over and over. As suggested by Tom Tromey, change many function signatures to accept `const frame_info_ptr &` instead of `frame_info_ptr`. Some functions reassign their `frame_info_ptr` parameter, like: void the_func (frame_info_ptr frame) { for (; frame != nullptr; frame = get_prev_frame (frame)) { ... } } I wondered what to do about them, do I leave them as-is or change them (and need to introduce a separate local variable that can be re-assigned). I opted for the later for consistency. It might not be clear why some functions take `const frame_info_ptr &` while others take `frame_info_ptr`. Also, if a function took a `frame_info_ptr` because it did re-assign its parameter, I doubt that we would think to change it to `const frame_info_ptr &` should the implementation change such that it doesn't need to take `frame_info_ptr` anymore. It seems better to have a simple rule and apply it everywhere. Change-Id: I59d10addef687d157f82ccf4d54f5dde9a963fd0 Approved-By: Andrew Burgess <aburgess@redhat.com>
2024-02-20 02:07:47 +08:00
const frame_info_ptr &this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func);
MIPS: Add support for microMIPS Linux signal trampolines The necessity for this change has been revealed in the course of investigation related to proposed changes in the treatment of the ISA bit encoded in function symbols on the MIPS target. This change adds support for Linux signal trampolines encoded with the microMIPS instruction set. Such trampolines are used by the Linux kernel if compiled as a microMIPS binary (even if the binary run/debugged itself contains no microMIPS code at all). To see if we need to check whether the execution mode selected matches the given trampoline I have checked what the bit patterns of all the trampoline sequences decode to in the opposite instruction set. This produced useless or at least unusual code in most cases, for example: microMIPS/EB, o32 sigreturn, decoded as MIPS code: 30401017 andi zero,v0,0x1017 00008b7c dsll32 s1,zero,0xd MIPS/EL, o32 sigreturn, decoded as microMIPS code: 1017 2402 addi zero,s7,9218 000c 0000 sll zero,t0,0x0 However in some corner cases reasonable code can mimic a trampoline, for example: MIPS/EB, n32 rt_sigreturn, decoded as microMIPS code: 2402 sll s0,s0,1 1843 0000 sb v0,0(v1) 000c 0f3c jr t0 -- here the first instruction is a 16-bit one, making things nastier even as there are some other microMIPS instructions whose first 16-bit halfword is 0x000c and therefore matches this whole trampoline pattern. To overcome this problem I have decided the signal trampoline unwinder has to ask the platform backend whether it can apply a given trampoline pattern to the code location being concerned or not. Anticipating the acceptance of the ISA bit proposal I decided the handler not to merely be a predicate, but also to be able to provide an adjusted PC if required. I decided that returning zero will mean that the trampoline pattern is not applicable and any other value is the adjusted PC to use; a handler may return the value requested if the trampoline pattern and the PC requested as-is are both accepted. This changes the semantics of the trampoline unwinder a bit in that the zero PC now has a special value. I think this should be safe as a NULL pointer is generally supposed to be invalid. * tramp-frame.h (tramp_frame): Add `validate' member. * tramp-frame.c (tramp_frame_start): Validate trampoline before scanning. * mips-linux-tdep.c (MICROMIPS_INST_LI_V0): New macro. (MICROMIPS_INST_POOL32A, MICROMIPS_INST_SYSCALL): Likewise. (mips_linux_o32_sigframe): Initialize `validate' member. (mips_linux_o32_rt_sigframe): Likewise. (mips_linux_n32_rt_sigframe): Likewise. (mips_linux_n64_rt_sigframe): Likewise. (micromips_linux_o32_sigframe): New variable. (micromips_linux_o32_rt_sigframe): Likewise. (micromips_linux_n32_rt_sigframe): Likewise. (micromips_linux_n64_rt_sigframe): Likewise. (mips_linux_o32_sigframe_init): Handle microMIPS trampolines. (mips_linux_n32n64_sigframe_init): Likewise. (mips_linux_sigframe_validate): New function. (micromips_linux_sigframe_validate): Likewise. (mips_linux_init_abi): Install microMIPS trampoline unwinders.
2014-12-04 03:19:41 +08:00
/* Return non-zero if the tramp-frame is valid for the PC requested.
Adjust the PC to point to the address to check the instruction
sequence against if required. If this is NULL, then the tramp-frame
is valid for any PC. */
int (*validate) (const struct tramp_frame *self,
gdb: pass frames as `const frame_info_ptr &` We currently pass frames to function by value, as `frame_info_ptr`. This is somewhat expensive: - the size of `frame_info_ptr` is 64 bytes, which is a bit big to pass by value - the constructors and destructor link/unlink the object in the global `frame_info_ptr::frame_list` list. This is an `intrusive_list`, so it's not so bad: it's just assigning a few points, there's no memory allocation as if it was `std::list`, but still it's useless to do that over and over. As suggested by Tom Tromey, change many function signatures to accept `const frame_info_ptr &` instead of `frame_info_ptr`. Some functions reassign their `frame_info_ptr` parameter, like: void the_func (frame_info_ptr frame) { for (; frame != nullptr; frame = get_prev_frame (frame)) { ... } } I wondered what to do about them, do I leave them as-is or change them (and need to introduce a separate local variable that can be re-assigned). I opted for the later for consistency. It might not be clear why some functions take `const frame_info_ptr &` while others take `frame_info_ptr`. Also, if a function took a `frame_info_ptr` because it did re-assign its parameter, I doubt that we would think to change it to `const frame_info_ptr &` should the implementation change such that it doesn't need to take `frame_info_ptr` anymore. It seems better to have a simple rule and apply it everywhere. Change-Id: I59d10addef687d157f82ccf4d54f5dde9a963fd0 Approved-By: Andrew Burgess <aburgess@redhat.com>
2024-02-20 02:07:47 +08:00
const frame_info_ptr &this_frame,
MIPS: Add support for microMIPS Linux signal trampolines The necessity for this change has been revealed in the course of investigation related to proposed changes in the treatment of the ISA bit encoded in function symbols on the MIPS target. This change adds support for Linux signal trampolines encoded with the microMIPS instruction set. Such trampolines are used by the Linux kernel if compiled as a microMIPS binary (even if the binary run/debugged itself contains no microMIPS code at all). To see if we need to check whether the execution mode selected matches the given trampoline I have checked what the bit patterns of all the trampoline sequences decode to in the opposite instruction set. This produced useless or at least unusual code in most cases, for example: microMIPS/EB, o32 sigreturn, decoded as MIPS code: 30401017 andi zero,v0,0x1017 00008b7c dsll32 s1,zero,0xd MIPS/EL, o32 sigreturn, decoded as microMIPS code: 1017 2402 addi zero,s7,9218 000c 0000 sll zero,t0,0x0 However in some corner cases reasonable code can mimic a trampoline, for example: MIPS/EB, n32 rt_sigreturn, decoded as microMIPS code: 2402 sll s0,s0,1 1843 0000 sb v0,0(v1) 000c 0f3c jr t0 -- here the first instruction is a 16-bit one, making things nastier even as there are some other microMIPS instructions whose first 16-bit halfword is 0x000c and therefore matches this whole trampoline pattern. To overcome this problem I have decided the signal trampoline unwinder has to ask the platform backend whether it can apply a given trampoline pattern to the code location being concerned or not. Anticipating the acceptance of the ISA bit proposal I decided the handler not to merely be a predicate, but also to be able to provide an adjusted PC if required. I decided that returning zero will mean that the trampoline pattern is not applicable and any other value is the adjusted PC to use; a handler may return the value requested if the trampoline pattern and the PC requested as-is are both accepted. This changes the semantics of the trampoline unwinder a bit in that the zero PC now has a special value. I think this should be safe as a NULL pointer is generally supposed to be invalid. * tramp-frame.h (tramp_frame): Add `validate' member. * tramp-frame.c (tramp_frame_start): Validate trampoline before scanning. * mips-linux-tdep.c (MICROMIPS_INST_LI_V0): New macro. (MICROMIPS_INST_POOL32A, MICROMIPS_INST_SYSCALL): Likewise. (mips_linux_o32_sigframe): Initialize `validate' member. (mips_linux_o32_rt_sigframe): Likewise. (mips_linux_n32_rt_sigframe): Likewise. (mips_linux_n64_rt_sigframe): Likewise. (micromips_linux_o32_sigframe): New variable. (micromips_linux_o32_rt_sigframe): Likewise. (micromips_linux_n32_rt_sigframe): Likewise. (micromips_linux_n64_rt_sigframe): Likewise. (mips_linux_o32_sigframe_init): Handle microMIPS trampolines. (mips_linux_n32n64_sigframe_init): Likewise. (mips_linux_sigframe_validate): New function. (micromips_linux_sigframe_validate): Likewise. (mips_linux_init_abi): Install microMIPS trampoline unwinders.
2014-12-04 03:19:41 +08:00
CORE_ADDR *pc);
sme: Fixup sigframe gdbarch when vg/svg changes With SME, where you have two different vector lengths (vl and svl), it may be the case that the current frame has a set of vector lengths (A) but the signal context has a distinct set of vector lengths (B). In this case, we may run into a situation where GDB attempts to use a gdbarch created for set A, but it is really dealing with a frame that was using set B. This is problematic, specially with SME, because now we have a different number of pseudo-registers and types that gets cached on creation of each gdbarch variation. For AArch64 we really need to be able to use the correct gdbarch for each frame, and I noticed the signal frame (tramp-frame) doesn't have a settable prev_arch field. So it ends up using the default frame_unwind_arch function and eventually calling get_frame_arch (next_frame). That means the previous frame will always have the same gdbarch as the current frame. This patch first refactors the AArch64/Linux signal context code, simplifying it and making it reusable for our purposes of calculating the previous frame's gdbarch. I introduced a struct that holds information that we have found in the signal context, and with which we can make various decisions. Finally, a small change to tramp-frame.c and tramp-frame.h to expose a prev_arch hook that the architecture can set. With this new field, AArch64/Linux can implement a hook that looks at the signal context and infers the gdbarch for the previous frame. Regression-tested on aarch64-linux Ubuntu 22.04/20.04. Approved-By: Simon Marchi <simon.marchi@efficios.com> Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
2023-02-02 22:00:58 +08:00
/* Given the current frame in THIS_FRAME and a frame cache in FRAME_CACHE,
return the architecture of the previous frame. */
frame_prev_arch_ftype *prev_arch;
};
void tramp_frame_prepend_unwinder (struct gdbarch *gdbarch,
const struct tramp_frame *tramp);
#endif