Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* Low level interface to I386 running the GNU Hurd |
2 | Copyright (C) 1992, 1995, 1996 Free Software Foundation, Inc. | |
3 | ||
c5aa993b | 4 | This file is part of GDB. |
c906108c | 5 | |
c5aa993b JM |
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. | |
c906108c | 10 | |
c5aa993b JM |
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. | |
c906108c | 15 | |
c5aa993b JM |
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. */ | |
c906108c SS |
20 | |
21 | #include "defs.h" | |
22 | #include "inferior.h" | |
23 | #include "floatformat.h" | |
24 | ||
25 | #include <stdio.h> | |
26 | #include <errno.h> | |
27 | ||
28 | #include <mach.h> | |
29 | #include <mach/message.h> | |
30 | #include <mach/exception.h> | |
31 | #include <mach_error.h> | |
32 | ||
33 | #include "gnu-nat.h" | |
34 | ||
35 | /* Hmmm... Should this not be here? | |
36 | * Now for i386_float_info() target_has_execution | |
37 | */ | |
38 | #include <target.h> | |
39 | ||
40 | /* @@@ Should move print_387_status() to i387-tdep.c */ | |
c5aa993b | 41 | extern void print_387_control_word (); /* i387-tdep.h */ |
c906108c SS |
42 | extern void print_387_status_word (); |
43 | \f | |
44 | /* Find offsets to thread states at compile time. | |
45 | * If your compiler does not grok this, calculate offsets | |
46 | * offsets yourself and use them (or get a compatible compiler :-) | |
47 | */ | |
48 | ||
49 | #define REG_OFFSET(reg) (int)(&((struct i386_thread_state *)0)->reg) | |
50 | ||
51 | /* at reg_offset[i] is the offset to the i386_thread_state | |
52 | * location where the gdb registers[i] is stored. | |
53 | */ | |
54 | ||
c5aa993b | 55 | static int reg_offset[] = |
c906108c | 56 | { |
c5aa993b JM |
57 | REG_OFFSET (eax), REG_OFFSET (ecx), REG_OFFSET (edx), REG_OFFSET (ebx), |
58 | REG_OFFSET (uesp), REG_OFFSET (ebp), REG_OFFSET (esi), REG_OFFSET (edi), | |
59 | REG_OFFSET (eip), REG_OFFSET (efl), REG_OFFSET (cs), REG_OFFSET (ss), | |
60 | REG_OFFSET (ds), REG_OFFSET (es), REG_OFFSET (fs), REG_OFFSET (gs) | |
c906108c SS |
61 | }; |
62 | ||
63 | #define REG_ADDR(state,regnum) ((char *)(state)+reg_offset[regnum]) | |
64 | ||
65 | /* Fetch COUNT contiguous registers from thread STATE starting from REGNUM | |
66 | * Caller knows that the regs handled in one transaction are of same size. | |
67 | */ | |
68 | #define FETCH_REGS(state, regnum, count) \ | |
69 | memcpy (®isters[REGISTER_BYTE (regnum)], \ | |
70 | REG_ADDR (state, regnum), \ | |
71 | count * REGISTER_RAW_SIZE (regnum)) | |
72 | ||
73 | /* Store COUNT contiguous registers to thread STATE starting from REGNUM */ | |
74 | #define STORE_REGS(state, regnum, count) \ | |
75 | memcpy (REG_ADDR (state, regnum), \ | |
76 | ®isters[REGISTER_BYTE (regnum)], \ | |
77 | count * REGISTER_RAW_SIZE (regnum)) | |
78 | \f | |
79 | /* | |
80 | * Fetch inferiors registers for gdb. | |
81 | * REG specifies which (as gdb views it) register, -1 for all. | |
82 | */ | |
83 | void | |
84 | gnu_fetch_registers (int reg) | |
85 | { | |
86 | struct proc *thread; | |
87 | thread_state_t state; | |
c5aa993b JM |
88 | |
89 | inf_update_procs (current_inferior); /* Make sure we know about new threads. */ | |
c906108c SS |
90 | |
91 | thread = inf_tid_to_thread (current_inferior, inferior_pid); | |
c5aa993b | 92 | if (!thread) |
c906108c SS |
93 | error ("fetch inferior registers: %d: Invalid thread", inferior_pid); |
94 | ||
95 | state = proc_get_state (thread, 0); | |
96 | ||
c5aa993b | 97 | if (!state) |
c906108c SS |
98 | warning ("Couldn't fetch register %s from %s (invalid thread).", |
99 | REGISTER_NAME (reg), proc_string (thread)); | |
100 | else if (reg >= 0) | |
101 | { | |
102 | proc_debug (thread, "fetching register: %s", REGISTER_NAME (reg)); | |
c5aa993b | 103 | supply_register (reg, REG_ADDR (state, reg)); |
c906108c SS |
104 | thread->fetched_regs |= (1 << reg); |
105 | } | |
106 | else | |
107 | { | |
108 | proc_debug (thread, "fetching all registers"); | |
c5aa993b JM |
109 | for (reg = 0; reg < NUM_REGS; reg++) |
110 | supply_register (reg, REG_ADDR (state, reg)); | |
c906108c SS |
111 | thread->fetched_regs = ~0; |
112 | } | |
113 | } | |
114 | \f | |
115 | /* Store our register values back into the inferior. | |
116 | * If REG is -1, do this for all registers. | |
117 | * Otherwise, REG specifies which register | |
118 | * | |
119 | * On mach3 all registers are always saved in one call. | |
120 | */ | |
121 | void | |
122 | gnu_store_registers (reg) | |
123 | int reg; | |
124 | { | |
125 | struct proc *thread; | |
126 | int was_aborted, was_valid; | |
127 | thread_state_t state; | |
128 | thread_state_data_t old_state; | |
c5aa993b JM |
129 | |
130 | inf_update_procs (current_inferior); /* Make sure we know about new threads. */ | |
c906108c SS |
131 | |
132 | thread = inf_tid_to_thread (current_inferior, inferior_pid); | |
c5aa993b | 133 | if (!thread) |
c906108c SS |
134 | error ("store inferior registers: %d: Invalid thread", inferior_pid); |
135 | ||
136 | proc_debug (thread, "storing register %s.", REGISTER_NAME (reg)); | |
137 | ||
138 | was_aborted = thread->aborted; | |
139 | was_valid = thread->state_valid; | |
c5aa993b | 140 | if (!was_aborted && was_valid) |
c906108c SS |
141 | bcopy (&thread->state, &old_state, sizeof (old_state)); |
142 | ||
143 | state = proc_get_state (thread, 1); | |
144 | ||
c5aa993b | 145 | if (!state) |
c906108c SS |
146 | warning ("Couldn't store register %s from %s (invalid thread).", |
147 | REGISTER_NAME (reg), proc_string (thread)); | |
148 | else | |
149 | { | |
c5aa993b | 150 | if (!was_aborted && was_valid) |
c906108c SS |
151 | /* See which registers have changed after aborting the thread. */ |
152 | { | |
153 | int check_reg; | |
154 | for (check_reg = 0; check_reg < NUM_REGS; check_reg++) | |
155 | if ((thread->fetched_regs & (1 << check_reg)) | |
156 | && bcmp (REG_ADDR (&old_state, check_reg), | |
157 | REG_ADDR (state, check_reg), | |
158 | REGISTER_RAW_SIZE (check_reg))) | |
159 | /* Register CHECK_REG has changed! Ack! */ | |
160 | { | |
161 | warning ("Register %s changed after thread was aborted.", | |
162 | REGISTER_NAME (check_reg)); | |
163 | if (reg >= 0 && reg != check_reg) | |
164 | /* Update gdb's copy of the register. */ | |
165 | supply_register (check_reg, REG_ADDR (state, check_reg)); | |
166 | else | |
167 | warning ("... also writing this register! Suspicious..."); | |
168 | } | |
169 | } | |
170 | ||
171 | if (reg >= 0) | |
172 | { | |
173 | proc_debug (thread, "storing register: %s", REGISTER_NAME (reg)); | |
174 | STORE_REGS (state, reg, 1); | |
175 | } | |
176 | else | |
177 | { | |
178 | proc_debug (thread, "storing all registers"); | |
c5aa993b | 179 | for (reg = 0; reg < NUM_REGS; reg++) |
c906108c SS |
180 | STORE_REGS (state, reg, 1); |
181 | } | |
182 | } | |
183 | } | |
184 | \f | |
185 | /* jtv@hut.fi: I copied and modified this 387 code from | |
186 | * gdb/i386-xdep.c. Modifications for Mach 3.0. | |
187 | * | |
188 | * i387 status dumper. See also i387-tdep.c | |
189 | */ | |
c5aa993b | 190 | struct env387 |
c906108c SS |
191 | { |
192 | unsigned short control; | |
193 | unsigned short r0; | |
194 | unsigned short status; | |
195 | unsigned short r1; | |
196 | unsigned short tag; | |
197 | unsigned short r2; | |
198 | unsigned long eip; | |
199 | unsigned short code_seg; | |
200 | unsigned short opcode; | |
201 | unsigned long operand; | |
202 | unsigned short operand_seg; | |
203 | unsigned short r3; | |
204 | unsigned char regs[8][10]; | |
205 | }; | |
206 | /* This routine is machine independent? | |
207 | * Should move it to i387-tdep.c but you need to export struct env387 | |
208 | */ | |
209 | static | |
210 | print_387_status (status, ep) | |
211 | unsigned short status; | |
212 | struct env387 *ep; | |
213 | { | |
214 | int i; | |
215 | int bothstatus; | |
216 | int top; | |
217 | int fpreg; | |
218 | unsigned char *p; | |
c5aa993b | 219 | |
c906108c | 220 | bothstatus = ((status != 0) && (ep->status != 0)); |
c5aa993b | 221 | if (status != 0) |
c906108c SS |
222 | { |
223 | if (bothstatus) | |
224 | printf_unfiltered ("u: "); | |
225 | print_387_status_word (status); | |
226 | } | |
c5aa993b JM |
227 | |
228 | if (ep->status != 0) | |
c906108c SS |
229 | { |
230 | if (bothstatus) | |
231 | printf_unfiltered ("e: "); | |
232 | print_387_status_word (ep->status); | |
233 | } | |
c5aa993b | 234 | |
c906108c SS |
235 | print_387_control_word (ep->control); |
236 | printf_unfiltered ("last exception: "); | |
c5aa993b JM |
237 | printf_unfiltered ("opcode %s; ", local_hex_string (ep->opcode)); |
238 | printf_unfiltered ("pc %s:", local_hex_string (ep->code_seg)); | |
239 | printf_unfiltered ("%s; ", local_hex_string (ep->eip)); | |
240 | printf_unfiltered ("operand %s", local_hex_string (ep->operand_seg)); | |
241 | printf_unfiltered (":%s\n", local_hex_string (ep->operand)); | |
242 | ||
c906108c | 243 | top = (ep->status >> 11) & 7; |
c5aa993b | 244 | |
c906108c | 245 | printf_unfiltered ("regno tag msb lsb value\n"); |
c5aa993b | 246 | for (fpreg = 7; fpreg >= 0; fpreg--) |
c906108c SS |
247 | { |
248 | double val; | |
c5aa993b | 249 | |
c906108c | 250 | printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); |
c5aa993b JM |
251 | |
252 | switch ((ep->tag >> (fpreg * 2)) & 3) | |
c906108c | 253 | { |
c5aa993b JM |
254 | case 0: |
255 | printf_unfiltered ("valid "); | |
256 | break; | |
257 | case 1: | |
258 | printf_unfiltered ("zero "); | |
259 | break; | |
260 | case 2: | |
261 | printf_unfiltered ("trap "); | |
262 | break; | |
263 | case 3: | |
264 | printf_unfiltered ("empty "); | |
265 | break; | |
c906108c SS |
266 | } |
267 | for (i = 9; i >= 0; i--) | |
268 | printf_unfiltered ("%02x", ep->regs[fpreg][i]); | |
c5aa993b JM |
269 | |
270 | floatformat_to_double (&floatformat_i387_ext, (char *) ep->regs[fpreg], | |
271 | &val); | |
c906108c SS |
272 | printf_unfiltered (" %g\n", val); |
273 | } | |
274 | if (ep->r0) | |
c5aa993b | 275 | printf_unfiltered ("warning: reserved0 is %s\n", local_hex_string (ep->r0)); |
c906108c | 276 | if (ep->r1) |
c5aa993b | 277 | printf_unfiltered ("warning: reserved1 is %s\n", local_hex_string (ep->r1)); |
c906108c | 278 | if (ep->r2) |
c5aa993b | 279 | printf_unfiltered ("warning: reserved2 is %s\n", local_hex_string (ep->r2)); |
c906108c | 280 | if (ep->r3) |
c5aa993b | 281 | printf_unfiltered ("warning: reserved3 is %s\n", local_hex_string (ep->r3)); |
c906108c | 282 | } |
c5aa993b | 283 | |
c906108c SS |
284 | /* |
285 | * values that go into fp_kind (from <i386/fpreg.h>) | |
286 | */ | |
c5aa993b JM |
287 | #define FP_NO 0 /* no fp chip, no emulator (no fp support) */ |
288 | #define FP_SW 1 /* no fp chip, using software emulator */ | |
289 | #define FP_HW 2 /* chip present bit */ | |
290 | #define FP_287 2 /* 80287 chip present */ | |
291 | #define FP_387 3 /* 80387 chip present */ | |
c906108c | 292 | |
c5aa993b JM |
293 | typedef struct fpstate |
294 | { | |
c906108c | 295 | #if 1 |
c5aa993b | 296 | unsigned char state[FP_STATE_BYTES]; /* "hardware" state */ |
c906108c | 297 | #else |
c5aa993b | 298 | struct env387 state; /* Actually this */ |
c906108c | 299 | #endif |
c5aa993b JM |
300 | int status; /* Duplicate status */ |
301 | } | |
302 | *fpstate_t; | |
c906108c SS |
303 | |
304 | /* Mach 3 specific routines. | |
305 | */ | |
306 | static int | |
307 | get_i387_state (fstate) | |
308 | struct fpstate *fstate; | |
309 | { | |
310 | error_t err; | |
311 | thread_state_data_t state; | |
312 | unsigned int fsCnt = i386_FLOAT_STATE_COUNT; | |
313 | struct i386_float_state *fsp; | |
314 | struct proc *thread = inf_tid_to_thread (current_inferior, inferior_pid); | |
c5aa993b | 315 | |
c906108c SS |
316 | if (!thread) |
317 | error ("get_i387_state: Invalid thread"); | |
318 | ||
319 | proc_abort (thread, 0); /* Make sure THREAD's in a reasonable state. */ | |
320 | ||
321 | err = thread_get_state (thread->port, i386_FLOAT_STATE, state, &fsCnt); | |
322 | if (err) | |
323 | { | |
324 | warning ("Can not get live floating point state: %s", | |
325 | mach_error_string (err)); | |
326 | return 0; | |
327 | } | |
328 | ||
c5aa993b | 329 | fsp = (struct i386_float_state *) state; |
c906108c SS |
330 | /* The 387 chip (also 486 counts) or a software emulator? */ |
331 | if (!fsp->initialized || (fsp->fpkind != FP_387 && fsp->fpkind != FP_SW)) | |
332 | return 0; | |
333 | ||
334 | /* Clear the target then copy thread's float state there. | |
335 | Make a copy of the status word, for some reason? | |
336 | */ | |
337 | memset (fstate, 0, sizeof (struct fpstate)); | |
338 | ||
339 | fstate->status = fsp->exc_status; | |
340 | ||
c5aa993b | 341 | memcpy (fstate->state, (char *) &fsp->hw_state, FP_STATE_BYTES); |
c906108c SS |
342 | |
343 | return 1; | |
344 | } | |
345 | ||
346 | /* | |
347 | * This is called by "info float" command | |
348 | */ | |
349 | void | |
c5aa993b | 350 | i386_mach3_float_info () |
c906108c | 351 | { |
c5aa993b | 352 | char buf[sizeof (struct fpstate) + 2 * sizeof (int)]; |
c906108c SS |
353 | int valid = 0; |
354 | fpstate_t fps; | |
c5aa993b | 355 | |
c906108c SS |
356 | if (target_has_execution) |
357 | valid = get_i387_state (buf); | |
358 | ||
c5aa993b | 359 | if (!valid) |
c906108c SS |
360 | { |
361 | warning ("no floating point status saved"); | |
362 | return; | |
363 | } | |
c5aa993b | 364 | |
c906108c SS |
365 | fps = (fpstate_t) buf; |
366 | ||
c5aa993b | 367 | print_387_status (fps->status, (struct env387 *) fps->state); |
c906108c | 368 | } |