2002-12-09 David Carlton <carlton@math.stanford.edu>
[external/binutils.git] / gdb / mipsm3-nat.c
1 /* Definitions to make GDB run on a mips box under Mach 3.0
2    Copyright 1992, 1993, 1998, 2000, 2001 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 2 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, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 /* Mach specific routines for little endian mips (e.g. pmax)
22  * running Mach 3.0
23  *
24  * Author: Jukka Virtanen <jtv@hut.fi>
25  */
26
27 #include "defs.h"
28 #include "inferior.h"
29 #include "regcache.h"
30
31 #include <stdio.h>
32
33 #include <mach.h>
34 #include <mach/message.h>
35 #include <mach/exception.h>
36 #include <mach_error.h>
37
38 /* Find offsets to thread states at compile time.
39  * If your compiler does not grok this, check the hand coded
40  * offsets and use them.
41  */
42
43 #if 1
44
45 #define  REG_OFFSET(reg) (int)(&((struct mips_thread_state *)0)->reg)
46 #define CREG_OFFSET(reg) (int)(&((struct mips_float_state *)0)->reg)
47 #define EREG_OFFSET(reg) (int)(&((struct mips_exc_state *)0)->reg)
48
49 /* at reg_offset[i] is the offset to the mips_thread_state
50  * location where the gdb registers[i] is stored.
51  *
52  * -1 means mach does not save it anywhere.
53  */
54 static int reg_offset[] =
55 {
56   /*  zero              at                v0                v1       */
57   -1, REG_OFFSET (r1), REG_OFFSET (r2), REG_OFFSET (r3),
58
59   /*  a0                a1                a2                a3       */
60   REG_OFFSET (r4), REG_OFFSET (r5), REG_OFFSET (r6), REG_OFFSET (r7),
61
62   /*  t0                t1                t2                t3       */
63   REG_OFFSET (r8), REG_OFFSET (r9), REG_OFFSET (r10), REG_OFFSET (r11),
64
65   /*  t4                t5                t6                t7       */
66   REG_OFFSET (r12), REG_OFFSET (r13), REG_OFFSET (r14), REG_OFFSET (r15),
67
68   /*  s0                s1                s2                s3       */
69   REG_OFFSET (r16), REG_OFFSET (r17), REG_OFFSET (r18), REG_OFFSET (r19),
70
71   /*  s4                s5                s6                s7       */
72   REG_OFFSET (r20), REG_OFFSET (r21), REG_OFFSET (r22), REG_OFFSET (r23),
73
74   /*  t8                t9                k0                k1       */
75   REG_OFFSET (r24), REG_OFFSET (r25), REG_OFFSET (r26), REG_OFFSET (r27),
76
77   /*  gp                sp            s8(30) == fp(72)      ra       */
78   REG_OFFSET (r28), REG_OFFSET (r29), REG_OFFSET (r30), REG_OFFSET (r31),
79
80   /*  sr(32) PS_REGNUM   */
81   EREG_OFFSET (coproc_state),
82
83   /*  lo(33)            hi(34)    */
84   REG_OFFSET (mdlo), REG_OFFSET (mdhi),
85
86   /*  bad(35)                 cause(36)          pc(37)  */
87   EREG_OFFSET (address), EREG_OFFSET (cause), REG_OFFSET (pc),
88
89   /*  f0(38)             f1(39)             f2(40)             f3(41)   */
90   CREG_OFFSET (r0), CREG_OFFSET (r1), CREG_OFFSET (r2), CREG_OFFSET (r3),
91   CREG_OFFSET (r4), CREG_OFFSET (r5), CREG_OFFSET (r6), CREG_OFFSET (r7),
92   CREG_OFFSET (r8), CREG_OFFSET (r9), CREG_OFFSET (r10), CREG_OFFSET (r11),
93   CREG_OFFSET (r12), CREG_OFFSET (r13), CREG_OFFSET (r14), CREG_OFFSET (r15),
94   CREG_OFFSET (r16), CREG_OFFSET (r17), CREG_OFFSET (r18), CREG_OFFSET (r19),
95   CREG_OFFSET (r20), CREG_OFFSET (r21), CREG_OFFSET (r22), CREG_OFFSET (r23),
96   CREG_OFFSET (r24), CREG_OFFSET (r25), CREG_OFFSET (r26), CREG_OFFSET (r27),
97   CREG_OFFSET (r28), CREG_OFFSET (r29), CREG_OFFSET (r30), CREG_OFFSET (r31),
98
99   /*  fsr(70)           fir(71)         fp(72) == s8(30) */
100   CREG_OFFSET (csr), CREG_OFFSET (esr), REG_OFFSET (r30)
101 };
102 #else
103 /* If the compiler does not grok the above defines */
104 static int reg_offset[] =
105 {
106 /* mach_thread_state offsets: */
107   -1, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56,
108   60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120,
109 /*sr, lo, hi,addr,cause,pc   */
110   8, 124, 128, 4, 0, 132,
111 /* mach_float_state offsets: */
112   0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60,
113   64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124,
114 /*fsr,fir */
115   128, 132,
116 /* FP_REGNUM pseudo maps to s8==r30 in mach_thread_state */
117   116
118 };
119 #endif
120
121 /* Fetch COUNT contiguous registers from thread STATE starting from REGNUM
122  * Caller knows that the regs handled in one transaction are of same size.
123  */
124 #define FETCH_REGS(state, regnum, count) \
125   memcpy (&deprecated_registers[REGISTER_BYTE (regnum)], \
126           (char *)state+reg_offset[ regnum ], \
127           count*REGISTER_SIZE)
128
129 /* Store COUNT contiguous registers to thread STATE starting from REGNUM */
130 #define STORE_REGS(state, regnum, count) \
131   memcpy ((char *)state+reg_offset[ regnum ], \
132           &deprecated_registers[REGISTER_BYTE (regnum)], \
133           count*REGISTER_SIZE)
134
135 #define REGS_ALL    -1
136 #define REGS_NORMAL  1
137 #define REGS_EXC     2
138 #define REGS_COP1    4
139
140 /* Hardware regs that matches FP_REGNUM */
141 #define MACH_FP_REGNUM 30
142
143 /* Fech thread's registers. if regno == -1, fetch all regs */
144 void
145 fetch_inferior_registers (int regno)
146 {
147   kern_return_t ret;
148
149   thread_state_data_t state;
150   struct mips_exc_state exc_state;
151
152   int stateCnt = MIPS_THREAD_STATE_COUNT;
153
154   int which_regs = 0;           /* A bit mask */
155
156   if (!MACH_PORT_VALID (current_thread))
157     error ("fetch inferior registers: Invalid thread");
158
159   if (regno < -1 || regno >= NUM_REGS)
160     error ("invalid register %d supplied to fetch_inferior_registers", regno);
161
162   if (regno == -1)
163     which_regs = REGS_ALL;
164   else if (regno == ZERO_REGNUM)
165     {
166       int zero = 0;
167       supply_register (ZERO_REGNUM, &zero);
168       return;
169     }
170   else if ((ZERO_REGNUM < regno && regno < PS_REGNUM)
171            || regno == FP_REGNUM
172            || regno == LO_REGNUM
173            || regno == HI_REGNUM
174            || regno == PC_REGNUM)
175     which_regs = REGS_NORMAL;
176   else if (FP0_REGNUM <= regno && regno <= FCRIR_REGNUM)
177     which_regs = REGS_COP1 | REGS_EXC;
178   else
179     which_regs = REGS_EXC;
180
181   /* fetch regs saved to mips_thread_state */
182   if (which_regs & REGS_NORMAL)
183     {
184       ret = thread_get_state (current_thread,
185                               MIPS_THREAD_STATE,
186                               state,
187                               &stateCnt);
188       CHK ("fetch inferior registers: thread_get_state", ret);
189
190       if (which_regs == REGS_NORMAL)
191         {
192           /* Fetch also FP_REGNUM if fetching MACH_FP_REGNUM and vice versa */
193           if (regno == MACH_FP_REGNUM || regno == FP_REGNUM)
194             {
195               supply_register (FP_REGNUM,
196                                (char *) state + reg_offset[MACH_FP_REGNUM]);
197               supply_register (MACH_FP_REGNUM,
198                                (char *) state + reg_offset[MACH_FP_REGNUM]);
199             }
200           else
201             supply_register (regno,
202                              (char *) state + reg_offset[regno]);
203           return;
204         }
205
206       /* ZERO_REGNUM is always zero */
207       *(int *) deprecated_registers = 0;
208
209       /* Copy thread saved regs 1..31 to gdb's reg value array
210        * Luckily, they are contiquous
211        */
212       FETCH_REGS (state, 1, 31);
213
214       /* Copy mdlo and mdhi */
215       FETCH_REGS (state, LO_REGNUM, 2);
216
217       /* Copy PC */
218       FETCH_REGS (state, PC_REGNUM, 1);
219
220       /* Mach 3.0 saves FP to MACH_FP_REGNUM.
221        * For some reason gdb wants to assign a pseudo register for it.
222        */
223       FETCH_REGS (state, FP_REGNUM, 1);
224     }
225
226   /* Read exc state. Also read if need to fetch floats */
227   if (which_regs & REGS_EXC)
228     {
229       stateCnt = MIPS_EXC_STATE_COUNT;
230       ret = thread_get_state (current_thread,
231                               MIPS_EXC_STATE,
232                               (thread_state_t) & exc_state,
233                               &stateCnt);
234       CHK ("fetch inferior regs (exc): thread_get_state", ret);
235
236       /* We need to fetch exc_state to see if the floating
237        * state is valid for the thread.
238        */
239
240       /* cproc_state: Which coprocessors the thread uses */
241       supply_register (PS_REGNUM,
242                        (char *) &exc_state + reg_offset[PS_REGNUM]);
243
244       if (which_regs == REGS_EXC || which_regs == REGS_ALL)
245         {
246           supply_register (BADVADDR_REGNUM,
247                          (char *) &exc_state + reg_offset[BADVADDR_REGNUM]);
248
249           supply_register (CAUSE_REGNUM,
250                            (char *) &exc_state + reg_offset[CAUSE_REGNUM]);
251           if (which_regs == REGS_EXC)
252             return;
253         }
254     }
255
256
257   if (which_regs & REGS_COP1)
258     {
259       /* If the thread does not have saved COPROC1, set regs to zero */
260
261       if (!(exc_state.coproc_state & MIPS_STATUS_USE_COP1))
262         bzero (&deprecated_registers[REGISTER_BYTE (FP0_REGNUM)],
263                sizeof (struct mips_float_state));
264       else
265         {
266           stateCnt = MIPS_FLOAT_STATE_COUNT;
267           ret = thread_get_state (current_thread,
268                                   MIPS_FLOAT_STATE,
269                                   state,
270                                   &stateCnt);
271           CHK ("fetch inferior regs (floats): thread_get_state", ret);
272
273           if (regno != -1)
274             {
275               supply_register (regno,
276                                (char *) state + reg_offset[regno]);
277               return;
278             }
279
280           FETCH_REGS (state, FP0_REGNUM, 34);
281         }
282     }
283
284   /* All registers are valid, if not returned yet */
285   deprecated_registers_fetched ();
286 }
287
288 /* Store gdb's view of registers to the thread.
289  * All registers are always valid when entering here.
290  * @@ ahem, maybe that is too strict, we could validate the necessary ones
291  *    here.
292  *
293  * Hmm. It seems that gdb set $reg=value command first reads everything,
294  * then sets the reg and then stores everything. -> we must make sure
295  * that the immutable registers are not changed by reading them first.
296  */
297
298 void
299 store_inferior_registers (register int regno)
300 {
301   thread_state_data_t state;
302   kern_return_t ret;
303
304   if (!MACH_PORT_VALID (current_thread))
305     error ("store inferior registers: Invalid thread");
306
307   /* Check for read only regs.
308    * @@ If some of these is can be changed, fix this
309    */
310   if (regno == ZERO_REGNUM ||
311       regno == PS_REGNUM ||
312       regno == BADVADDR_REGNUM ||
313       regno == CAUSE_REGNUM ||
314       regno == FCRIR_REGNUM)
315     {
316       message ("You can not alter read-only register `%s'",
317                REGISTER_NAME (regno));
318       fetch_inferior_registers (regno);
319       return;
320     }
321
322   if (regno == -1)
323     {
324       /* Don't allow these to change */
325
326       /* ZERO_REGNUM */
327       *(int *) deprecated_registers = 0;
328
329       fetch_inferior_registers (PS_REGNUM);
330       fetch_inferior_registers (BADVADDR_REGNUM);
331       fetch_inferior_registers (CAUSE_REGNUM);
332       fetch_inferior_registers (FCRIR_REGNUM);
333     }
334
335   if (regno == -1 || (ZERO_REGNUM < regno && regno <= PC_REGNUM))
336     {
337 #if 1
338       /* Mach 3.0 saves thread's FP to MACH_FP_REGNUM.
339        * GDB wants assigns a pseudo register FP_REGNUM for frame pointer.
340        *
341        * @@@ Here I assume (!) that gdb's FP has the value that
342        *     should go to threads frame pointer. If not true, this
343        *     fails badly!!!!!
344        */
345       memcpy (&deprecated_registers[REGISTER_BYTE (MACH_FP_REGNUM)],
346               &deprecated_registers[REGISTER_BYTE (FP_REGNUM)],
347               REGISTER_RAW_SIZE (FP_REGNUM));
348 #endif
349
350       /* Save gdb's regs 1..31 to thread saved regs 1..31
351        * Luckily, they are contiquous
352        */
353       STORE_REGS (state, 1, 31);
354
355       /* Save mdlo, mdhi */
356       STORE_REGS (state, LO_REGNUM, 2);
357
358       /* Save PC */
359       STORE_REGS (state, PC_REGNUM, 1);
360
361       ret = thread_set_state (current_thread,
362                               MIPS_THREAD_STATE,
363                               state,
364                               MIPS_FLOAT_STATE_COUNT);
365       CHK ("store inferior regs : thread_set_state", ret);
366     }
367
368   if (regno == -1 || regno >= FP0_REGNUM)
369     {
370       /* If thread has floating state, save it */
371       if (read_register (PS_REGNUM) & MIPS_STATUS_USE_COP1)
372         {
373           /* Do NOT save FCRIR_REGNUM */
374           STORE_REGS (state, FP0_REGNUM, 33);
375
376           ret = thread_set_state (current_thread,
377                                   MIPS_FLOAT_STATE,
378                                   state,
379                                   MIPS_FLOAT_STATE_COUNT);
380           CHK ("store inferior registers (floats): thread_set_state", ret);
381         }
382       else if (regno != -1)
383         message
384           ("Thread does not use floating point unit, floating regs not saved");
385     }
386 }