Support R_SPARC_WDISP10 and R_SPARC_H34.
[external/binutils.git] / gdb / gdbserver / linux-xtensa-low.c
1 /* GNU/Linux/Xtensa specific low level interface, for the remote server for GDB.
2    Copyright 2007-2012 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
26 #include <sys/ptrace.h>
27 #include <xtensa-config.h>
28
29 #include "xtensa-xtregs.c"
30
31 enum regnum {
32         R_PC=0, R_PS,
33         R_LBEG, R_LEND, R_LCOUNT,
34         R_SAR,
35         R_WS, R_WB,
36         R_A0 = 64
37 };
38
39 static void
40 xtensa_fill_gregset (struct regcache *regcache, void *buf)
41 {
42   elf_greg_t* rset = (elf_greg_t*)buf;
43   int ar0_regnum;
44   char *ptr;
45   int i;
46
47   /* Take care of AR registers.  */
48
49   ar0_regnum = find_regno ("ar0");
50   ptr = (char*)&rset[R_A0];
51
52   for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
53     {
54       collect_register (regcache, i, ptr);
55       ptr += register_size(i);
56     }
57
58   /* Loop registers, if hardware has it.  */
59
60 #if XCHAL_HAVE_LOOP
61   collect_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]);
62   collect_register_by_name (regcache, "lend", (char*)&rset[R_LEND]);
63   collect_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]);
64 #endif
65
66   collect_register_by_name (regcache, "sar", (char*)&rset[R_SAR]);
67   collect_register_by_name (regcache, "pc", (char*)&rset[R_PC]);
68   collect_register_by_name (regcache, "ps", (char*)&rset[R_PS]);
69   collect_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]);
70   collect_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]);
71 }
72
73 static void
74 xtensa_store_gregset (struct regcache *regcache, const void *buf)
75 {
76   const elf_greg_t* rset = (const elf_greg_t*)buf;
77   int ar0_regnum;
78   char *ptr;
79   int i;
80
81   /* Take care of AR registers.  */
82
83   ar0_regnum = find_regno ("ar0");
84   ptr = (char *)&rset[R_A0];
85
86   for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
87     {
88       supply_register (regcache, i, ptr);
89       ptr += register_size(i);
90     }
91
92   /* Loop registers, if hardware has it.  */
93
94 #if XCHAL_HAVE_LOOP
95   supply_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]);
96   supply_register_by_name (regcache, "lend", (char*)&rset[R_LEND]);
97   supply_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]);
98 #endif
99
100   supply_register_by_name (regcache, "sar", (char*)&rset[R_SAR]);
101   supply_register_by_name (regcache, "pc", (char*)&rset[R_PC]);
102   supply_register_by_name (regcache, "ps", (char*)&rset[R_PS]);
103   supply_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]);
104   supply_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]);
105 }
106
107 /* Xtensa GNU/Linux PTRACE interface includes extended register set.  */
108
109 static void
110 xtensa_fill_xtregset (struct regcache *regcache, void *buf)
111 {
112   const xtensa_regtable_t *ptr;
113
114   for (ptr = xtensa_regmap_table; ptr->name; ptr++)
115     {
116       collect_register_by_name (regcache, ptr->name,
117                                 (char*)buf + ptr->ptrace_offset);
118     }
119 }
120
121 static void
122 xtensa_store_xtregset (struct regcache *regcache, const void *buf)
123 {
124   const xtensa_regtable_t *ptr;
125
126   for (ptr = xtensa_regmap_table; ptr->name; ptr++)
127     {
128       supply_register_by_name (regcache, ptr->name,
129                                 (char*)buf + ptr->ptrace_offset);
130     }
131 }
132
133 struct regset_info target_regsets[] = {
134   { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
135     GENERAL_REGS,
136     xtensa_fill_gregset, xtensa_store_gregset },
137   { PTRACE_GETXTREGS, PTRACE_SETXTREGS, 0, XTENSA_ELF_XTREG_SIZE,
138     EXTENDED_REGS,
139     xtensa_fill_xtregset, xtensa_store_xtregset },
140   { 0, 0, 0, -1, -1, NULL, NULL }
141 };
142
143 #if XCHAL_HAVE_BE
144 #define XTENSA_BREAKPOINT {0xd2,0x0f}
145 #else
146 #define XTENSA_BREAKPOINT {0x2d,0xf0}
147 #endif
148
149 static const unsigned char xtensa_breakpoint[] = XTENSA_BREAKPOINT;
150 #define xtensa_breakpoint_len 2
151
152 static CORE_ADDR
153 xtensa_get_pc (struct regcache *regcache)
154 {
155   unsigned long pc;
156
157   collect_register_by_name (regcache, "pc", &pc);
158   return pc;
159 }
160
161 static void
162 xtensa_set_pc (struct regcache *regcache, CORE_ADDR pc)
163 {
164   unsigned long newpc = pc;
165   supply_register_by_name (regcache, "pc", &newpc);
166 }
167
168 static int
169 xtensa_breakpoint_at (CORE_ADDR where)
170 {
171     unsigned long insn;
172
173     (*the_target->read_memory) (where, (unsigned char *) &insn,
174                                 xtensa_breakpoint_len);
175     return memcmp((char *) &insn,
176                   xtensa_breakpoint, xtensa_breakpoint_len) == 0;
177 }
178
179 struct linux_target_ops the_low_target = {
180   init_registers_xtensa,
181   0,
182   0,
183   NULL,
184   0,
185   0,
186   NULL, /* fetch_register */
187   xtensa_get_pc,
188   xtensa_set_pc,
189   xtensa_breakpoint,
190   xtensa_breakpoint_len,
191   NULL,
192   0,
193   xtensa_breakpoint_at,
194 };