Andrew Geissler | 0903674 | 2021-06-25 14:25:14 -0500 | [diff] [blame^] | 1 | From bfee93403b46ae4f050282b7721ba39073905c69 Mon Sep 17 00:00:00 2001 |
| 2 | From: Anton Kolesov <Anton.Kolesov@synopsys.com> |
| 3 | Date: Mon, 22 Aug 2016 19:39:46 +0300 |
| 4 | Subject: [PATCH 1/4] arc: Add support for signal handlers |
| 5 | |
| 6 | This patch adds the necessary infrastructure to handle signal frames for |
| 7 | ARC architecture. It is fairly similar to what any other architecture |
| 8 | would have. Linux specific parts will be in a separate patch. |
| 9 | |
| 10 | v2 [1]: |
| 11 | - Make the logic of "arc_sigtramp_frame_sniffer ()" simpler. |
| 12 | |
| 13 | [1] Tom's remark for the first version |
| 14 | https://sourceware.org/pipermail/gdb-patches/2020-November/173221.html |
| 15 | |
| 16 | gdb/ChangeLog: |
| 17 | |
| 18 | * arc-tdep.c (arc_make_sigtramp_frame_cache): New function. |
| 19 | (arc_sigtramp_frame_this_id): Likewise. |
| 20 | (arc_sigtramp_frame_prev_register): Likewise. |
| 21 | (arc_sigtramp_frame_sniffer): Likewise. |
| 22 | (arc_siftramp_frame_unwind): New global variable. |
| 23 | (arc_gdbarch_init): Use sigtramp capabilities. |
| 24 | (arc_dump_tdep): Print sigtramp fields. |
| 25 | * arc-tdep.h (gdbarch_tdep): Add sigtramp fields. |
| 26 | |
| 27 | Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=b4e3cd0440109d0a5552d3313ccbd35c8103335b] |
| 28 | |
| 29 | Signed-off-by: Anton Kolesov <Anton.Kolesov@synopsys.com> |
| 30 | Signed-off-by: Shahab Vahedi <shahab@synopsys.com> |
| 31 | Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com> |
| 32 | --- |
| 33 | gdb/arc-tdep.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| 34 | gdb/arc-tdep.h | 13 ++++++ |
| 35 | 2 files changed, 136 insertions(+) |
| 36 | |
| 37 | diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c |
| 38 | index 93e2fd88a9a..3356252525d 100644 |
| 39 | --- a/gdb/arc-tdep.c |
| 40 | +++ b/gdb/arc-tdep.c |
| 41 | @@ -1843,6 +1843,104 @@ arc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, |
| 42 | reg->how = DWARF2_FRAME_REG_CFA; |
| 43 | } |
| 44 | |
| 45 | +/* Signal trampoline frame unwinder. Allows frame unwinding to happen |
| 46 | + from within signal handlers. */ |
| 47 | + |
| 48 | +static struct arc_frame_cache * |
| 49 | +arc_make_sigtramp_frame_cache (struct frame_info *this_frame) |
| 50 | +{ |
| 51 | + if (arc_debug) |
| 52 | + debug_printf ("arc: sigtramp_frame_cache\n"); |
| 53 | + |
| 54 | + struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame)); |
| 55 | + |
| 56 | + /* Allocate new frame cache instance and space for saved register info. */ |
| 57 | + struct arc_frame_cache *cache = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache); |
| 58 | + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); |
| 59 | + |
| 60 | + /* Get the stack pointer and use it as the frame base. */ |
| 61 | + cache->prev_sp = arc_frame_base_address (this_frame, NULL); |
| 62 | + |
| 63 | + /* If the ARC-private target-dependent info doesn't have a table of |
| 64 | + offsets of saved register contents within an OS signal context |
| 65 | + structure, then there is nothing to analyze. */ |
| 66 | + if (tdep->sc_reg_offset == NULL) |
| 67 | + return cache; |
| 68 | + |
| 69 | + /* Find the address of the sigcontext structure. */ |
| 70 | + CORE_ADDR addr = tdep->sigcontext_addr (this_frame); |
| 71 | + |
| 72 | + /* For each register, if its contents have been saved within the |
| 73 | + sigcontext structure, determine the address of those contents. */ |
| 74 | + gdb_assert (tdep->sc_num_regs <= (ARC_LAST_REGNUM + 1)); |
| 75 | + for (int i = 0; i < tdep->sc_num_regs; i++) |
| 76 | + { |
| 77 | + if (tdep->sc_reg_offset[i] != ARC_OFFSET_NO_REGISTER) |
| 78 | + cache->saved_regs[i].addr = addr + tdep->sc_reg_offset[i]; |
| 79 | + } |
| 80 | + |
| 81 | + return cache; |
| 82 | +} |
| 83 | + |
| 84 | +/* Implement the "this_id" frame_unwind method for signal trampoline |
| 85 | + frames. */ |
| 86 | + |
| 87 | +static void |
| 88 | +arc_sigtramp_frame_this_id (struct frame_info *this_frame, |
| 89 | + void **this_cache, struct frame_id *this_id) |
| 90 | +{ |
| 91 | + if (arc_debug) |
| 92 | + debug_printf ("arc: sigtramp_frame_this_id\n"); |
| 93 | + |
| 94 | + if (*this_cache == NULL) |
| 95 | + *this_cache = arc_make_sigtramp_frame_cache (this_frame); |
| 96 | + |
| 97 | + struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| 98 | + struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache; |
| 99 | + CORE_ADDR stack_addr = cache->prev_sp; |
| 100 | + CORE_ADDR code_addr |
| 101 | + = get_frame_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch)); |
| 102 | + *this_id = frame_id_build (stack_addr, code_addr); |
| 103 | +} |
| 104 | + |
| 105 | +/* Get a register from a signal handler frame. */ |
| 106 | + |
| 107 | +static struct value * |
| 108 | +arc_sigtramp_frame_prev_register (struct frame_info *this_frame, |
| 109 | + void **this_cache, int regnum) |
| 110 | +{ |
| 111 | + if (arc_debug) |
| 112 | + debug_printf ("arc: sigtramp_frame_prev_register (regnum = %d)\n", regnum); |
| 113 | + |
| 114 | + /* Make sure we've initialized the cache. */ |
| 115 | + if (*this_cache == NULL) |
| 116 | + *this_cache = arc_make_sigtramp_frame_cache (this_frame); |
| 117 | + |
| 118 | + struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache; |
| 119 | + return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum); |
| 120 | +} |
| 121 | + |
| 122 | +/* Frame sniffer for signal handler frame. Only recognize a frame if we |
| 123 | + have a sigcontext_addr handler in the target dependency. */ |
| 124 | + |
| 125 | +static int |
| 126 | +arc_sigtramp_frame_sniffer (const struct frame_unwind *self, |
| 127 | + struct frame_info *this_frame, |
| 128 | + void **this_cache) |
| 129 | +{ |
| 130 | + struct gdbarch_tdep *tdep; |
| 131 | + |
| 132 | + if (arc_debug) |
| 133 | + debug_printf ("arc: sigtramp_frame_sniffer\n"); |
| 134 | + |
| 135 | + tdep = gdbarch_tdep (get_frame_arch (this_frame)); |
| 136 | + |
| 137 | + /* If we have a sigcontext_addr handler, then just return 1 (same as the |
| 138 | + "default_frame_sniffer ()"). */ |
| 139 | + return (tdep->sigcontext_addr != NULL && tdep->is_sigtramp != NULL |
| 140 | + && tdep->is_sigtramp (this_frame)); |
| 141 | +} |
| 142 | + |
| 143 | /* Structure defining the ARC ordinary frame unwind functions. Since we are |
| 144 | the fallback unwinder, we use the default frame sniffer, which always |
| 145 | accepts the frame. */ |
| 146 | @@ -1858,6 +1956,21 @@ static const struct frame_unwind arc_frame_unwind = { |
| 147 | NULL |
| 148 | }; |
| 149 | |
| 150 | +/* Structure defining the ARC signal frame unwind functions. Custom |
| 151 | + sniffer is used, because this frame must be accepted only in the right |
| 152 | + context. */ |
| 153 | + |
| 154 | +static const struct frame_unwind arc_sigtramp_frame_unwind = { |
| 155 | + SIGTRAMP_FRAME, |
| 156 | + default_frame_unwind_stop_reason, |
| 157 | + arc_sigtramp_frame_this_id, |
| 158 | + arc_sigtramp_frame_prev_register, |
| 159 | + NULL, |
| 160 | + arc_sigtramp_frame_sniffer, |
| 161 | + NULL, |
| 162 | + NULL |
| 163 | +}; |
| 164 | + |
| 165 | |
| 166 | static const struct frame_base arc_normal_base = { |
| 167 | &arc_frame_unwind, |
| 168 | @@ -2272,6 +2385,7 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) |
| 169 | /* Frame unwinders and sniffers. */ |
| 170 | dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg); |
| 171 | dwarf2_append_unwinders (gdbarch); |
| 172 | + frame_unwind_append_unwinder (gdbarch, &arc_sigtramp_frame_unwind); |
| 173 | frame_unwind_append_unwinder (gdbarch, &arc_frame_unwind); |
| 174 | frame_base_set_default (gdbarch, &arc_normal_base); |
| 175 | |
| 176 | @@ -2350,6 +2464,15 @@ arc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file) |
| 177 | struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); |
| 178 | |
| 179 | fprintf_unfiltered (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc); |
| 180 | + |
| 181 | + fprintf_unfiltered (file, "arc_dump_tdep: is_sigtramp = <%s>\n", |
| 182 | + host_address_to_string (tdep->is_sigtramp)); |
| 183 | + fprintf_unfiltered (file, "arc_dump_tdep: sigcontext_addr = <%s>\n", |
| 184 | + host_address_to_string (tdep->sigcontext_addr)); |
| 185 | + fprintf_unfiltered (file, "arc_dump_tdep: sc_reg_offset = <%s>\n", |
| 186 | + host_address_to_string (tdep->sc_reg_offset)); |
| 187 | + fprintf_unfiltered (file, "arc_dump_tdep: sc_num_regs = %d\n", |
| 188 | + tdep->sc_num_regs); |
| 189 | } |
| 190 | |
| 191 | /* This command accepts single argument - address of instruction to |
| 192 | diff --git a/gdb/arc-tdep.h b/gdb/arc-tdep.h |
| 193 | index 50b14905134..70fc3d95c48 100644 |
| 194 | --- a/gdb/arc-tdep.h |
| 195 | +++ b/gdb/arc-tdep.h |
| 196 | @@ -124,6 +124,19 @@ struct gdbarch_tdep |
| 197 | |
| 198 | /* Whether target has hardware (aka zero-delay) loops. */ |
| 199 | bool has_hw_loops; |
| 200 | + |
| 201 | + /* Detect sigtramp. */ |
| 202 | + bool (*is_sigtramp) (struct frame_info *); |
| 203 | + |
| 204 | + /* Get address of sigcontext for sigtramp. */ |
| 205 | + CORE_ADDR (*sigcontext_addr) (struct frame_info *); |
| 206 | + |
| 207 | + /* Offset of registers in `struct sigcontext'. */ |
| 208 | + const int *sc_reg_offset; |
| 209 | + |
| 210 | + /* Number of registers in sc_reg_offsets. Most likely a ARC_LAST_REGNUM, |
| 211 | + but in theory it could be less, so it is kept separate. */ |
| 212 | + int sc_num_regs; |
| 213 | }; |
| 214 | |
| 215 | /* Utility functions used by other ARC-specific modules. */ |
| 216 | -- |
| 217 | 2.16.2 |
| 218 | |