mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-03 04:12:10 +08:00
858339f2b7
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.
85 lines
3.0 KiB
C
85 lines
3.0 KiB
C
/* Signal trampoline unwinder.
|
|
|
|
Copyright (C) 2004-2014 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" /* For "enum frame_type". */
|
|
|
|
struct trad_frame;
|
|
struct frame_info;
|
|
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. */
|
|
#define TRAMP_SENTINEL_INSN ((LONGEST) -1)
|
|
|
|
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,
|
|
struct frame_info *this_frame,
|
|
struct trad_frame_cache *this_cache,
|
|
CORE_ADDR func);
|
|
/* 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,
|
|
struct frame_info *this_frame,
|
|
CORE_ADDR *pc);
|
|
};
|
|
|
|
void tramp_frame_prepend_unwinder (struct gdbarch *gdbarch,
|
|
const struct tramp_frame *tramp);
|
|
|
|
#endif
|