GDBserver
linux-xtensa-low.c
Go to the documentation of this file.
1 /* GNU/Linux/Xtensa specific low level interface, for the remote server for GDB.
2  Copyright (C) 2007-2018 Free Software Foundation, Inc.
3 
4  This file is part of GDB.
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 
19 
20 #include "server.h"
21 #include "linux-low.h"
22 
23 /* Defined in auto-generated file reg-xtensa.c. */
24 void init_registers_xtensa (void);
25 extern const struct target_desc *tdesc_xtensa;
26 
27 #include <asm/ptrace.h>
28 #include <xtensa-config.h>
29 #include "arch/xtensa.h"
30 #include "gdb_proc_service.h"
31 
32 #include "xtensa-xtregs.c"
33 
34 enum regnum {
35  R_PC=0, R_PS,
40  R_A0 = 64
41 };
42 
43 static void
45 {
46  elf_greg_t* rset = (elf_greg_t*)buf;
47  const struct target_desc *tdesc = regcache->tdesc;
48  int ar0_regnum;
49  char *ptr;
50  int i;
51 
52  /* Take care of AR registers. */
53 
54  ar0_regnum = find_regno (tdesc, "ar0");
55  ptr = (char*)&rset[R_A0];
56 
57  for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
58  {
59  collect_register (regcache, i, ptr);
60  ptr += register_size (tdesc, i);
61  }
62 
63  if (XSHAL_ABI == XTHAL_ABI_CALL0)
64  {
65  int a0_regnum = find_regno (tdesc, "a0");
66  ptr = (char *) &rset[R_A0 + 4 * rset[R_WB]];
67 
68  for (i = a0_regnum; i < a0_regnum + C0_NREGS; i++)
69  {
70  if ((4 * rset[R_WB] + i - a0_regnum) == XCHAL_NUM_AREGS)
71  ptr = (char *) &rset[R_A0];
72  collect_register (regcache, i, ptr);
73  ptr += register_size (tdesc, i);
74  }
75  }
76 
77  /* Loop registers, if hardware has it. */
78 
79 #if XCHAL_HAVE_LOOPS
80  collect_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]);
81  collect_register_by_name (regcache, "lend", (char*)&rset[R_LEND]);
82  collect_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]);
83 #endif
84 
85  collect_register_by_name (regcache, "sar", (char*)&rset[R_SAR]);
86  collect_register_by_name (regcache, "pc", (char*)&rset[R_PC]);
87  collect_register_by_name (regcache, "ps", (char*)&rset[R_PS]);
88  collect_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]);
89  collect_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]);
90 
91 #if XCHAL_HAVE_THREADPTR
92  collect_register_by_name (regcache, "threadptr",
93  (char *) &rset[R_THREADPTR]);
94 #endif
95 }
96 
97 static void
98 xtensa_store_gregset (struct regcache *regcache, const void *buf)
99 {
100  const elf_greg_t* rset = (const elf_greg_t*)buf;
101  const struct target_desc *tdesc = regcache->tdesc;
102  int ar0_regnum;
103  char *ptr;
104  int i;
105 
106  /* Take care of AR registers. */
107 
108  ar0_regnum = find_regno (tdesc, "ar0");
109  ptr = (char *)&rset[R_A0];
110 
111  for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
112  {
113  supply_register (regcache, i, ptr);
114  ptr += register_size (tdesc, i);
115  }
116 
117  if (XSHAL_ABI == XTHAL_ABI_CALL0)
118  {
119  int a0_regnum = find_regno (tdesc, "a0");
120  ptr = (char *) &rset[R_A0 + (4 * rset[R_WB]) % XCHAL_NUM_AREGS];
121 
122  for (i = a0_regnum; i < a0_regnum + C0_NREGS; i++)
123  {
124  if ((4 * rset[R_WB] + i - a0_regnum) == XCHAL_NUM_AREGS)
125  ptr = (char *) &rset[R_A0];
126  supply_register (regcache, i, ptr);
127  ptr += register_size (tdesc, i);
128  }
129  }
130 
131  /* Loop registers, if hardware has it. */
132 
133 #if XCHAL_HAVE_LOOPS
134  supply_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]);
135  supply_register_by_name (regcache, "lend", (char*)&rset[R_LEND]);
136  supply_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]);
137 #endif
138 
139  supply_register_by_name (regcache, "sar", (char*)&rset[R_SAR]);
140  supply_register_by_name (regcache, "pc", (char*)&rset[R_PC]);
141  supply_register_by_name (regcache, "ps", (char*)&rset[R_PS]);
142  supply_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]);
143  supply_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]);
144 
145 #if XCHAL_HAVE_THREADPTR
146  supply_register_by_name (regcache, "threadptr",
147  (char *) &rset[R_THREADPTR]);
148 #endif
149 }
150 
151 /* Xtensa GNU/Linux PTRACE interface includes extended register set. */
152 
153 static void
155 {
156  const xtensa_regtable_t *ptr;
157 
158  for (ptr = xtensa_regmap_table; ptr->name; ptr++)
159  {
161  (char*)buf + ptr->ptrace_offset);
162  }
163 }
164 
165 static void
166 xtensa_store_xtregset (struct regcache *regcache, const void *buf)
167 {
168  const xtensa_regtable_t *ptr;
169 
170  for (ptr = xtensa_regmap_table; ptr->name; ptr++)
171  {
173  (char*)buf + ptr->ptrace_offset);
174  }
175 }
176 
177 static struct regset_info xtensa_regsets[] = {
178  { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
179  GENERAL_REGS,
181  { PTRACE_GETXTREGS, PTRACE_SETXTREGS, 0, XTENSA_ELF_XTREG_SIZE,
182  EXTENDED_REGS,
184  NULL_REGSET
185 };
186 
187 #if XCHAL_HAVE_BE
188 #define XTENSA_BREAKPOINT {0xd2,0x0f}
189 #else
190 #define XTENSA_BREAKPOINT {0x2d,0xf0}
191 #endif
192 
194 #define xtensa_breakpoint_len 2
195 
196 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
197 
198 static const gdb_byte *
199 xtensa_sw_breakpoint_from_kind (int kind, int *size)
200 {
201  *size = xtensa_breakpoint_len;
202  return xtensa_breakpoint;
203 }
204 
205 static int
207 {
208  unsigned long insn;
209 
210  (*the_target->read_memory) (where, (unsigned char *) &insn,
212  return memcmp((char *) &insn,
214 }
215 
216 /* Called by libthread_db. */
217 
218 ps_err_e
220  lwpid_t lwpid, int idx, void **base)
221 {
222  xtensa_elf_gregset_t regs;
223 
224  if (ptrace (PTRACE_GETREGS, lwpid, NULL, &regs) != 0)
225  return PS_ERR;
226 
227  /* IDX is the bias from the thread pointer to the beginning of the
228  thread descriptor. It has to be subtracted due to implementation
229  quirks in libthread_db. */
230  *base = (void *) ((char *) regs.threadptr - idx);
231 
232  return PS_OK;
233 }
234 
235 static struct regsets_info xtensa_regsets_info =
236  {
237  xtensa_regsets, /* regsets */
238  0, /* num_regsets */
239  NULL, /* disabled_regsets */
240  };
241 
242 static struct regs_info regs_info =
243  {
244  NULL, /* regset_bitmap */
245  NULL, /* usrregs */
247  };
248 
249 static void
251 {
253 }
254 
255 /* Support for hardware single step. */
256 
257 static int
259 {
260  return 1;
261 }
262 
263 static const struct regs_info *
265 {
266  return &regs_info;
267 }
268 
272  0,
273  0,
274  NULL, /* fetch_register */
277  NULL, /* breakpoint_kind_from_pc */
279  NULL,
280  0,
282  NULL, /* supports_z_point_type */
283  NULL, /* insert_point */
284  NULL, /* remove_point */
285  NULL, /* stopped_by_watchpoint */
286  NULL, /* stopped_data_address */
287  NULL, /* collect_ptrace_register */
288  NULL, /* supply_ptrace_register */
289  NULL, /* siginfo_fixup */
290  NULL, /* new_process */
291  NULL, /* delete_process */
292  NULL, /* new_thread */
293  NULL, /* delete_thread */
294  NULL, /* new_fork */
295  NULL, /* prepare_to_resume */
296  NULL, /* process_qsupported */
297  NULL, /* supports_tracepoints */
298  NULL, /* get_thread_area */
299  NULL, /* install_fast_tracepoint_jump_pad */
300  NULL, /* emit_ops */
301  NULL, /* get_min_fast_tracepoint_insn_len */
302  NULL, /* supports_range_stepping */
303  NULL, /* breakpoint_kind_from_current_state */
305 };
306 
307 
308 void
310 {
311  /* Initialize the Linux target descriptions. */
313 
314  initialize_regsets_info (&xtensa_regsets_info);
315 }
unsigned int lwpid_t
const struct target_desc * tdesc
Definition: regcache.h:34
const xtensa_regtable_t xtensa_regmap_table[]
Definition: xtensa-xtregs.c:33
void collect_register(struct regcache *regcache, int n, void *buf)
Definition: regcache.c:402
struct linux_target_ops the_low_target
bfd_vma CORE_ADDR
Definition: common-types.h:41
void supply_register_by_name(struct regcache *regcache, const char *name, const void *buf)
Definition: regcache.c:393
static struct regs_info regs_info
static struct regsets_info xtensa_regsets_info
#define XTENSA_ELF_XTREG_SIZE
Definition: xtensa-xtregs.c:31
static struct regset_info xtensa_regsets[]
ps_err_e
regnum
static void xtensa_fill_xtregset(struct regcache *regcache, void *buf)
struct target_ops * the_target
Definition: target.c:24
const struct target_desc * tdesc
Definition: inferiors.h:67
PTRACE_TYPE_RET ptrace()
void initialize_low_arch(void)
CORE_ADDR linux_get_pc_32bit(struct regcache *regcache)
Definition: linux-low.c:7411
static void xtensa_fill_gregset(struct regcache *regcache, void *buf)
void collect_register_by_name(struct regcache *regcache, const char *name, void *buf)
Definition: regcache.c:441
static void xtensa_arch_setup(void)
static const struct regs_info * xtensa_regs_info(void)
void init_registers_xtensa(void)
static int xtensa_breakpoint_at(CORE_ADDR where)
static const gdb_byte xtensa_breakpoint[]
int register_size(const struct target_desc *tdesc, int n)
Definition: regcache.c:293
const struct target_desc * tdesc_xtensa
struct process_info * current_process(void)
Definition: inferiors.c:210
static void xtensa_store_xtregset(struct regcache *regcache, const void *buf)
#define XTENSA_BREAKPOINT
void linux_set_pc_32bit(struct regcache *regcache, CORE_ADDR pc)
Definition: linux-low.c:7400
ps_err_e ps_get_thread_area(struct ps_prochandle *ph, lwpid_t lwpid, int idx, void **base)
bfd_byte gdb_byte
Definition: common-types.h:38
int find_regno(const struct target_desc *tdesc, const char *name)
Definition: regcache.c:243
#define xtensa_breakpoint_len
static int xtensa_supports_hardware_single_step(void)
int(* read_memory)(CORE_ADDR memaddr, unsigned char *myaddr, int len)
Definition: target.h:166
static const gdb_byte * xtensa_sw_breakpoint_from_kind(int kind, int *size)
void supply_register(struct regcache *regcache, int n, const void *buf)
Definition: regcache.c:318
static void xtensa_store_gregset(struct regcache *regcache, const void *buf)