arc: Add support for signal handlers
authorAnton Kolesov <Anton.Kolesov@synopsys.com>
Mon, 22 Aug 2016 16:39:46 +0000 (19:39 +0300)
committerShahab Vahedi <shahab@synopsys.com>
Tue, 22 Dec 2020 11:04:31 +0000 (12:04 +0100)
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/ChangeLog
gdb/arc-tdep.c
gdb/arc-tdep.h

index 142278a34990e8dcac885962cd73a874a913e085..ba574d7fd8b1d1ffd99749cca804cc71c65fd353 100644 (file)
@@ -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.
+
 2020-12-21  Tom Tromey  <tom@tromey.com>
 
        * expression.h (enum noside): Move earlier.
index d18d3bcdf2d02c4f59f452305ed86f1733bbda78..846cc80541641ec73a6aa2ea8b5e0572e2c60ba0 100644 (file)
@@ -1844,6 +1844,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.  */
@@ -1859,6 +1957,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,
@@ -2272,6 +2385,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);
 
@@ -2350,6 +2464,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
index 09fcbeab9c785ceb2a3232f3d7ceba5413c63232..5ee5cf85c6cd1c74d3a1cc27c86ee06fececbfd6 100644 (file)
@@ -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.  */