diff options
Diffstat (limited to 'packages/gdb/10.2/0006-arc-Add-support-for-signal-frames-for-Linux-targets.patch')
-rw-r--r-- | packages/gdb/10.2/0006-arc-Add-support-for-signal-frames-for-Linux-targets.patch | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/packages/gdb/10.2/0006-arc-Add-support-for-signal-frames-for-Linux-targets.patch b/packages/gdb/10.2/0006-arc-Add-support-for-signal-frames-for-Linux-targets.patch new file mode 100644 index 00000000..add2a0e2 --- /dev/null +++ b/packages/gdb/10.2/0006-arc-Add-support-for-signal-frames-for-Linux-targets.patch @@ -0,0 +1,240 @@ +From 27a456bbaa0c525e534195d17345c2e9268dd5d2 Mon Sep 17 00:00:00 2001 +From: Anton Kolesov <Anton.Kolesov@synopsys.com> +Date: Thu, 22 Dec 2016 21:52:16 +0300 +Subject: [PATCH 07/20] arc: Add support for signal frames for Linux targets + +Implement functions needed to unwind signal frames on ARC Linux targets. + +gdb/ChangeLog + + * arc-linux-tdep.c (arc_linux_sc_reg_offsets): New static variable. + (arc_linux_is_sigtramp): New function. + (arc_linux_sigcontext_addr): Likewise. + (arc_linux_init_osabi): Use them. + +Will be a part of GDB 11: +https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=d4af727286e3a9f177ba11677fbd3a012d36558a +--- + gdb/ChangeLog | 7 + + gdb/arc-linux-tdep.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 188 insertions(+) + +--- a/gdb/ChangeLog ++++ b/gdb/ChangeLog +@@ -1,5 +1,12 @@ + 2020-12-22 Anton Kolesov <anton.kolesov@synopsys.com> + ++ * arc-linux-tdep.c (arc_linux_sc_reg_offsets): New static variable. ++ (arc_linux_is_sigtramp): New function. ++ (arc_linux_sigcontext_addr): Likewise. ++ (arc_linux_init_osabi): Use them. ++ ++2020-12-22 Anton Kolesov <anton.kolesov@synopsys.com> ++ + * arc-tdep.c (arc_make_sigtramp_frame_cache): New function. + (arc_sigtramp_frame_this_id): Likewise. + (arc_sigtramp_frame_prev_register): Likewise. +--- a/gdb/arc-linux-tdep.c ++++ b/gdb/arc-linux-tdep.c +@@ -33,6 +33,60 @@ + + #define REGOFF(offset) (offset * ARC_REGISTER_SIZE) + ++/* arc_linux_sc_reg_offsets[i] is the offset of register i in the `struct ++ sigcontext'. Array index is an internal GDB register number, as defined in ++ arc-tdep.h:arc_regnum. ++ ++ From <include/uapi/asm/sigcontext.h> and <include/uapi/asm/ptrace.h>. ++ ++ The layout of this struct is tightly bound to "arc_regnum" enum ++ in arc-tdep.h. Any change of order in there, must be reflected ++ here as well. */ ++static const int arc_linux_sc_reg_offsets[] = { ++ /* R0 - R12. */ ++ REGOFF (22), REGOFF (21), REGOFF (20), REGOFF (19), ++ REGOFF (18), REGOFF (17), REGOFF (16), REGOFF (15), ++ REGOFF (14), REGOFF (13), REGOFF (12), REGOFF (11), ++ REGOFF (10), ++ ++ /* R13 - R25. */ ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ++ ++ REGOFF (9), /* R26 (GP) */ ++ REGOFF (8), /* FP */ ++ REGOFF (23), /* SP */ ++ ARC_OFFSET_NO_REGISTER, /* ILINK */ ++ ARC_OFFSET_NO_REGISTER, /* R30 */ ++ REGOFF (7), /* BLINK */ ++ ++ /* R32 - R59. */ ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ++ ARC_OFFSET_NO_REGISTER, ++ ++ REGOFF (4), /* LP_COUNT */ ++ ARC_OFFSET_NO_REGISTER, /* RESERVED */ ++ ARC_OFFSET_NO_REGISTER, /* LIMM */ ++ ARC_OFFSET_NO_REGISTER, /* PCL */ ++ ++ REGOFF (6), /* PC */ ++ REGOFF (5), /* STATUS32 */ ++ REGOFF (2), /* LP_START */ ++ REGOFF (3), /* LP_END */ ++ REGOFF (1), /* BTA */ ++}; ++ + /* arc_linux_core_reg_offsets[i] is the offset in the .reg section of GDB + regnum i. Array index is an internal GDB register number, as defined in + arc-tdep.h:arc_regnum. +@@ -87,6 +141,127 @@ + REGOFF (6) /* ERET */ + }; + ++/* Is THIS_FRAME a sigtramp function - the function that returns from ++ signal handler into normal execution flow? This is the case if the PC is ++ either at the start of, or in the middle of the two instructions: ++ ++ mov r8, __NR_rt_sigreturn ; __NR_rt_sigreturn == 139 ++ trap_s 0 ; `swi' for ARC700 ++ ++ On ARC uClibc Linux this function is called __default_rt_sa_restorer. ++ ++ Returns TRUE if this is a sigtramp frame. */ ++ ++static bool ++arc_linux_is_sigtramp (struct frame_info *this_frame) ++{ ++ struct gdbarch *gdbarch = get_frame_arch (this_frame); ++ CORE_ADDR pc = get_frame_pc (this_frame); ++ ++ if (arc_debug) ++ { ++ debug_printf ("arc-linux: arc_linux_is_sigtramp, pc=%s\n", ++ paddress(gdbarch, pc)); ++ } ++ ++ static const gdb_byte insns_be_hs[] = { ++ 0x20, 0x8a, 0x12, 0xc2, /* mov r8,nr_rt_sigreturn */ ++ 0x78, 0x1e /* trap_s 0 */ ++ }; ++ static const gdb_byte insns_be_700[] = { ++ 0x20, 0x8a, 0x12, 0xc2, /* mov r8,nr_rt_sigreturn */ ++ 0x22, 0x6f, 0x00, 0x3f /* swi */ ++ }; ++ ++ gdb_byte arc_sigtramp_insns[sizeof (insns_be_700)]; ++ size_t insns_sz; ++ if (arc_mach_is_arcv2 (gdbarch)) ++ { ++ insns_sz = sizeof (insns_be_hs); ++ memcpy (arc_sigtramp_insns, insns_be_hs, insns_sz); ++ } ++ else ++ { ++ insns_sz = sizeof (insns_be_700); ++ memcpy (arc_sigtramp_insns, insns_be_700, insns_sz); ++ } ++ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE) ++ { ++ /* On little endian targets, ARC code section is in what is called ++ "middle endian", where half-words are in the big-endian order, ++ only bytes inside the halfwords are in the little endian order. ++ As a result it is very easy to convert big endian instruction to ++ little endian, since it is needed to swap bytes in the halfwords, ++ so there is no need to have information on whether that is a ++ 4-byte instruction or 2-byte. */ ++ gdb_assert ((insns_sz % 2) == 0); ++ for (int i = 0; i < insns_sz; i += 2) ++ std::swap (arc_sigtramp_insns[i], arc_sigtramp_insns[i+1]); ++ } ++ ++ gdb_byte buf[insns_sz]; ++ ++ /* Read the memory at the PC. Since we are stopped, any breakpoint must ++ have been removed. */ ++ if (!safe_frame_unwind_memory (this_frame, pc, buf, insns_sz)) ++ { ++ /* Failed to unwind frame. */ ++ return FALSE; ++ } ++ ++ /* Is that code the sigtramp instruction sequence? */ ++ if (memcmp (buf, arc_sigtramp_insns, insns_sz) == 0) ++ return TRUE; ++ ++ /* No - look one instruction earlier in the code... */ ++ if (!safe_frame_unwind_memory (this_frame, pc - 4, buf, insns_sz)) ++ { ++ /* Failed to unwind frame. */ ++ return FALSE; ++ } ++ ++ return (memcmp (buf, arc_sigtramp_insns, insns_sz) == 0); ++} ++ ++/* Get sigcontext structure of sigtramp frame - it contains saved ++ registers of interrupted frame. ++ ++ Stack pointer points to the rt_sigframe structure, and sigcontext can ++ be found as in: ++ ++ struct rt_sigframe { ++ struct siginfo info; ++ struct ucontext uc; ++ ... ++ }; ++ ++ struct ucontext { ++ unsigned long uc_flags; ++ struct ucontext *uc_link; ++ stack_t uc_stack; ++ struct sigcontext uc_mcontext; ++ sigset_t uc_sigmask; ++ }; ++ ++ sizeof (struct siginfo) == 0x80 ++ offsetof (struct ucontext, uc_mcontext) == 0x14 ++ ++ GDB cannot include linux headers and use offsetof () because those are ++ target headers and GDB might be built for a different run host. There ++ doesn't seem to be an established mechanism to figure out those offsets ++ via gdbserver, so the only way is to hardcode values in the GDB, ++ meaning that GDB will be broken if values will change. That seems to ++ be a very unlikely scenario and other arches (aarch64, alpha, amd64, ++ etc) in GDB hardcode values. */ ++ ++static CORE_ADDR ++arc_linux_sigcontext_addr (struct frame_info *this_frame) ++{ ++ const int ucontext_offset = 0x80; ++ const int sigcontext_offset = 0x14; ++ return get_frame_sp (this_frame) + ucontext_offset + sigcontext_offset; ++} ++ + /* Implement the "cannot_fetch_register" gdbarch method. */ + + static int +@@ -504,6 +679,12 @@ + if (arc_debug) + debug_printf ("arc-linux: GNU/Linux OS/ABI initialization.\n"); + ++ /* Fill in target-dependent info in ARC-private structure. */ ++ tdep->is_sigtramp = arc_linux_is_sigtramp; ++ tdep->sigcontext_addr = arc_linux_sigcontext_addr; ++ tdep->sc_reg_offset = arc_linux_sc_reg_offsets; ++ tdep->sc_num_regs = ARRAY_SIZE (arc_linux_sc_reg_offsets); ++ + /* If we are using Linux, we have in uClibc + (libc/sysdeps/linux/arc/bits/setjmp.h): + |