OSDN Git Service

Copyright updates for 2007.
[pf3gnuchains/pf3gnuchains3x.git] / gdb / gdbserver / linux-mips-low.c
1 /* GNU/Linux/MIPS specific low level interface, for the remote server for GDB.
2    Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2005, 2006, 2007
3    Free Software Foundation, Inc.
4
5    This file is part of GDB.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301, USA.  */
21
22 #include "server.h"
23 #include "linux-low.h"
24
25 #include <sys/ptrace.h>
26 #include <endian.h>
27
28 #include "gdb_proc_service.h"
29
30 #ifndef PTRACE_GET_THREAD_AREA
31 #define PTRACE_GET_THREAD_AREA 25
32 #endif
33
34 #ifdef HAVE_SYS_REG_H
35 #include <sys/reg.h>
36 #endif
37
38 #define mips_num_regs 90
39
40 #include <asm/ptrace.h>
41
42 union mips_register
43 {
44   unsigned char buf[8];
45
46   /* Deliberately signed, for proper sign extension.  */
47   int reg32;
48   long long reg64;
49 };
50
51 /* Return the ptrace ``address'' of register REGNO. */
52
53 /* Matches mips_generic32_regs */
54 static int mips_regmap[] = {
55   0,  1,  2,  3,  4,  5,  6,  7,
56   8,  9,  10, 11, 12, 13, 14, 15,
57   16, 17, 18, 19, 20, 21, 22, 23,
58   24, 25, 26, 27, 28, 29, 30, 31,
59
60   -1, MMLO, MMHI, BADVADDR, CAUSE, PC,
61
62   FPR_BASE,      FPR_BASE + 1,  FPR_BASE + 2,  FPR_BASE + 3,
63   FPR_BASE + 4,  FPR_BASE + 5,  FPR_BASE + 6,  FPR_BASE + 7,
64   FPR_BASE + 8,  FPR_BASE + 8,  FPR_BASE + 10, FPR_BASE + 11,
65   FPR_BASE + 12, FPR_BASE + 13, FPR_BASE + 14, FPR_BASE + 15,
66   FPR_BASE + 16, FPR_BASE + 17, FPR_BASE + 18, FPR_BASE + 19,
67   FPR_BASE + 20, FPR_BASE + 21, FPR_BASE + 22, FPR_BASE + 23,
68   FPR_BASE + 24, FPR_BASE + 25, FPR_BASE + 26, FPR_BASE + 27,
69   FPR_BASE + 28, FPR_BASE + 29, FPR_BASE + 30, FPR_BASE + 31,
70   FPC_CSR, FPC_EIR,
71
72   -1, -1,
73   -1, -1, -1, -1, -1, -1, -1, -1,
74   -1, -1, -1, -1, -1, -1, -1, -1,
75 };
76
77 /* From mips-linux-nat.c.  */
78
79 /* Pseudo registers can not be read.  ptrace does not provide a way to
80    read (or set) PS_REGNUM, and there's no point in reading or setting
81    ZERO_REGNUM.  We also can not set BADVADDR, CAUSE, or FCRIR via
82    ptrace().  */
83
84 static int
85 mips_cannot_fetch_register (int regno)
86 {
87   if (mips_regmap[regno] == -1)
88     return 1;
89
90   if (find_regno ("zero") == regno)
91     return 1;
92
93   return 0;
94 }
95
96 static int
97 mips_cannot_store_register (int regno)
98 {
99   if (mips_regmap[regno] == -1)
100     return 1;
101
102   if (find_regno ("zero") == regno)
103     return 1;
104
105   if (find_regno ("cause") == regno)
106     return 1;
107
108   if (find_regno ("bad") == regno)
109     return 1;
110
111   if (find_regno ("fir") == regno)
112     return 1;
113
114   return 0;
115 }
116
117 static CORE_ADDR
118 mips_get_pc ()
119 {
120   union mips_register pc;
121   collect_register_by_name ("pc", pc.buf);
122   return register_size (0) == 4 ? pc.reg32 : pc.reg64;
123 }
124
125 static void
126 mips_set_pc (CORE_ADDR pc)
127 {
128   union mips_register newpc;
129   if (register_size (0) == 4)
130     newpc.reg32 = pc;
131   else
132     newpc.reg64 = pc;
133
134   supply_register_by_name ("pc", newpc.buf);
135 }
136
137 /* Correct in either endianness.  */
138 static const unsigned int mips_breakpoint = 0x0005000d;
139 #define mips_breakpoint_len 4
140
141 /* We only place breakpoints in empty marker functions, and thread locking
142    is outside of the function.  So rather than importing software single-step,
143    we can just run until exit.  */
144 static CORE_ADDR
145 mips_reinsert_addr ()
146 {
147   union mips_register ra;
148   collect_register_by_name ("ra", ra.buf);
149   return register_size (0) == 4 ? ra.reg32 : ra.reg64;
150 }
151
152 static int
153 mips_breakpoint_at (CORE_ADDR where)
154 {
155   unsigned int insn;
156
157   (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
158   if (insn == mips_breakpoint)
159     return 1;
160
161   /* If necessary, recognize more trap instructions here.  GDB only uses the
162      one.  */
163   return 0;
164 }
165
166 /* Fetch the thread-local storage pointer for libthread_db.  */
167
168 ps_err_e
169 ps_get_thread_area (const struct ps_prochandle *ph,
170                     lwpid_t lwpid, int idx, void **base)
171 {
172   if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
173     return PS_ERR;
174
175   /* IDX is the bias from the thread pointer to the beginning of the
176      thread descriptor.  It has to be subtracted due to implementation
177      quirks in libthread_db.  */
178   *base = (void *) ((char *)*base - idx);
179
180   return PS_OK;
181 }
182
183 #ifdef HAVE_PTRACE_GETREGS
184
185 static void
186 mips_collect_register (int use_64bit, int regno, union mips_register *reg)
187 {
188   union mips_register tmp_reg;
189
190   if (use_64bit)
191     {
192       collect_register (regno, &tmp_reg.reg64);
193       *reg = tmp_reg;
194     }
195   else
196     {
197       collect_register (regno, &tmp_reg.reg32);
198       reg->reg64 = tmp_reg.reg32;
199     }
200 }
201
202 static void
203 mips_supply_register (int use_64bit, int regno, const union mips_register *reg)
204 {
205   int offset = 0;
206
207   /* For big-endian 32-bit targets, ignore the high four bytes of each
208      eight-byte slot.  */
209   if (__BYTE_ORDER == __BIG_ENDIAN && !use_64bit)
210     offset = 4;
211
212   supply_register (regno, reg->buf + offset);
213 }
214
215 static void
216 mips_collect_register_32bit (int use_64bit, int regno, unsigned char *buf)
217 {
218   union mips_register tmp_reg;
219   int reg32;
220
221   mips_collect_register (use_64bit, regno, &tmp_reg);
222   reg32 = tmp_reg.reg64;
223   memcpy (buf, &reg32, 4);
224 }
225
226 static void
227 mips_supply_register_32bit (int use_64bit, int regno, const unsigned char *buf)
228 {
229   union mips_register tmp_reg;
230   int reg32;
231
232   memcpy (&reg32, buf, 4);
233   tmp_reg.reg64 = reg32;
234   mips_supply_register (use_64bit, regno, &tmp_reg);
235 }
236
237 static void
238 mips_fill_gregset (void *buf)
239 {
240   union mips_register *regset = buf;
241   int i, use_64bit;
242
243   use_64bit = (register_size (0) == 8);
244
245   for (i = 0; i < 32; i++)
246     mips_collect_register (use_64bit, i, regset + i);
247
248   mips_collect_register (use_64bit, find_regno ("lo"), regset + 32);
249   mips_collect_register (use_64bit, find_regno ("hi"), regset + 33);
250   mips_collect_register (use_64bit, find_regno ("pc"), regset + 34);
251   mips_collect_register (use_64bit, find_regno ("bad"), regset + 35);
252   mips_collect_register (use_64bit, find_regno ("sr"), regset + 36);
253   mips_collect_register (use_64bit, find_regno ("cause"), regset + 37);
254 }
255
256 static void
257 mips_store_gregset (const void *buf)
258 {
259   const union mips_register *regset = buf;
260   int i, use_64bit;
261
262   use_64bit = (register_size (0) == 8);
263
264   for (i = 0; i < 32; i++)
265     mips_supply_register (use_64bit, i, regset + i);
266
267   mips_supply_register (use_64bit, find_regno ("lo"), regset + 32);
268   mips_supply_register (use_64bit, find_regno ("hi"), regset + 33);
269   mips_supply_register (use_64bit, find_regno ("pc"), regset + 34);
270   mips_supply_register (use_64bit, find_regno ("bad"), regset + 35);
271   mips_supply_register (use_64bit, find_regno ("sr"), regset + 36);
272   mips_supply_register (use_64bit, find_regno ("cause"), regset + 37);
273 }
274
275 static void
276 mips_fill_fpregset (void *buf)
277 {
278   union mips_register *regset = buf;
279   int i, use_64bit, first_fp, big_endian;
280
281   use_64bit = (register_size (0) == 8);
282   first_fp = find_regno ("f0");
283   big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
284
285   /* See GDB for a discussion of this peculiar layout.  */
286   for (i = 0; i < 32; i++)
287     if (use_64bit)
288       collect_register (first_fp + i, regset[i].buf);
289     else
290       collect_register (first_fp + i,
291                         regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
292
293   mips_collect_register_32bit (use_64bit, find_regno ("fsr"), regset[32].buf);
294   mips_collect_register_32bit (use_64bit, find_regno ("fir"),
295                                regset[32].buf + 4);
296 }
297
298 static void
299 mips_store_fpregset (const void *buf)
300 {
301   const union mips_register *regset = buf;
302   int i, use_64bit, first_fp, big_endian;
303
304   use_64bit = (register_size (0) == 8);
305   first_fp = find_regno ("f0");
306   big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
307
308   /* See GDB for a discussion of this peculiar layout.  */
309   for (i = 0; i < 32; i++)
310     if (use_64bit)
311       supply_register (first_fp + i, regset[i].buf);
312     else
313       supply_register (first_fp + i,
314                        regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
315
316   mips_supply_register_32bit (use_64bit, find_regno ("fsr"), regset[32].buf);
317   mips_supply_register_32bit (use_64bit, find_regno ("fir"),
318                               regset[32].buf + 4);
319 }
320 #endif /* HAVE_PTRACE_GETREGS */
321
322 struct regset_info target_regsets[] = {
323 #ifdef HAVE_PTRACE_GETREGS
324   { PTRACE_GETREGS, PTRACE_SETREGS, 38 * 8, GENERAL_REGS,
325     mips_fill_gregset, mips_store_gregset },
326   { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 33 * 8, FP_REGS,
327     mips_fill_fpregset, mips_store_fpregset },
328 #endif /* HAVE_PTRACE_GETREGS */
329   { 0, 0, -1, -1, NULL, NULL }
330 };
331
332 struct linux_target_ops the_low_target = {
333   mips_num_regs,
334   mips_regmap,
335   mips_cannot_fetch_register,
336   mips_cannot_store_register,
337   mips_get_pc,
338   mips_set_pc,
339   (const unsigned char *) &mips_breakpoint,
340   mips_breakpoint_len,
341   mips_reinsert_addr,
342   0,
343   mips_breakpoint_at,
344 };