2000-03-21 J.T. Conklin <jtc@redback.com>
[platform/upstream/binutils.git] / gdb / mipsm3-nat.c
1 /* Definitions to make GDB run on a mips box under Mach 3.0
2    Copyright (C) 1992 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
30 #include <stdio.h>
31
32 #include <mach.h>
33 #include <mach/message.h>
34 #include <mach/exception.h>
35 #include <mach_error.h>
36
37 /* Find offsets to thread states at compile time.
38  * If your compiler does not grok this, check the hand coded
39  * offsets and use them.
40  */
41
42 #if 1
43
44 #define  REG_OFFSET(reg) (int)(&((struct mips_thread_state *)0)->reg)
45 #define CREG_OFFSET(reg) (int)(&((struct mips_float_state *)0)->reg)
46 #define EREG_OFFSET(reg) (int)(&((struct mips_exc_state *)0)->reg)
47
48 /* at reg_offset[i] is the offset to the mips_thread_state
49  * location where the gdb registers[i] is stored.
50  *
51  * -1 means mach does not save it anywhere.
52  */
53 static int reg_offset[] =
54 {
55   /*  zero              at                v0                v1       */
56   -1, REG_OFFSET (r1), REG_OFFSET (r2), REG_OFFSET (r3),
57
58   /*  a0                a1                a2                a3       */
59   REG_OFFSET (r4), REG_OFFSET (r5), REG_OFFSET (r6), REG_OFFSET (r7),
60
61   /*  t0                t1                t2                t3       */
62   REG_OFFSET (r8), REG_OFFSET (r9), REG_OFFSET (r10), REG_OFFSET (r11),
63
64   /*  t4                t5                t6                t7       */
65   REG_OFFSET (r12), REG_OFFSET (r13), REG_OFFSET (r14), REG_OFFSET (r15),
66
67   /*  s0                s1                s2                s3       */
68   REG_OFFSET (r16), REG_OFFSET (r17), REG_OFFSET (r18), REG_OFFSET (r19),
69
70   /*  s4                s5                s6                s7       */
71   REG_OFFSET (r20), REG_OFFSET (r21), REG_OFFSET (r22), REG_OFFSET (r23),
72
73   /*  t8                t9                k0                k1       */
74   REG_OFFSET (r24), REG_OFFSET (r25), REG_OFFSET (r26), REG_OFFSET (r27),
75
76   /*  gp                sp            s8(30) == fp(72)      ra       */
77   REG_OFFSET (r28), REG_OFFSET (r29), REG_OFFSET (r30), REG_OFFSET (r31),
78
79   /*  sr(32) PS_REGNUM   */
80   EREG_OFFSET (coproc_state),
81
82   /*  lo(33)            hi(34)    */
83   REG_OFFSET (mdlo), REG_OFFSET (mdhi),
84
85   /*  bad(35)                 cause(36)          pc(37)  */
86   EREG_OFFSET (address), EREG_OFFSET (cause), REG_OFFSET (pc),
87
88   /*  f0(38)             f1(39)             f2(40)             f3(41)   */
89   CREG_OFFSET (r0), CREG_OFFSET (r1), CREG_OFFSET (r2), CREG_OFFSET (r3),
90   CREG_OFFSET (r4), CREG_OFFSET (r5), CREG_OFFSET (r6), CREG_OFFSET (r7),
91   CREG_OFFSET (r8), CREG_OFFSET (r9), CREG_OFFSET (r10), CREG_OFFSET (r11),
92   CREG_OFFSET (r12), CREG_OFFSET (r13), CREG_OFFSET (r14), CREG_OFFSET (r15),
93   CREG_OFFSET (r16), CREG_OFFSET (r17), CREG_OFFSET (r18), CREG_OFFSET (r19),
94   CREG_OFFSET (r20), CREG_OFFSET (r21), CREG_OFFSET (r22), CREG_OFFSET (r23),
95   CREG_OFFSET (r24), CREG_OFFSET (r25), CREG_OFFSET (r26), CREG_OFFSET (r27),
96   CREG_OFFSET (r28), CREG_OFFSET (r29), CREG_OFFSET (r30), CREG_OFFSET (r31),
97
98   /*  fsr(70)           fir(71)         fp(72) == s8(30) */
99   CREG_OFFSET (csr), CREG_OFFSET (esr), REG_OFFSET (r30)
100 };
101 #else
102 /* If the compiler does not grok the above defines */
103 static int reg_offset[] =
104 {
105 /* mach_thread_state offsets: */
106   -1, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56,
107   60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120,
108 /*sr, lo, hi,addr,cause,pc   */
109   8, 124, 128, 4, 0, 132,
110 /* mach_float_state offsets: */
111   0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60,
112   64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124,
113 /*fsr,fir */
114   128, 132,
115 /* FP_REGNUM pseudo maps to s8==r30 in mach_thread_state */
116   116
117 };
118 #endif
119
120 /* Fetch COUNT contiguous registers from thread STATE starting from REGNUM
121  * Caller knows that the regs handled in one transaction are of same size.
122  */
123 #define FETCH_REGS(state, regnum, count) \
124   memcpy (&registers[REGISTER_BYTE (regnum)], \
125           (char *)state+reg_offset[ regnum ], \
126           count*REGISTER_SIZE)
127
128 /* Store COUNT contiguous registers to thread STATE starting from REGNUM */
129 #define STORE_REGS(state, regnum, count) \
130   memcpy ((char *)state+reg_offset[ regnum ], \
131           &registers[REGISTER_BYTE (regnum)], \
132           count*REGISTER_SIZE)
133
134 #define REGS_ALL    -1
135 #define REGS_NORMAL  1
136 #define REGS_EXC     2
137 #define REGS_COP1    4
138
139 /* Hardware regs that matches FP_REGNUM */
140 #define MACH_FP_REGNUM 30
141
142 /* Fech thread's registers. if regno == -1, fetch all regs */
143 void
144 fetch_inferior_registers (regno)
145      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 *) 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 (&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   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 (regno)
300      register int regno;
301 {
302   thread_state_data_t state;
303   kern_return_t ret;
304
305   if (!MACH_PORT_VALID (current_thread))
306     error ("store inferior registers: Invalid thread");
307
308   /* Check for read only regs.
309    * @@ If some of these is can be changed, fix this
310    */
311   if (regno == ZERO_REGNUM ||
312       regno == PS_REGNUM ||
313       regno == BADVADDR_REGNUM ||
314       regno == CAUSE_REGNUM ||
315       regno == FCRIR_REGNUM)
316     {
317       message ("You can not alter read-only register `%s'",
318                REGISTER_NAME (regno));
319       fetch_inferior_registers (regno);
320       return;
321     }
322
323   if (regno == -1)
324     {
325       /* Don't allow these to change */
326
327       /* ZERO_REGNUM */
328       *(int *) registers = 0;
329
330       fetch_inferior_registers (PS_REGNUM);
331       fetch_inferior_registers (BADVADDR_REGNUM);
332       fetch_inferior_registers (CAUSE_REGNUM);
333       fetch_inferior_registers (FCRIR_REGNUM);
334     }
335
336   if (regno == -1 || (ZERO_REGNUM < regno && regno <= PC_REGNUM))
337     {
338 #if 1
339       /* Mach 3.0 saves thread's FP to MACH_FP_REGNUM.
340        * GDB wants assigns a pseudo register FP_REGNUM for frame pointer.
341        *
342        * @@@ Here I assume (!) that gdb's FP has the value that
343        *     should go to threads frame pointer. If not true, this
344        *     fails badly!!!!!
345        */
346       memcpy (&registers[REGISTER_BYTE (MACH_FP_REGNUM)],
347               &registers[REGISTER_BYTE (FP_REGNUM)],
348               REGISTER_RAW_SIZE (FP_REGNUM));
349 #endif
350
351       /* Save gdb's regs 1..31 to thread saved regs 1..31
352        * Luckily, they are contiquous
353        */
354       STORE_REGS (state, 1, 31);
355
356       /* Save mdlo, mdhi */
357       STORE_REGS (state, LO_REGNUM, 2);
358
359       /* Save PC */
360       STORE_REGS (state, PC_REGNUM, 1);
361
362       ret = thread_set_state (current_thread,
363                               MIPS_THREAD_STATE,
364                               state,
365                               MIPS_FLOAT_STATE_COUNT);
366       CHK ("store inferior regs : thread_set_state", ret);
367     }
368
369   if (regno == -1 || regno >= FP0_REGNUM)
370     {
371       /* If thread has floating state, save it */
372       if (read_register (PS_REGNUM) & MIPS_STATUS_USE_COP1)
373         {
374           /* Do NOT save FCRIR_REGNUM */
375           STORE_REGS (state, FP0_REGNUM, 33);
376
377           ret = thread_set_state (current_thread,
378                                   MIPS_FLOAT_STATE,
379                                   state,
380                                   MIPS_FLOAT_STATE_COUNT);
381           CHK ("store inferior registers (floats): thread_set_state", ret);
382         }
383       else if (regno != -1)
384         message
385           ("Thread does not use floating point unit, floating regs not saved");
386     }
387 }