mirror of
https://github.com/crosstool-ng/crosstool-ng.git
synced 2024-12-23 06:32:23 +00:00
227 lines
7.7 KiB
Diff
227 lines
7.7 KiB
Diff
|
From 977e6e7dc30737b2a8be382e604d2b998d446749 Mon Sep 17 00:00:00 2001
|
||
|
From: Anton Kolesov <Anton.Kolesov@synopsys.com>
|
||
|
Date: Mon, 22 Aug 2016 19:39:46 +0300
|
||
|
Subject: [PATCH 06/20] arc: Add support for signal handlers
|
||
|
|
||
|
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.
|
||
|
|
||
|
Will be a part of GDB 11:
|
||
|
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=b4e3cd0440109d0a5552d3313ccbd35c8103335b
|
||
|
---
|
||
|
gdb/ChangeLog | 11 +++++
|
||
|
gdb/arc-tdep.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
gdb/arc-tdep.h | 13 ++++++
|
||
|
3 files changed, 147 insertions(+)
|
||
|
|
||
|
--- a/gdb/ChangeLog
|
||
|
+++ b/gdb/ChangeLog
|
||
|
@@ -1,3 +1,14 @@
|
||
|
+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.
|
||
|
+ (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.
|
||
|
+
|
||
|
2021-04-25 Joel Brobecker <brobecker@adacore.com>
|
||
|
|
||
|
* version.in: Set GDB version number to 10.2.
|
||
|
--- a/gdb/arc-tdep.c
|
||
|
+++ b/gdb/arc-tdep.c
|
||
|
@@ -1843,6 +1843,104 @@
|
||
|
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 @@
|
||
|
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,
|
||
|
@@ -2272,6 +2385,7 @@
|
||
|
/* 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);
|
||
|
|
||
|
@@ -2350,6 +2464,15 @@
|
||
|
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
|
||
|
--- a/gdb/arc-tdep.h
|
||
|
+++ b/gdb/arc-tdep.h
|
||
|
@@ -124,6 +124,19 @@
|
||
|
|
||
|
/* 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. */
|