summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/gdb/gdb/0012-arc-Add-support-for-signal-handlers.patch
blob: 6a98b65766f76aa4abd59c18aeb0b4a4afea3394 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
From bfee93403b46ae4f050282b7721ba39073905c69 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 1/4] 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.

Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=b4e3cd0440109d0a5552d3313ccbd35c8103335b]

Signed-off-by: Anton Kolesov <Anton.Kolesov@synopsys.com>
Signed-off-by: Shahab Vahedi <shahab@synopsys.com>
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
---
 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 93e2fd88a9a..3356252525d 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,
@@ -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
diff --git a/gdb/arc-tdep.h b/gdb/arc-tdep.h
index 50b14905134..70fc3d95c48 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.16.2