* [PATCH 0/2] arc: Add signal handling support
@ 2020-10-22 16:51 Shahab Vahedi
2020-10-22 16:51 ` [PATCH 1/2] arc: Add support for signal handlers Shahab Vahedi
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: Shahab Vahedi @ 2020-10-22 16:51 UTC (permalink / raw)
To: gdb-patches; +Cc: Shahab Vahedi, Shahab Vahedi, Anton Kolesov, Francois Bedard
From: Shahab Vahedi <shahab@synopsys.com>
These 2 patches add the infrastructure and necessary hooks to process
the handle signal handlers in ARC targets. The first patch mostly add
the necessary infrastructure/place holders and the second one adds the
hooks for handling an ARC Linux target.
Anton Kolesov (2):
arc: Add support for signal handlers
arc: Add support for signal frames for Linux targets
gdb/arc-linux-tdep.c | 181 +++++++++++++++++++++++++++++++++++++++++++
gdb/arc-tdep.c | 126 ++++++++++++++++++++++++++++++
gdb/arc-tdep.h | 13 ++++
3 files changed, 320 insertions(+)
--
2.29.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/2] arc: Add support for signal handlers
2020-10-22 16:51 [PATCH 0/2] arc: Add signal handling support Shahab Vahedi
@ 2020-10-22 16:51 ` Shahab Vahedi
2020-11-12 17:47 ` Tom Tromey
2020-10-22 16:51 ` [PATCH 2/2] arc: Add support for signal frames for Linux targets Shahab Vahedi
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Shahab Vahedi @ 2020-10-22 16:51 UTC (permalink / raw)
To: gdb-patches
Cc: Shahab Vahedi, Shahab Vahedi, Anton Kolesov, Francois Bedard,
Anton Kolesov
From: Anton Kolesov <Anton.Kolesov@synopsys.com>
This patch adds the necessary infrastructure to handle signal frames for
ARC architecture. It is fairly similar to what any other architecture
would have. Linux specific parts will be in a separate patch.
gdb/ChangeLog:
* arc-tdep.c (arc_make_sigtramp_frame_cache): New function.
(arc_sigtramp_frame_this_id): Likewise.
(arc_sigtramp_frame_prev_register): Likewise.
(arc_sigtramp_frame_sniffer): Likewise.
(arc_siftramp_frame_unwind): New global variable.
(arc_gdbarch_init): Use sigtramp capabilities.
(arc_dump_tdep): Print sigtramp fields.
* arc-tdep.h (gdbarch_tdep): Add sigtramp fields.
---
gdb/arc-tdep.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++
gdb/arc-tdep.h | 13 +++++
2 files changed, 139 insertions(+)
diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index 3b7a419dfc1..40484522a1a 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -1843,6 +1843,107 @@ arc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
reg->how = DWARF2_FRAME_REG_CFA;
}
+/* Signal trampoline frame unwinder. Allows frame unwinding to happen
+ from within signal handlers. */
+
+static struct arc_frame_cache *
+arc_make_sigtramp_frame_cache (struct frame_info *this_frame)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_cache\n");
+
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
+
+ /* Allocate new frame cache instance and space for saved register info. */
+ struct arc_frame_cache *cache = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ /* Get the stack pointer and use it as the frame base. */
+ cache->prev_sp = arc_frame_base_address (this_frame, NULL);
+
+ /* If the ARC-private target-dependent info doesn't have a table of
+ offsets of saved register contents within an OS signal context
+ structure, then there is nothing to analyze. */
+ if (tdep->sc_reg_offset == NULL)
+ return cache;
+
+ /* Find the address of the sigcontext structure. */
+ CORE_ADDR addr = tdep->sigcontext_addr (this_frame);
+
+ /* For each register, if its contents have been saved within the
+ sigcontext structure, determine the address of those contents. */
+ gdb_assert (tdep->sc_num_regs <= (ARC_LAST_REGNUM + 1));
+ for (int i = 0; i < tdep->sc_num_regs; i++)
+ {
+ if (tdep->sc_reg_offset[i] != ARC_OFFSET_NO_REGISTER)
+ cache->saved_regs[i].addr = addr + tdep->sc_reg_offset[i];
+ }
+
+ return cache;
+}
+
+/* Implement the "this_id" frame_unwind method for signal trampoline
+ frames. */
+
+static void
+arc_sigtramp_frame_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_this_id\n");
+
+ if (*this_cache == NULL)
+ *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+ CORE_ADDR stack_addr = cache->prev_sp;
+ CORE_ADDR code_addr
+ = get_frame_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch));
+ *this_id = frame_id_build (stack_addr, code_addr);
+}
+
+/* Get a register from a signal handler frame. */
+
+static struct value *
+arc_sigtramp_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_prev_register (regnum = %d)\n", regnum);
+
+ /* Make sure we've initialized the cache. */
+ if (*this_cache == NULL)
+ *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+ struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+/* Frame sniffer for signal handler frame. Only recognize a frame if we
+ have a sigcontext_addr handler in the target dependency. */
+
+static int
+arc_sigtramp_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct gdbarch_tdep *tdep;
+
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_sniffer\n");
+
+ tdep = gdbarch_tdep (get_frame_arch (this_frame));
+
+ /* If we have a sigcontext_addr handler, then just use the default frame
+ sniffer. */
+ if ((tdep->sigcontext_addr != NULL) && (tdep->is_sigtramp != NULL)
+ && tdep->is_sigtramp (this_frame))
+ return default_frame_sniffer (self, this_frame, this_cache);
+ else
+ return FALSE;
+}
+
/* Structure defining the ARC ordinary frame unwind functions. Since we are
the fallback unwinder, we use the default frame sniffer, which always
accepts the frame. */
@@ -1858,6 +1959,21 @@ static const struct frame_unwind arc_frame_unwind = {
NULL
};
+/* Structure defining the ARC signal frame unwind functions. Custom
+ sniffer is used, because this frame must be accepted only in the right
+ context. */
+
+static const struct frame_unwind arc_sigtramp_frame_unwind = {
+ SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
+ arc_sigtramp_frame_this_id,
+ arc_sigtramp_frame_prev_register,
+ NULL,
+ arc_sigtramp_frame_sniffer,
+ NULL,
+ NULL
+};
+
static const struct frame_base arc_normal_base = {
&arc_frame_unwind,
@@ -2271,6 +2387,7 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Frame unwinders and sniffers. */
dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg);
dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &arc_sigtramp_frame_unwind);
frame_unwind_append_unwinder (gdbarch, &arc_frame_unwind);
frame_base_set_default (gdbarch, &arc_normal_base);
@@ -2349,6 +2466,15 @@ arc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
fprintf_unfiltered (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc);
+
+ fprintf_unfiltered (file, "arc_dump_tdep: is_sigtramp = <%s>\n",
+ host_address_to_string (tdep->is_sigtramp));
+ fprintf_unfiltered (file, "arc_dump_tdep: sigcontext_addr = <%s>\n",
+ host_address_to_string (tdep->sigcontext_addr));
+ fprintf_unfiltered (file, "arc_dump_tdep: sc_reg_offset = <%s>\n",
+ host_address_to_string (tdep->sc_reg_offset));
+ fprintf_unfiltered (file, "arc_dump_tdep: sc_num_regs = %d\n",
+ tdep->sc_num_regs);
}
/* This command accepts single argument - address of instruction to
diff --git a/gdb/arc-tdep.h b/gdb/arc-tdep.h
index 09fcbeab9c7..5ee5cf85c6c 100644
--- a/gdb/arc-tdep.h
+++ b/gdb/arc-tdep.h
@@ -124,6 +124,19 @@ struct gdbarch_tdep
/* Whether target has hardware (aka zero-delay) loops. */
bool has_hw_loops;
+
+ /* Detect sigtramp. */
+ bool (*is_sigtramp) (struct frame_info *);
+
+ /* Get address of sigcontext for sigtramp. */
+ CORE_ADDR (*sigcontext_addr) (struct frame_info *);
+
+ /* Offset of registers in `struct sigcontext'. */
+ const int *sc_reg_offset;
+
+ /* Number of registers in sc_reg_offsets. Most likely a ARC_LAST_REGNUM,
+ but in theory it could be less, so it is kept separate. */
+ int sc_num_regs;
};
/* Utility functions used by other ARC-specific modules. */
--
2.29.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 2/2] arc: Add support for signal frames for Linux targets
2020-10-22 16:51 [PATCH 0/2] arc: Add signal handling support Shahab Vahedi
2020-10-22 16:51 ` [PATCH 1/2] arc: Add support for signal handlers Shahab Vahedi
@ 2020-10-22 16:51 ` Shahab Vahedi
2020-11-12 17:51 ` Tom Tromey
2020-11-10 19:12 ` [PING^1][PATCH 0/2] arc: Add signal handling support Shahab Vahedi
` (2 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Shahab Vahedi @ 2020-10-22 16:51 UTC (permalink / raw)
To: gdb-patches
Cc: Shahab Vahedi, Shahab Vahedi, Anton Kolesov, Francois Bedard,
Anton Kolesov
From: Anton Kolesov <Anton.Kolesov@synopsys.com>
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.
---
gdb/arc-linux-tdep.c | 181 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 181 insertions(+)
diff --git a/gdb/arc-linux-tdep.c b/gdb/arc-linux-tdep.c
index 9ff5f1214a1..b8ea2194934 100644
--- 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 @@ static const int arc_linux_core_reg_offsets[] = {
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
@@ -425,6 +600,12 @@ arc_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
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):
--
2.29.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PING^1][PATCH 0/2] arc: Add signal handling support
2020-10-22 16:51 [PATCH 0/2] arc: Add signal handling support Shahab Vahedi
2020-10-22 16:51 ` [PATCH 1/2] arc: Add support for signal handlers Shahab Vahedi
2020-10-22 16:51 ` [PATCH 2/2] arc: Add support for signal frames for Linux targets Shahab Vahedi
@ 2020-11-10 19:12 ` Shahab Vahedi
2020-12-07 16:36 ` [PATCH v2 " Shahab Vahedi
2020-12-22 11:13 ` [PUSHED v2 1/2] arc: Add support for signal handlers Shahab Vahedi
4 siblings, 0 replies; 12+ messages in thread
From: Shahab Vahedi @ 2020-11-10 19:12 UTC (permalink / raw)
To: gdb-patches; +Cc: Shahab Vahedi, Anton Kolesov, Francois Bedard
A gentle reminder for reviewing the "arc: Add signal handling support"
patch [1].
Cheers,
Shahab
[1] [PATCH 0/2] arc: Add signal handling support
https://sourceware.org/pipermail/gdb-patches/2020-October/172751.html
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] arc: Add support for signal handlers
2020-10-22 16:51 ` [PATCH 1/2] arc: Add support for signal handlers Shahab Vahedi
@ 2020-11-12 17:47 ` Tom Tromey
0 siblings, 0 replies; 12+ messages in thread
From: Tom Tromey @ 2020-11-12 17:47 UTC (permalink / raw)
To: Shahab Vahedi via Gdb-patches
Cc: Shahab Vahedi, Shahab Vahedi, Anton Kolesov, Francois Bedard
>>>>> "Shahab" == Shahab Vahedi via Gdb-patches <gdb-patches@sourceware.org> writes:
Shahab> + /* If we have a sigcontext_addr handler, then just use the default frame
Shahab> + sniffer. */
Shahab> + if ((tdep->sigcontext_addr != NULL) && (tdep->is_sigtramp != NULL)
Shahab> + && tdep->is_sigtramp (this_frame))
Shahab> + return default_frame_sniffer (self, this_frame, this_cache);
Shahab> + else
Shahab> + return FALSE;
The 'if' is over-parenthesized; but also obscure because
default_frame_sniffer just returns 1. How about just using
return (tdep->sigcontext_addr != NULL && tdep->is_sigtramp != NULL
&& tdep->is_sigtramp (this_frame));
Tom
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] arc: Add support for signal frames for Linux targets
2020-10-22 16:51 ` [PATCH 2/2] arc: Add support for signal frames for Linux targets Shahab Vahedi
@ 2020-11-12 17:51 ` Tom Tromey
0 siblings, 0 replies; 12+ messages in thread
From: Tom Tromey @ 2020-11-12 17:51 UTC (permalink / raw)
To: Shahab Vahedi via Gdb-patches
Cc: Shahab Vahedi, Shahab Vahedi, Anton Kolesov, Francois Bedard
>>>>> "Shahab" == Shahab Vahedi via Gdb-patches <gdb-patches@sourceware.org> writes:
Shahab> From: Anton Kolesov <Anton.Kolesov@synopsys.com>
Shahab> Implement functions needed to unwind signal frames on ARC Linux targets.
Shahab> gdb/ChangeLog
Shahab> * arc-linux-tdep.c (arc_linux_sc_reg_offsets): New static variable.
Shahab> (arc_linux_is_sigtramp): New function.
Shahab> (arc_linux_sigcontext_addr): Likewise.
Shahab> (arc_linux_init_osabi): Use them.
This looks good to me. Thank you for the patch.
Tom
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 0/2] arc: Add signal handling support
2020-10-22 16:51 [PATCH 0/2] arc: Add signal handling support Shahab Vahedi
` (2 preceding siblings ...)
2020-11-10 19:12 ` [PING^1][PATCH 0/2] arc: Add signal handling support Shahab Vahedi
@ 2020-12-07 16:36 ` Shahab Vahedi
2020-12-07 16:36 ` [PATCH v2 1/2] arc: Add support for signal handlers Shahab Vahedi
` (2 more replies)
2020-12-22 11:13 ` [PUSHED v2 1/2] arc: Add support for signal handlers Shahab Vahedi
4 siblings, 3 replies; 12+ messages in thread
From: Shahab Vahedi @ 2020-12-07 16:36 UTC (permalink / raw)
To: gdb-patches; +Cc: Shahab Vahedi, Shahab Vahedi, Tom Tromey, Francois Bedard
From: Shahab Vahedi <shahab@synopsys.com>
These 2 patches add the infrastructure and necessary hooks to process
the handle signal handlers in ARC targets. The first patch mostly add
the necessary infrastructure/place holders and the second one adds the
hooks for handling an ARC Linux target.
v2:
Because there was only some remarks about the first patch in this
series, that is the one that has been reworked. Look at its commit
message to see what has exactly changed.
Anton Kolesov (2):
arc: Add support for signal handlers
arc: Add support for signal frames for Linux targets
gdb/arc-linux-tdep.c | 181 +++++++++++++++++++++++++++++++++++++++++++
gdb/arc-tdep.c | 123 +++++++++++++++++++++++++++++
gdb/arc-tdep.h | 13 ++++
3 files changed, 317 insertions(+)
--
2.29.2
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 1/2] arc: Add support for signal handlers
2020-12-07 16:36 ` [PATCH v2 " Shahab Vahedi
@ 2020-12-07 16:36 ` Shahab Vahedi
2020-12-07 16:36 ` [PATCH v2 2/2] arc: Add support for signal frames for Linux targets Shahab Vahedi
2020-12-10 19:07 ` [PATCH v2 0/2] arc: Add signal handling support Tom Tromey
2 siblings, 0 replies; 12+ messages in thread
From: Shahab Vahedi @ 2020-12-07 16:36 UTC (permalink / raw)
To: gdb-patches
Cc: Shahab Vahedi, Shahab Vahedi, Tom Tromey, Francois Bedard, Anton Kolesov
From: Anton Kolesov <Anton.Kolesov@synopsys.com>
This patch adds the necessary infrastructure to handle signal frames for
ARC architecture. It is fairly similar to what any other architecture
would have. Linux specific parts will be in a separate patch.
v2 [1]:
- Make the logic of "arc_sigtramp_frame_sniffer ()" simpler.
[1] Tom's remark for the first version
https://sourceware.org/pipermail/gdb-patches/2020-November/173221.html
gdb/ChangeLog:
* arc-tdep.c (arc_make_sigtramp_frame_cache): New function.
(arc_sigtramp_frame_this_id): Likewise.
(arc_sigtramp_frame_prev_register): Likewise.
(arc_sigtramp_frame_sniffer): Likewise.
(arc_siftramp_frame_unwind): New global variable.
(arc_gdbarch_init): Use sigtramp capabilities.
(arc_dump_tdep): Print sigtramp fields.
* arc-tdep.h (gdbarch_tdep): Add sigtramp fields.
---
gdb/arc-tdep.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++
gdb/arc-tdep.h | 13 ++++++
2 files changed, 136 insertions(+)
diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index bcc73590087..2dced431452 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -1843,6 +1843,104 @@ arc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
reg->how = DWARF2_FRAME_REG_CFA;
}
+/* Signal trampoline frame unwinder. Allows frame unwinding to happen
+ from within signal handlers. */
+
+static struct arc_frame_cache *
+arc_make_sigtramp_frame_cache (struct frame_info *this_frame)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_cache\n");
+
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
+
+ /* Allocate new frame cache instance and space for saved register info. */
+ struct arc_frame_cache *cache = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ /* Get the stack pointer and use it as the frame base. */
+ cache->prev_sp = arc_frame_base_address (this_frame, NULL);
+
+ /* If the ARC-private target-dependent info doesn't have a table of
+ offsets of saved register contents within an OS signal context
+ structure, then there is nothing to analyze. */
+ if (tdep->sc_reg_offset == NULL)
+ return cache;
+
+ /* Find the address of the sigcontext structure. */
+ CORE_ADDR addr = tdep->sigcontext_addr (this_frame);
+
+ /* For each register, if its contents have been saved within the
+ sigcontext structure, determine the address of those contents. */
+ gdb_assert (tdep->sc_num_regs <= (ARC_LAST_REGNUM + 1));
+ for (int i = 0; i < tdep->sc_num_regs; i++)
+ {
+ if (tdep->sc_reg_offset[i] != ARC_OFFSET_NO_REGISTER)
+ cache->saved_regs[i].addr = addr + tdep->sc_reg_offset[i];
+ }
+
+ return cache;
+}
+
+/* Implement the "this_id" frame_unwind method for signal trampoline
+ frames. */
+
+static void
+arc_sigtramp_frame_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_this_id\n");
+
+ if (*this_cache == NULL)
+ *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+ CORE_ADDR stack_addr = cache->prev_sp;
+ CORE_ADDR code_addr
+ = get_frame_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch));
+ *this_id = frame_id_build (stack_addr, code_addr);
+}
+
+/* Get a register from a signal handler frame. */
+
+static struct value *
+arc_sigtramp_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_prev_register (regnum = %d)\n", regnum);
+
+ /* Make sure we've initialized the cache. */
+ if (*this_cache == NULL)
+ *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+ struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+/* Frame sniffer for signal handler frame. Only recognize a frame if we
+ have a sigcontext_addr handler in the target dependency. */
+
+static int
+arc_sigtramp_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct gdbarch_tdep *tdep;
+
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_sniffer\n");
+
+ tdep = gdbarch_tdep (get_frame_arch (this_frame));
+
+ /* If we have a sigcontext_addr handler, then just return 1 (same as the
+ "default_frame_sniffer ()"). */
+ return (tdep->sigcontext_addr != NULL && tdep->is_sigtramp != NULL
+ && tdep->is_sigtramp (this_frame));
+}
+
/* Structure defining the ARC ordinary frame unwind functions. Since we are
the fallback unwinder, we use the default frame sniffer, which always
accepts the frame. */
@@ -1858,6 +1956,21 @@ static const struct frame_unwind arc_frame_unwind = {
NULL
};
+/* Structure defining the ARC signal frame unwind functions. Custom
+ sniffer is used, because this frame must be accepted only in the right
+ context. */
+
+static const struct frame_unwind arc_sigtramp_frame_unwind = {
+ SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
+ arc_sigtramp_frame_this_id,
+ arc_sigtramp_frame_prev_register,
+ NULL,
+ arc_sigtramp_frame_sniffer,
+ NULL,
+ NULL
+};
+
static const struct frame_base arc_normal_base = {
&arc_frame_unwind,
@@ -2271,6 +2384,7 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Frame unwinders and sniffers. */
dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg);
dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &arc_sigtramp_frame_unwind);
frame_unwind_append_unwinder (gdbarch, &arc_frame_unwind);
frame_base_set_default (gdbarch, &arc_normal_base);
@@ -2349,6 +2463,15 @@ arc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
fprintf_unfiltered (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc);
+
+ fprintf_unfiltered (file, "arc_dump_tdep: is_sigtramp = <%s>\n",
+ host_address_to_string (tdep->is_sigtramp));
+ fprintf_unfiltered (file, "arc_dump_tdep: sigcontext_addr = <%s>\n",
+ host_address_to_string (tdep->sigcontext_addr));
+ fprintf_unfiltered (file, "arc_dump_tdep: sc_reg_offset = <%s>\n",
+ host_address_to_string (tdep->sc_reg_offset));
+ fprintf_unfiltered (file, "arc_dump_tdep: sc_num_regs = %d\n",
+ tdep->sc_num_regs);
}
/* This command accepts single argument - address of instruction to
diff --git a/gdb/arc-tdep.h b/gdb/arc-tdep.h
index 09fcbeab9c7..5ee5cf85c6c 100644
--- a/gdb/arc-tdep.h
+++ b/gdb/arc-tdep.h
@@ -124,6 +124,19 @@ struct gdbarch_tdep
/* Whether target has hardware (aka zero-delay) loops. */
bool has_hw_loops;
+
+ /* Detect sigtramp. */
+ bool (*is_sigtramp) (struct frame_info *);
+
+ /* Get address of sigcontext for sigtramp. */
+ CORE_ADDR (*sigcontext_addr) (struct frame_info *);
+
+ /* Offset of registers in `struct sigcontext'. */
+ const int *sc_reg_offset;
+
+ /* Number of registers in sc_reg_offsets. Most likely a ARC_LAST_REGNUM,
+ but in theory it could be less, so it is kept separate. */
+ int sc_num_regs;
};
/* Utility functions used by other ARC-specific modules. */
--
2.29.2
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 2/2] arc: Add support for signal frames for Linux targets
2020-12-07 16:36 ` [PATCH v2 " Shahab Vahedi
2020-12-07 16:36 ` [PATCH v2 1/2] arc: Add support for signal handlers Shahab Vahedi
@ 2020-12-07 16:36 ` Shahab Vahedi
2020-12-10 19:07 ` [PATCH v2 0/2] arc: Add signal handling support Tom Tromey
2 siblings, 0 replies; 12+ messages in thread
From: Shahab Vahedi @ 2020-12-07 16:36 UTC (permalink / raw)
To: gdb-patches
Cc: Shahab Vahedi, Shahab Vahedi, Tom Tromey, Francois Bedard, Anton Kolesov
From: Anton Kolesov <Anton.Kolesov@synopsys.com>
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.
---
gdb/arc-linux-tdep.c | 181 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 181 insertions(+)
diff --git a/gdb/arc-linux-tdep.c b/gdb/arc-linux-tdep.c
index 6e74bae8056..ad68f494b3c 100644
--- 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 @@ static const int arc_linux_core_reg_offsets[] = {
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
@@ -429,6 +604,12 @@ arc_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
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):
--
2.29.2
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 0/2] arc: Add signal handling support
2020-12-07 16:36 ` [PATCH v2 " Shahab Vahedi
2020-12-07 16:36 ` [PATCH v2 1/2] arc: Add support for signal handlers Shahab Vahedi
2020-12-07 16:36 ` [PATCH v2 2/2] arc: Add support for signal frames for Linux targets Shahab Vahedi
@ 2020-12-10 19:07 ` Tom Tromey
2 siblings, 0 replies; 12+ messages in thread
From: Tom Tromey @ 2020-12-10 19:07 UTC (permalink / raw)
To: Shahab Vahedi via Gdb-patches
Cc: Shahab Vahedi, Shahab Vahedi, Tom Tromey, Francois Bedard
Shahab> From: Shahab Vahedi <shahab@synopsys.com>
Shahab> These 2 patches add the infrastructure and necessary hooks to process
Shahab> the handle signal handlers in ARC targets. The first patch mostly add
Shahab> the necessary infrastructure/place holders and the second one adds the
Shahab> hooks for handling an ARC Linux target.
Shahab> v2:
Shahab> Because there was only some remarks about the first patch in this
Shahab> series, that is the one that has been reworked. Look at its commit
Shahab> message to see what has exactly changed.
I read through these and they both look ok to me.
Thank you.
Tom
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PUSHED v2 1/2] arc: Add support for signal handlers
2020-10-22 16:51 [PATCH 0/2] arc: Add signal handling support Shahab Vahedi
` (3 preceding siblings ...)
2020-12-07 16:36 ` [PATCH v2 " Shahab Vahedi
@ 2020-12-22 11:13 ` Shahab Vahedi
2020-12-22 11:13 ` [PUSHED v2 2/2] arc: Add support for signal frames for Linux targets Shahab Vahedi
4 siblings, 1 reply; 12+ messages in thread
From: Shahab Vahedi @ 2020-12-22 11:13 UTC (permalink / raw)
To: gdb-patches
Cc: Shahab Vahedi, Shahab Vahedi, Tom Tromey, Francois Bedard, Anton Kolesov
From: Anton Kolesov <Anton.Kolesov@synopsys.com>
This patch adds the necessary infrastructure to handle signal frames for
ARC architecture. It is fairly similar to what any other architecture
would have. Linux specific parts will be in a separate patch.
v2 [1]:
- Make the logic of "arc_sigtramp_frame_sniffer ()" simpler.
[1] Tom's remark for the first version
https://sourceware.org/pipermail/gdb-patches/2020-November/173221.html
gdb/ChangeLog:
* arc-tdep.c (arc_make_sigtramp_frame_cache): New function.
(arc_sigtramp_frame_this_id): Likewise.
(arc_sigtramp_frame_prev_register): Likewise.
(arc_sigtramp_frame_sniffer): Likewise.
(arc_siftramp_frame_unwind): New global variable.
(arc_gdbarch_init): Use sigtramp capabilities.
(arc_dump_tdep): Print sigtramp fields.
* arc-tdep.h (gdbarch_tdep): Add sigtramp fields.
---
gdb/arc-tdep.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++
gdb/arc-tdep.h | 13 ++++++
2 files changed, 136 insertions(+)
diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index bcc73590087..2dced431452 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -1843,6 +1843,104 @@ arc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
reg->how = DWARF2_FRAME_REG_CFA;
}
+/* Signal trampoline frame unwinder. Allows frame unwinding to happen
+ from within signal handlers. */
+
+static struct arc_frame_cache *
+arc_make_sigtramp_frame_cache (struct frame_info *this_frame)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_cache\n");
+
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
+
+ /* Allocate new frame cache instance and space for saved register info. */
+ struct arc_frame_cache *cache = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ /* Get the stack pointer and use it as the frame base. */
+ cache->prev_sp = arc_frame_base_address (this_frame, NULL);
+
+ /* If the ARC-private target-dependent info doesn't have a table of
+ offsets of saved register contents within an OS signal context
+ structure, then there is nothing to analyze. */
+ if (tdep->sc_reg_offset == NULL)
+ return cache;
+
+ /* Find the address of the sigcontext structure. */
+ CORE_ADDR addr = tdep->sigcontext_addr (this_frame);
+
+ /* For each register, if its contents have been saved within the
+ sigcontext structure, determine the address of those contents. */
+ gdb_assert (tdep->sc_num_regs <= (ARC_LAST_REGNUM + 1));
+ for (int i = 0; i < tdep->sc_num_regs; i++)
+ {
+ if (tdep->sc_reg_offset[i] != ARC_OFFSET_NO_REGISTER)
+ cache->saved_regs[i].addr = addr + tdep->sc_reg_offset[i];
+ }
+
+ return cache;
+}
+
+/* Implement the "this_id" frame_unwind method for signal trampoline
+ frames. */
+
+static void
+arc_sigtramp_frame_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_this_id\n");
+
+ if (*this_cache == NULL)
+ *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+ CORE_ADDR stack_addr = cache->prev_sp;
+ CORE_ADDR code_addr
+ = get_frame_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch));
+ *this_id = frame_id_build (stack_addr, code_addr);
+}
+
+/* Get a register from a signal handler frame. */
+
+static struct value *
+arc_sigtramp_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_prev_register (regnum = %d)\n", regnum);
+
+ /* Make sure we've initialized the cache. */
+ if (*this_cache == NULL)
+ *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+ struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+/* Frame sniffer for signal handler frame. Only recognize a frame if we
+ have a sigcontext_addr handler in the target dependency. */
+
+static int
+arc_sigtramp_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct gdbarch_tdep *tdep;
+
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_sniffer\n");
+
+ tdep = gdbarch_tdep (get_frame_arch (this_frame));
+
+ /* If we have a sigcontext_addr handler, then just return 1 (same as the
+ "default_frame_sniffer ()"). */
+ return (tdep->sigcontext_addr != NULL && tdep->is_sigtramp != NULL
+ && tdep->is_sigtramp (this_frame));
+}
+
/* Structure defining the ARC ordinary frame unwind functions. Since we are
the fallback unwinder, we use the default frame sniffer, which always
accepts the frame. */
@@ -1858,6 +1956,21 @@ static const struct frame_unwind arc_frame_unwind = {
NULL
};
+/* Structure defining the ARC signal frame unwind functions. Custom
+ sniffer is used, because this frame must be accepted only in the right
+ context. */
+
+static const struct frame_unwind arc_sigtramp_frame_unwind = {
+ SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
+ arc_sigtramp_frame_this_id,
+ arc_sigtramp_frame_prev_register,
+ NULL,
+ arc_sigtramp_frame_sniffer,
+ NULL,
+ NULL
+};
+
static const struct frame_base arc_normal_base = {
&arc_frame_unwind,
@@ -2271,6 +2384,7 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Frame unwinders and sniffers. */
dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg);
dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &arc_sigtramp_frame_unwind);
frame_unwind_append_unwinder (gdbarch, &arc_frame_unwind);
frame_base_set_default (gdbarch, &arc_normal_base);
@@ -2349,6 +2463,15 @@ arc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
fprintf_unfiltered (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc);
+
+ fprintf_unfiltered (file, "arc_dump_tdep: is_sigtramp = <%s>\n",
+ host_address_to_string (tdep->is_sigtramp));
+ fprintf_unfiltered (file, "arc_dump_tdep: sigcontext_addr = <%s>\n",
+ host_address_to_string (tdep->sigcontext_addr));
+ fprintf_unfiltered (file, "arc_dump_tdep: sc_reg_offset = <%s>\n",
+ host_address_to_string (tdep->sc_reg_offset));
+ fprintf_unfiltered (file, "arc_dump_tdep: sc_num_regs = %d\n",
+ tdep->sc_num_regs);
}
/* This command accepts single argument - address of instruction to
diff --git a/gdb/arc-tdep.h b/gdb/arc-tdep.h
index 09fcbeab9c7..5ee5cf85c6c 100644
--- a/gdb/arc-tdep.h
+++ b/gdb/arc-tdep.h
@@ -124,6 +124,19 @@ struct gdbarch_tdep
/* Whether target has hardware (aka zero-delay) loops. */
bool has_hw_loops;
+
+ /* Detect sigtramp. */
+ bool (*is_sigtramp) (struct frame_info *);
+
+ /* Get address of sigcontext for sigtramp. */
+ CORE_ADDR (*sigcontext_addr) (struct frame_info *);
+
+ /* Offset of registers in `struct sigcontext'. */
+ const int *sc_reg_offset;
+
+ /* Number of registers in sc_reg_offsets. Most likely a ARC_LAST_REGNUM,
+ but in theory it could be less, so it is kept separate. */
+ int sc_num_regs;
};
/* Utility functions used by other ARC-specific modules. */
--
2.29.2
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PUSHED v2 2/2] arc: Add support for signal frames for Linux targets
2020-12-22 11:13 ` [PUSHED v2 1/2] arc: Add support for signal handlers Shahab Vahedi
@ 2020-12-22 11:13 ` Shahab Vahedi
0 siblings, 0 replies; 12+ messages in thread
From: Shahab Vahedi @ 2020-12-22 11:13 UTC (permalink / raw)
To: gdb-patches
Cc: Shahab Vahedi, Shahab Vahedi, Tom Tromey, Francois Bedard, Anton Kolesov
From: Anton Kolesov <Anton.Kolesov@synopsys.com>
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.
---
gdb/arc-linux-tdep.c | 181 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 181 insertions(+)
diff --git a/gdb/arc-linux-tdep.c b/gdb/arc-linux-tdep.c
index 6e74bae8056..ad68f494b3c 100644
--- 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 @@ static const int arc_linux_core_reg_offsets[] = {
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
@@ -429,6 +604,12 @@ arc_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
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):
--
2.29.2
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2020-12-22 11:13 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-22 16:51 [PATCH 0/2] arc: Add signal handling support Shahab Vahedi
2020-10-22 16:51 ` [PATCH 1/2] arc: Add support for signal handlers Shahab Vahedi
2020-11-12 17:47 ` Tom Tromey
2020-10-22 16:51 ` [PATCH 2/2] arc: Add support for signal frames for Linux targets Shahab Vahedi
2020-11-12 17:51 ` Tom Tromey
2020-11-10 19:12 ` [PING^1][PATCH 0/2] arc: Add signal handling support Shahab Vahedi
2020-12-07 16:36 ` [PATCH v2 " Shahab Vahedi
2020-12-07 16:36 ` [PATCH v2 1/2] arc: Add support for signal handlers Shahab Vahedi
2020-12-07 16:36 ` [PATCH v2 2/2] arc: Add support for signal frames for Linux targets Shahab Vahedi
2020-12-10 19:07 ` [PATCH v2 0/2] arc: Add signal handling support Tom Tromey
2020-12-22 11:13 ` [PUSHED v2 1/2] arc: Add support for signal handlers Shahab Vahedi
2020-12-22 11:13 ` [PUSHED v2 2/2] arc: Add support for signal frames for Linux targets Shahab Vahedi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).