1e93f7393Sniklas /* Intel 387 floating point stuff.
2b725ae77Skettenis
3b725ae77Skettenis Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1998, 1999, 2000,
4b725ae77Skettenis 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
5e93f7393Sniklas
6e93f7393Sniklas This file is part of GDB.
7e93f7393Sniklas
8e93f7393Sniklas This program is free software; you can redistribute it and/or modify
9e93f7393Sniklas it under the terms of the GNU General Public License as published by
10e93f7393Sniklas the Free Software Foundation; either version 2 of the License, or
11e93f7393Sniklas (at your option) any later version.
12e93f7393Sniklas
13e93f7393Sniklas This program is distributed in the hope that it will be useful,
14e93f7393Sniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
15e93f7393Sniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16e93f7393Sniklas GNU General Public License for more details.
17e93f7393Sniklas
18e93f7393Sniklas You should have received a copy of the GNU General Public License
19e93f7393Sniklas along with this program; if not, write to the Free Software
20b725ae77Skettenis Foundation, Inc., 59 Temple Place - Suite 330,
21b725ae77Skettenis Boston, MA 02111-1307, USA. */
22e93f7393Sniklas
23e93f7393Sniklas #include "defs.h"
24b725ae77Skettenis #include "doublest.h"
25b725ae77Skettenis #include "floatformat.h"
26e93f7393Sniklas #include "frame.h"
27b725ae77Skettenis #include "gdbcore.h"
28e93f7393Sniklas #include "inferior.h"
29e93f7393Sniklas #include "language.h"
30b725ae77Skettenis #include "regcache.h"
31b725ae77Skettenis #include "value.h"
32e93f7393Sniklas
33b725ae77Skettenis #include "gdb_assert.h"
34b725ae77Skettenis #include "gdb_string.h"
35e93f7393Sniklas
36b725ae77Skettenis #include "i386-tdep.h"
37b725ae77Skettenis #include "i387-tdep.h"
38b725ae77Skettenis
39b725ae77Skettenis /* Implement the `info float' layout based on the register definitions
40b725ae77Skettenis in `tm-i386.h'. */
41b725ae77Skettenis
42b725ae77Skettenis /* Print the floating point number specified by RAW. */
43b725ae77Skettenis
44b725ae77Skettenis static void
print_i387_value(char * raw,struct ui_file * file)45b725ae77Skettenis print_i387_value (char *raw, struct ui_file *file)
46e93f7393Sniklas {
47b725ae77Skettenis DOUBLEST value;
48b725ae77Skettenis
49b725ae77Skettenis /* Using extract_typed_floating here might affect the representation
50b725ae77Skettenis of certain numbers such as NaNs, even if GDB is running natively.
51b725ae77Skettenis This is fine since our caller already detects such special
52b725ae77Skettenis numbers and we print the hexadecimal representation anyway. */
53b725ae77Skettenis value = extract_typed_floating (raw, builtin_type_i387_ext);
54b725ae77Skettenis
55b725ae77Skettenis /* We try to print 19 digits. The last digit may or may not contain
56b725ae77Skettenis garbage, but we'd better print one too many. We need enough room
57b725ae77Skettenis to print the value, 1 position for the sign, 1 for the decimal
58b725ae77Skettenis point, 19 for the digits and 6 for the exponent adds up to 27. */
59b725ae77Skettenis #ifdef PRINTF_HAS_LONG_DOUBLE
60b725ae77Skettenis fprintf_filtered (file, " %-+27.19Lg", (long double) value);
61b725ae77Skettenis #else
62b725ae77Skettenis fprintf_filtered (file, " %-+27.19g", (double) value);
63b725ae77Skettenis #endif
64e93f7393Sniklas }
65e93f7393Sniklas
66b725ae77Skettenis /* Print the classification for the register contents RAW. */
67b725ae77Skettenis
68b725ae77Skettenis static void
print_i387_ext(unsigned char * raw,struct ui_file * file)69b725ae77Skettenis print_i387_ext (unsigned char *raw, struct ui_file *file)
70e93f7393Sniklas {
71b725ae77Skettenis int sign;
72b725ae77Skettenis int integer;
73b725ae77Skettenis unsigned int exponent;
74b725ae77Skettenis unsigned long fraction[2];
75b725ae77Skettenis
76b725ae77Skettenis sign = raw[9] & 0x80;
77b725ae77Skettenis integer = raw[7] & 0x80;
78b725ae77Skettenis exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
79b725ae77Skettenis fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
80b725ae77Skettenis fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
81b725ae77Skettenis | (raw[5] << 8) | raw[4]);
82b725ae77Skettenis
83b725ae77Skettenis if (exponent == 0x7fff && integer)
84b725ae77Skettenis {
85b725ae77Skettenis if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000)
86b725ae77Skettenis /* Infinity. */
87b725ae77Skettenis fprintf_filtered (file, " %cInf", (sign ? '-' : '+'));
88b725ae77Skettenis else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000)
89b725ae77Skettenis /* Real Indefinite (QNaN). */
90b725ae77Skettenis fputs_unfiltered (" Real Indefinite (QNaN)", file);
91b725ae77Skettenis else if (fraction[1] & 0x40000000)
92b725ae77Skettenis /* QNaN. */
93b725ae77Skettenis fputs_filtered (" QNaN", file);
94b725ae77Skettenis else
95b725ae77Skettenis /* SNaN. */
96b725ae77Skettenis fputs_filtered (" SNaN", file);
97b725ae77Skettenis }
98b725ae77Skettenis else if (exponent < 0x7fff && exponent > 0x0000 && integer)
99b725ae77Skettenis /* Normal. */
100b725ae77Skettenis print_i387_value (raw, file);
101b725ae77Skettenis else if (exponent == 0x0000)
102b725ae77Skettenis {
103b725ae77Skettenis /* Denormal or zero. */
104b725ae77Skettenis print_i387_value (raw, file);
105b725ae77Skettenis
106b725ae77Skettenis if (integer)
107b725ae77Skettenis /* Pseudo-denormal. */
108b725ae77Skettenis fputs_filtered (" Pseudo-denormal", file);
109b725ae77Skettenis else if (fraction[0] || fraction[1])
110b725ae77Skettenis /* Denormal. */
111b725ae77Skettenis fputs_filtered (" Denormal", file);
112b725ae77Skettenis }
113b725ae77Skettenis else
114b725ae77Skettenis /* Unsupported. */
115b725ae77Skettenis fputs_filtered (" Unsupported", file);
116e93f7393Sniklas }
117e93f7393Sniklas
118b725ae77Skettenis /* Print the status word STATUS. */
119b725ae77Skettenis
120b725ae77Skettenis static void
print_i387_status_word(unsigned int status,struct ui_file * file)121b725ae77Skettenis print_i387_status_word (unsigned int status, struct ui_file *file)
122e93f7393Sniklas {
123b725ae77Skettenis fprintf_filtered (file, "Status Word: %s",
124*63addd46Skettenis hex_string_custom (status, 4));
125b725ae77Skettenis fputs_filtered (" ", file);
126b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0001) ? "IE" : " ");
127b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0002) ? "DE" : " ");
128b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0004) ? "ZE" : " ");
129b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0008) ? "OE" : " ");
130b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0010) ? "UE" : " ");
131b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0020) ? "PE" : " ");
132b725ae77Skettenis fputs_filtered (" ", file);
133b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0080) ? "ES" : " ");
134b725ae77Skettenis fputs_filtered (" ", file);
135b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0040) ? "SF" : " ");
136b725ae77Skettenis fputs_filtered (" ", file);
137b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0100) ? "C0" : " ");
138b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0200) ? "C1" : " ");
139b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x0400) ? "C2" : " ");
140b725ae77Skettenis fprintf_filtered (file, " %s", (status & 0x4000) ? "C3" : " ");
141b725ae77Skettenis
142b725ae77Skettenis fputs_filtered ("\n", file);
143b725ae77Skettenis
144b725ae77Skettenis fprintf_filtered (file,
145b725ae77Skettenis " TOP: %d\n", ((status >> 11) & 7));
146b725ae77Skettenis }
147b725ae77Skettenis
148b725ae77Skettenis /* Print the control word CONTROL. */
149b725ae77Skettenis
150b725ae77Skettenis static void
print_i387_control_word(unsigned int control,struct ui_file * file)151b725ae77Skettenis print_i387_control_word (unsigned int control, struct ui_file *file)
152b725ae77Skettenis {
153b725ae77Skettenis fprintf_filtered (file, "Control Word: %s",
154*63addd46Skettenis hex_string_custom (control, 4));
155b725ae77Skettenis fputs_filtered (" ", file);
156b725ae77Skettenis fprintf_filtered (file, " %s", (control & 0x0001) ? "IM" : " ");
157b725ae77Skettenis fprintf_filtered (file, " %s", (control & 0x0002) ? "DM" : " ");
158b725ae77Skettenis fprintf_filtered (file, " %s", (control & 0x0004) ? "ZM" : " ");
159b725ae77Skettenis fprintf_filtered (file, " %s", (control & 0x0008) ? "OM" : " ");
160b725ae77Skettenis fprintf_filtered (file, " %s", (control & 0x0010) ? "UM" : " ");
161b725ae77Skettenis fprintf_filtered (file, " %s", (control & 0x0020) ? "PM" : " ");
162b725ae77Skettenis
163b725ae77Skettenis fputs_filtered ("\n", file);
164b725ae77Skettenis
165b725ae77Skettenis fputs_filtered (" PC: ", file);
166e93f7393Sniklas switch ((control >> 8) & 3)
167e93f7393Sniklas {
168b725ae77Skettenis case 0:
169b725ae77Skettenis fputs_filtered ("Single Precision (24-bits)\n", file);
170b725ae77Skettenis break;
171b725ae77Skettenis case 1:
172b725ae77Skettenis fputs_filtered ("Reserved\n", file);
173b725ae77Skettenis break;
174b725ae77Skettenis case 2:
175b725ae77Skettenis fputs_filtered ("Double Precision (53-bits)\n", file);
176b725ae77Skettenis break;
177b725ae77Skettenis case 3:
178b725ae77Skettenis fputs_filtered ("Extended Precision (64-bits)\n", file);
179b725ae77Skettenis break;
180e93f7393Sniklas }
181b725ae77Skettenis
182b725ae77Skettenis fputs_filtered (" RC: ", file);
183e93f7393Sniklas switch ((control >> 10) & 3)
184e93f7393Sniklas {
185b725ae77Skettenis case 0:
186b725ae77Skettenis fputs_filtered ("Round to nearest\n", file);
187b725ae77Skettenis break;
188b725ae77Skettenis case 1:
189b725ae77Skettenis fputs_filtered ("Round down\n", file);
190b725ae77Skettenis break;
191b725ae77Skettenis case 2:
192b725ae77Skettenis fputs_filtered ("Round up\n", file);
193b725ae77Skettenis break;
194b725ae77Skettenis case 3:
195b725ae77Skettenis fputs_filtered ("Round toward zero\n", file);
196b725ae77Skettenis break;
197e93f7393Sniklas }
198e93f7393Sniklas }
199b725ae77Skettenis
200b725ae77Skettenis /* Print out the i387 floating point state. Note that we ignore FRAME
201b725ae77Skettenis in the code below. That's OK since floating-point registers are
202b725ae77Skettenis never saved on the stack. */
203e93f7393Sniklas
204e93f7393Sniklas void
i387_print_float_info(struct gdbarch * gdbarch,struct ui_file * file,struct frame_info * frame,const char * args)205b725ae77Skettenis i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
206b725ae77Skettenis struct frame_info *frame, const char *args)
207e93f7393Sniklas {
208b725ae77Skettenis struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
209b725ae77Skettenis char buf[4];
210b725ae77Skettenis ULONGEST fctrl;
211b725ae77Skettenis ULONGEST fstat;
212b725ae77Skettenis ULONGEST ftag;
213b725ae77Skettenis ULONGEST fiseg;
214b725ae77Skettenis ULONGEST fioff;
215b725ae77Skettenis ULONGEST foseg;
216b725ae77Skettenis ULONGEST fooff;
217b725ae77Skettenis ULONGEST fop;
218b725ae77Skettenis int fpreg;
219b725ae77Skettenis int top;
220e93f7393Sniklas
221b725ae77Skettenis gdb_assert (gdbarch == get_frame_arch (frame));
222b725ae77Skettenis
223b725ae77Skettenis /* Define I387_ST0_REGNUM such that we use the proper definitions
224b725ae77Skettenis for FRAME's architecture. */
225b725ae77Skettenis #define I387_ST0_REGNUM tdep->st0_regnum
226b725ae77Skettenis
227b725ae77Skettenis fctrl = get_frame_register_unsigned (frame, I387_FCTRL_REGNUM);
228b725ae77Skettenis fstat = get_frame_register_unsigned (frame, I387_FSTAT_REGNUM);
229b725ae77Skettenis ftag = get_frame_register_unsigned (frame, I387_FTAG_REGNUM);
230b725ae77Skettenis fiseg = get_frame_register_unsigned (frame, I387_FISEG_REGNUM);
231b725ae77Skettenis fioff = get_frame_register_unsigned (frame, I387_FIOFF_REGNUM);
232b725ae77Skettenis foseg = get_frame_register_unsigned (frame, I387_FOSEG_REGNUM);
233b725ae77Skettenis fooff = get_frame_register_unsigned (frame, I387_FOOFF_REGNUM);
234b725ae77Skettenis fop = get_frame_register_unsigned (frame, I387_FOP_REGNUM);
235b725ae77Skettenis
236b725ae77Skettenis top = ((fstat >> 11) & 7);
237b725ae77Skettenis
238b725ae77Skettenis for (fpreg = 7; fpreg >= 0; fpreg--)
239b725ae77Skettenis {
240b725ae77Skettenis unsigned char raw[I386_MAX_REGISTER_SIZE];
241b725ae77Skettenis int tag = (ftag >> (fpreg * 2)) & 3;
242b725ae77Skettenis int i;
243b725ae77Skettenis
244b725ae77Skettenis fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : " ", fpreg);
245b725ae77Skettenis
246b725ae77Skettenis switch (tag)
247b725ae77Skettenis {
248b725ae77Skettenis case 0:
249b725ae77Skettenis fputs_filtered ("Valid ", file);
250b725ae77Skettenis break;
251b725ae77Skettenis case 1:
252b725ae77Skettenis fputs_filtered ("Zero ", file);
253b725ae77Skettenis break;
254b725ae77Skettenis case 2:
255b725ae77Skettenis fputs_filtered ("Special ", file);
256b725ae77Skettenis break;
257b725ae77Skettenis case 3:
258b725ae77Skettenis fputs_filtered ("Empty ", file);
259b725ae77Skettenis break;
260b725ae77Skettenis }
261b725ae77Skettenis
262b725ae77Skettenis get_frame_register (frame, (fpreg + 8 - top) % 8 + I387_ST0_REGNUM, raw);
263b725ae77Skettenis
264b725ae77Skettenis fputs_filtered ("0x", file);
265b725ae77Skettenis for (i = 9; i >= 0; i--)
266b725ae77Skettenis fprintf_filtered (file, "%02x", raw[i]);
267b725ae77Skettenis
268b725ae77Skettenis if (tag != 3)
269b725ae77Skettenis print_i387_ext (raw, file);
270b725ae77Skettenis
271b725ae77Skettenis fputs_filtered ("\n", file);
272b725ae77Skettenis }
273b725ae77Skettenis
274b725ae77Skettenis fputs_filtered ("\n", file);
275b725ae77Skettenis
276b725ae77Skettenis print_i387_status_word (fstat, file);
277b725ae77Skettenis print_i387_control_word (fctrl, file);
278b725ae77Skettenis fprintf_filtered (file, "Tag Word: %s\n",
279*63addd46Skettenis hex_string_custom (ftag, 4));
280b725ae77Skettenis fprintf_filtered (file, "Instruction Pointer: %s:",
281*63addd46Skettenis hex_string_custom (fiseg, 2));
282*63addd46Skettenis fprintf_filtered (file, "%s\n", hex_string_custom (fioff, 8));
283b725ae77Skettenis fprintf_filtered (file, "Operand Pointer: %s:",
284*63addd46Skettenis hex_string_custom (foseg, 2));
285*63addd46Skettenis fprintf_filtered (file, "%s\n", hex_string_custom (fooff, 8));
286b725ae77Skettenis fprintf_filtered (file, "Opcode: %s\n",
287*63addd46Skettenis hex_string_custom (fop ? (fop | 0xd800) : 0, 4));
288b725ae77Skettenis
289b725ae77Skettenis #undef I387_ST0_REGNUM
290b725ae77Skettenis }
291b725ae77Skettenis
292b725ae77Skettenis
293b725ae77Skettenis /* Read a value of type TYPE from register REGNUM in frame FRAME, and
294b725ae77Skettenis return its contents in TO. */
295b725ae77Skettenis
296b725ae77Skettenis void
i387_register_to_value(struct frame_info * frame,int regnum,struct type * type,void * to)297b725ae77Skettenis i387_register_to_value (struct frame_info *frame, int regnum,
298b725ae77Skettenis struct type *type, void *to)
299b725ae77Skettenis {
300b725ae77Skettenis char from[I386_MAX_REGISTER_SIZE];
301b725ae77Skettenis
302b725ae77Skettenis gdb_assert (i386_fp_regnum_p (regnum));
303b725ae77Skettenis
304b725ae77Skettenis /* We only support floating-point values. */
305b725ae77Skettenis if (TYPE_CODE (type) != TYPE_CODE_FLT)
306b725ae77Skettenis {
307b725ae77Skettenis warning ("Cannot convert floating-point register value "
308b725ae77Skettenis "to non-floating-point type.");
309b725ae77Skettenis return;
310b725ae77Skettenis }
311b725ae77Skettenis
312b725ae77Skettenis /* Convert to TYPE. This should be a no-op if TYPE is equivalent to
313b725ae77Skettenis the extended floating-point format used by the FPU. */
314b725ae77Skettenis get_frame_register (frame, regnum, from);
315b725ae77Skettenis convert_typed_floating (from, builtin_type_i387_ext, to, type);
316b725ae77Skettenis }
317b725ae77Skettenis
318b725ae77Skettenis /* Write the contents FROM of a value of type TYPE into register
319b725ae77Skettenis REGNUM in frame FRAME. */
320b725ae77Skettenis
321b725ae77Skettenis void
i387_value_to_register(struct frame_info * frame,int regnum,struct type * type,const void * from)322b725ae77Skettenis i387_value_to_register (struct frame_info *frame, int regnum,
323b725ae77Skettenis struct type *type, const void *from)
324b725ae77Skettenis {
325b725ae77Skettenis char to[I386_MAX_REGISTER_SIZE];
326b725ae77Skettenis
327b725ae77Skettenis gdb_assert (i386_fp_regnum_p (regnum));
328b725ae77Skettenis
329b725ae77Skettenis /* We only support floating-point values. */
330b725ae77Skettenis if (TYPE_CODE (type) != TYPE_CODE_FLT)
331b725ae77Skettenis {
332b725ae77Skettenis warning ("Cannot convert non-floating-point type "
333b725ae77Skettenis "to floating-point register value.");
334b725ae77Skettenis return;
335b725ae77Skettenis }
336b725ae77Skettenis
337b725ae77Skettenis /* Convert from TYPE. This should be a no-op if TYPE is equivalent
338b725ae77Skettenis to the extended floating-point format used by the FPU. */
339b725ae77Skettenis convert_typed_floating (from, type, to, builtin_type_i387_ext);
340b725ae77Skettenis put_frame_register (frame, regnum, to);
341b725ae77Skettenis }
342b725ae77Skettenis
343b725ae77Skettenis
344b725ae77Skettenis /* Handle FSAVE and FXSAVE formats. */
345b725ae77Skettenis
346b725ae77Skettenis /* FIXME: kettenis/20030927: The functions below should accept a
347b725ae77Skettenis `regcache' argument, but I don't want to change the function
348b725ae77Skettenis signature just yet. There's some band-aid in the functions below
349b725ae77Skettenis in the form of the `regcache' local variables. This will ease the
350b725ae77Skettenis transition later on. */
351b725ae77Skettenis
352b725ae77Skettenis /* At fsave_offset[REGNUM] you'll find the offset to the location in
353b725ae77Skettenis the data structure used by the "fsave" instruction where GDB
354b725ae77Skettenis register REGNUM is stored. */
355b725ae77Skettenis
356b725ae77Skettenis static int fsave_offset[] =
357b725ae77Skettenis {
358b725ae77Skettenis 28 + 0 * 10, /* %st(0) ... */
359b725ae77Skettenis 28 + 1 * 10,
360b725ae77Skettenis 28 + 2 * 10,
361b725ae77Skettenis 28 + 3 * 10,
362b725ae77Skettenis 28 + 4 * 10,
363b725ae77Skettenis 28 + 5 * 10,
364b725ae77Skettenis 28 + 6 * 10,
365b725ae77Skettenis 28 + 7 * 10, /* ... %st(7). */
366b725ae77Skettenis 0, /* `fctrl' (16 bits). */
367b725ae77Skettenis 4, /* `fstat' (16 bits). */
368b725ae77Skettenis 8, /* `ftag' (16 bits). */
369b725ae77Skettenis 16, /* `fiseg' (16 bits). */
370b725ae77Skettenis 12, /* `fioff'. */
371b725ae77Skettenis 24, /* `foseg' (16 bits). */
372b725ae77Skettenis 20, /* `fooff'. */
373b725ae77Skettenis 18 /* `fop' (bottom 11 bits). */
374b725ae77Skettenis };
375b725ae77Skettenis
376b725ae77Skettenis #define FSAVE_ADDR(fsave, regnum) \
377b725ae77Skettenis (fsave + fsave_offset[regnum - I387_ST0_REGNUM])
378b725ae77Skettenis
379b725ae77Skettenis
380b725ae77Skettenis /* Fill register REGNUM in REGCACHE with the appropriate value from
381b725ae77Skettenis *FSAVE. This function masks off any of the reserved bits in
382b725ae77Skettenis *FSAVE. */
383b725ae77Skettenis
384b725ae77Skettenis void
i387_supply_fsave(struct regcache * regcache,int regnum,const void * fsave)385b725ae77Skettenis i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
386b725ae77Skettenis {
387b725ae77Skettenis struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
388b725ae77Skettenis const char *regs = fsave;
389b725ae77Skettenis int i;
390b725ae77Skettenis
391b725ae77Skettenis gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
392b725ae77Skettenis
393*63addd46Skettenis /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
394*63addd46Skettenis proper definitions for REGCACHE's architecture. */
395*63addd46Skettenis
396b725ae77Skettenis #define I387_ST0_REGNUM tdep->st0_regnum
397*63addd46Skettenis #define I387_NUM_XMM_REGS tdep->num_xmm_regs
398b725ae77Skettenis
399b725ae77Skettenis for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
400b725ae77Skettenis if (regnum == -1 || regnum == i)
401b725ae77Skettenis {
402b725ae77Skettenis if (fsave == NULL)
403b725ae77Skettenis {
404b725ae77Skettenis regcache_raw_supply (regcache, i, NULL);
405b725ae77Skettenis continue;
406b725ae77Skettenis }
407b725ae77Skettenis
408b725ae77Skettenis /* Most of the FPU control registers occupy only 16 bits in the
409b725ae77Skettenis fsave area. Give those a special treatment. */
410b725ae77Skettenis if (i >= I387_FCTRL_REGNUM
411b725ae77Skettenis && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
412b725ae77Skettenis {
413b725ae77Skettenis unsigned char val[4];
414b725ae77Skettenis
415b725ae77Skettenis memcpy (val, FSAVE_ADDR (regs, i), 2);
416b725ae77Skettenis val[2] = val[3] = 0;
417b725ae77Skettenis if (i == I387_FOP_REGNUM)
418b725ae77Skettenis val[1] &= ((1 << 3) - 1);
419b725ae77Skettenis regcache_raw_supply (regcache, i, val);
420b725ae77Skettenis }
421b725ae77Skettenis else
422b725ae77Skettenis regcache_raw_supply (regcache, i, FSAVE_ADDR (regs, i));
423b725ae77Skettenis }
424*63addd46Skettenis
425*63addd46Skettenis /* Provide dummy values for the SSE registers. */
426*63addd46Skettenis for (i = I387_XMM0_REGNUM; i < I387_MXCSR_REGNUM; i++)
427*63addd46Skettenis if (regnum == -1 || regnum == i)
428*63addd46Skettenis regcache_raw_supply (regcache, i, NULL);
429*63addd46Skettenis if (regnum == -1 || regnum == I387_MXCSR_REGNUM)
430*63addd46Skettenis {
431*63addd46Skettenis char buf[4];
432*63addd46Skettenis
433*63addd46Skettenis store_unsigned_integer (buf, 4, 0x1f80);
434*63addd46Skettenis regcache_raw_supply (regcache, I387_MXCSR_REGNUM, buf);
435*63addd46Skettenis }
436*63addd46Skettenis
437b725ae77Skettenis #undef I387_ST0_REGNUM
438*63addd46Skettenis #undef I387_NUM_XMM_REGS
439b725ae77Skettenis }
440b725ae77Skettenis
441b725ae77Skettenis /* Fill register REGNUM (if it is a floating-point register) in *FSAVE
442*63addd46Skettenis with the value from REGCACHE. If REGNUM is -1, do this for all
443*63addd46Skettenis registers. This function doesn't touch any of the reserved bits in
444*63addd46Skettenis *FSAVE. */
445b725ae77Skettenis
446b725ae77Skettenis void
i387_collect_fsave(const struct regcache * regcache,int regnum,void * fsave)447*63addd46Skettenis i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave)
448b725ae77Skettenis {
449b725ae77Skettenis struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
450b725ae77Skettenis char *regs = fsave;
451b725ae77Skettenis int i;
452b725ae77Skettenis
453b725ae77Skettenis gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
454b725ae77Skettenis
455b725ae77Skettenis /* Define I387_ST0_REGNUM such that we use the proper definitions
456b725ae77Skettenis for REGCACHE's architecture. */
457b725ae77Skettenis #define I387_ST0_REGNUM tdep->st0_regnum
458b725ae77Skettenis
459b725ae77Skettenis for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
460b725ae77Skettenis if (regnum == -1 || regnum == i)
461b725ae77Skettenis {
462b725ae77Skettenis /* Most of the FPU control registers occupy only 16 bits in
463b725ae77Skettenis the fsave area. Give those a special treatment. */
464b725ae77Skettenis if (i >= I387_FCTRL_REGNUM
465b725ae77Skettenis && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
466b725ae77Skettenis {
467b725ae77Skettenis unsigned char buf[4];
468b725ae77Skettenis
469b725ae77Skettenis regcache_raw_collect (regcache, i, buf);
470b725ae77Skettenis
471b725ae77Skettenis if (i == I387_FOP_REGNUM)
472b725ae77Skettenis {
473b725ae77Skettenis /* The opcode occupies only 11 bits. Make sure we
474b725ae77Skettenis don't touch the other bits. */
475b725ae77Skettenis buf[1] &= ((1 << 3) - 1);
476b725ae77Skettenis buf[1] |= ((FSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1));
477b725ae77Skettenis }
478b725ae77Skettenis memcpy (FSAVE_ADDR (regs, i), buf, 2);
479b725ae77Skettenis }
480b725ae77Skettenis else
481b725ae77Skettenis regcache_raw_collect (regcache, i, FSAVE_ADDR (regs, i));
482b725ae77Skettenis }
483b725ae77Skettenis #undef I387_ST0_REGNUM
484b725ae77Skettenis }
485*63addd46Skettenis
486*63addd46Skettenis /* Fill register REGNUM (if it is a floating-point register) in *FSAVE
487*63addd46Skettenis with the value in GDB's register cache. If REGNUM is -1, do this
488*63addd46Skettenis for all registers. This function doesn't touch any of the reserved
489*63addd46Skettenis bits in *FSAVE. */
490*63addd46Skettenis
491*63addd46Skettenis void
i387_fill_fsave(void * fsave,int regnum)492*63addd46Skettenis i387_fill_fsave (void *fsave, int regnum)
493*63addd46Skettenis {
494*63addd46Skettenis i387_collect_fsave (current_regcache, regnum, fsave);
495*63addd46Skettenis }
496b725ae77Skettenis
497b725ae77Skettenis
498b725ae77Skettenis /* At fxsave_offset[REGNUM] you'll find the offset to the location in
499b725ae77Skettenis the data structure used by the "fxsave" instruction where GDB
500b725ae77Skettenis register REGNUM is stored. */
501b725ae77Skettenis
502b725ae77Skettenis static int fxsave_offset[] =
503b725ae77Skettenis {
504b725ae77Skettenis 32, /* %st(0) through ... */
505b725ae77Skettenis 48,
506b725ae77Skettenis 64,
507b725ae77Skettenis 80,
508b725ae77Skettenis 96,
509b725ae77Skettenis 112,
510b725ae77Skettenis 128,
511b725ae77Skettenis 144, /* ... %st(7) (80 bits each). */
512b725ae77Skettenis 0, /* `fctrl' (16 bits). */
513b725ae77Skettenis 2, /* `fstat' (16 bits). */
514b725ae77Skettenis 4, /* `ftag' (16 bits). */
515b725ae77Skettenis 12, /* `fiseg' (16 bits). */
516b725ae77Skettenis 8, /* `fioff'. */
517b725ae77Skettenis 20, /* `foseg' (16 bits). */
518b725ae77Skettenis 16, /* `fooff'. */
519b725ae77Skettenis 6, /* `fop' (bottom 11 bits). */
520b725ae77Skettenis 160 + 0 * 16, /* %xmm0 through ... */
521b725ae77Skettenis 160 + 1 * 16,
522b725ae77Skettenis 160 + 2 * 16,
523b725ae77Skettenis 160 + 3 * 16,
524b725ae77Skettenis 160 + 4 * 16,
525b725ae77Skettenis 160 + 5 * 16,
526b725ae77Skettenis 160 + 6 * 16,
527b725ae77Skettenis 160 + 7 * 16,
528b725ae77Skettenis 160 + 8 * 16,
529b725ae77Skettenis 160 + 9 * 16,
530b725ae77Skettenis 160 + 10 * 16,
531b725ae77Skettenis 160 + 11 * 16,
532b725ae77Skettenis 160 + 12 * 16,
533b725ae77Skettenis 160 + 13 * 16,
534b725ae77Skettenis 160 + 14 * 16,
535b725ae77Skettenis 160 + 15 * 16, /* ... %xmm15 (128 bits each). */
536b725ae77Skettenis };
537b725ae77Skettenis
538b725ae77Skettenis #define FXSAVE_ADDR(fxsave, regnum) \
539b725ae77Skettenis (fxsave + fxsave_offset[regnum - I387_ST0_REGNUM])
540b725ae77Skettenis
541b725ae77Skettenis /* We made an unfortunate choice in putting %mxcsr after the SSE
542b725ae77Skettenis registers %xmm0-%xmm7 instead of before, since it makes supporting
543b725ae77Skettenis the registers %xmm8-%xmm15 on AMD64 a bit involved. Therefore we
544b725ae77Skettenis don't include the offset for %mxcsr here above. */
545b725ae77Skettenis
546b725ae77Skettenis #define FXSAVE_MXCSR_ADDR(fxsave) (fxsave + 24)
547b725ae77Skettenis
548b725ae77Skettenis static int i387_tag (const unsigned char *raw);
549b725ae77Skettenis
550b725ae77Skettenis
551b725ae77Skettenis /* Fill register REGNUM in REGCACHE with the appropriate
552b725ae77Skettenis floating-point or SSE register value from *FXSAVE. This function
553b725ae77Skettenis masks off any of the reserved bits in *FXSAVE. */
554b725ae77Skettenis
555b725ae77Skettenis void
i387_supply_fxsave(struct regcache * regcache,int regnum,const void * fxsave)556b725ae77Skettenis i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
557b725ae77Skettenis {
558b725ae77Skettenis struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
559b725ae77Skettenis const char *regs = fxsave;
560b725ae77Skettenis int i;
561b725ae77Skettenis
562b725ae77Skettenis gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
563b725ae77Skettenis gdb_assert (tdep->num_xmm_regs > 0);
564b725ae77Skettenis
565b725ae77Skettenis /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
566b725ae77Skettenis proper definitions for REGCACHE's architecture. */
567b725ae77Skettenis
568b725ae77Skettenis #define I387_ST0_REGNUM tdep->st0_regnum
569b725ae77Skettenis #define I387_NUM_XMM_REGS tdep->num_xmm_regs
570b725ae77Skettenis
571b725ae77Skettenis for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
572b725ae77Skettenis if (regnum == -1 || regnum == i)
573b725ae77Skettenis {
574b725ae77Skettenis if (regs == NULL)
575b725ae77Skettenis {
576b725ae77Skettenis regcache_raw_supply (regcache, i, NULL);
577b725ae77Skettenis continue;
578b725ae77Skettenis }
579b725ae77Skettenis
580b725ae77Skettenis /* Most of the FPU control registers occupy only 16 bits in
581b725ae77Skettenis the fxsave area. Give those a special treatment. */
582b725ae77Skettenis if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
583b725ae77Skettenis && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
584b725ae77Skettenis {
585b725ae77Skettenis unsigned char val[4];
586b725ae77Skettenis
587b725ae77Skettenis memcpy (val, FXSAVE_ADDR (regs, i), 2);
588b725ae77Skettenis val[2] = val[3] = 0;
589b725ae77Skettenis if (i == I387_FOP_REGNUM)
590b725ae77Skettenis val[1] &= ((1 << 3) - 1);
591b725ae77Skettenis else if (i== I387_FTAG_REGNUM)
592b725ae77Skettenis {
593b725ae77Skettenis /* The fxsave area contains a simplified version of
594b725ae77Skettenis the tag word. We have to look at the actual 80-bit
595b725ae77Skettenis FP data to recreate the traditional i387 tag word. */
596b725ae77Skettenis
597b725ae77Skettenis unsigned long ftag = 0;
598b725ae77Skettenis int fpreg;
599b725ae77Skettenis int top;
600b725ae77Skettenis
601b725ae77Skettenis top = ((FXSAVE_ADDR (regs, I387_FSTAT_REGNUM))[1] >> 3);
602b725ae77Skettenis top &= 0x7;
603b725ae77Skettenis
604b725ae77Skettenis for (fpreg = 7; fpreg >= 0; fpreg--)
605b725ae77Skettenis {
606b725ae77Skettenis int tag;
607b725ae77Skettenis
608b725ae77Skettenis if (val[0] & (1 << fpreg))
609b725ae77Skettenis {
610b725ae77Skettenis int regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM;
611b725ae77Skettenis tag = i387_tag (FXSAVE_ADDR (regs, regnum));
612b725ae77Skettenis }
613b725ae77Skettenis else
614b725ae77Skettenis tag = 3; /* Empty */
615b725ae77Skettenis
616b725ae77Skettenis ftag |= tag << (2 * fpreg);
617b725ae77Skettenis }
618b725ae77Skettenis val[0] = ftag & 0xff;
619b725ae77Skettenis val[1] = (ftag >> 8) & 0xff;
620b725ae77Skettenis }
621b725ae77Skettenis regcache_raw_supply (regcache, i, val);
622b725ae77Skettenis }
623b725ae77Skettenis else
624b725ae77Skettenis regcache_raw_supply (regcache, i, FXSAVE_ADDR (regs, i));
625b725ae77Skettenis }
626b725ae77Skettenis
627b725ae77Skettenis if (regnum == I387_MXCSR_REGNUM || regnum == -1)
628b725ae77Skettenis {
629b725ae77Skettenis if (regs == NULL)
630b725ae77Skettenis regcache_raw_supply (regcache, I387_MXCSR_REGNUM, NULL);
631b725ae77Skettenis else
632b725ae77Skettenis regcache_raw_supply (regcache, I387_MXCSR_REGNUM,
633b725ae77Skettenis FXSAVE_MXCSR_ADDR (regs));
634b725ae77Skettenis }
635b725ae77Skettenis
636b725ae77Skettenis #undef I387_ST0_REGNUM
637b725ae77Skettenis #undef I387_NUM_XMM_REGS
638b725ae77Skettenis }
639b725ae77Skettenis
640b725ae77Skettenis /* Fill register REGNUM (if it is a floating-point or SSE register) in
641b725ae77Skettenis *FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for
642b725ae77Skettenis all registers. This function doesn't touch any of the reserved
643b725ae77Skettenis bits in *FXSAVE. */
644b725ae77Skettenis
645b725ae77Skettenis void
i387_collect_fxsave(const struct regcache * regcache,int regnum,void * fxsave)646b725ae77Skettenis i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave)
647b725ae77Skettenis {
648b725ae77Skettenis struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
649b725ae77Skettenis char *regs = fxsave;
650b725ae77Skettenis int i;
651b725ae77Skettenis
652b725ae77Skettenis gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
653b725ae77Skettenis gdb_assert (tdep->num_xmm_regs > 0);
654b725ae77Skettenis
655b725ae77Skettenis /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
656b725ae77Skettenis proper definitions for REGCACHE's architecture. */
657b725ae77Skettenis
658b725ae77Skettenis #define I387_ST0_REGNUM tdep->st0_regnum
659b725ae77Skettenis #define I387_NUM_XMM_REGS tdep->num_xmm_regs
660b725ae77Skettenis
661b725ae77Skettenis for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
662b725ae77Skettenis if (regnum == -1 || regnum == i)
663b725ae77Skettenis {
664b725ae77Skettenis /* Most of the FPU control registers occupy only 16 bits in
665b725ae77Skettenis the fxsave area. Give those a special treatment. */
666b725ae77Skettenis if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
667b725ae77Skettenis && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
668b725ae77Skettenis {
669b725ae77Skettenis unsigned char buf[4];
670b725ae77Skettenis
671b725ae77Skettenis regcache_raw_collect (regcache, i, buf);
672b725ae77Skettenis
673b725ae77Skettenis if (i == I387_FOP_REGNUM)
674b725ae77Skettenis {
675b725ae77Skettenis /* The opcode occupies only 11 bits. Make sure we
676b725ae77Skettenis don't touch the other bits. */
677b725ae77Skettenis buf[1] &= ((1 << 3) - 1);
678b725ae77Skettenis buf[1] |= ((FXSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1));
679b725ae77Skettenis }
680b725ae77Skettenis else if (i == I387_FTAG_REGNUM)
681b725ae77Skettenis {
682b725ae77Skettenis /* Converting back is much easier. */
683b725ae77Skettenis
684b725ae77Skettenis unsigned short ftag;
685b725ae77Skettenis int fpreg;
686b725ae77Skettenis
687b725ae77Skettenis ftag = (buf[1] << 8) | buf[0];
688b725ae77Skettenis buf[0] = 0;
689b725ae77Skettenis buf[1] = 0;
690b725ae77Skettenis
691b725ae77Skettenis for (fpreg = 7; fpreg >= 0; fpreg--)
692b725ae77Skettenis {
693b725ae77Skettenis int tag = (ftag >> (fpreg * 2)) & 3;
694b725ae77Skettenis
695b725ae77Skettenis if (tag != 3)
696b725ae77Skettenis buf[0] |= (1 << fpreg);
697b725ae77Skettenis }
698b725ae77Skettenis }
699b725ae77Skettenis memcpy (FXSAVE_ADDR (regs, i), buf, 2);
700b725ae77Skettenis }
701b725ae77Skettenis else
702b725ae77Skettenis regcache_raw_collect (regcache, i, FXSAVE_ADDR (regs, i));
703b725ae77Skettenis }
704b725ae77Skettenis
705b725ae77Skettenis if (regnum == I387_MXCSR_REGNUM || regnum == -1)
706b725ae77Skettenis regcache_raw_collect (regcache, I387_MXCSR_REGNUM,
707b725ae77Skettenis FXSAVE_MXCSR_ADDR (regs));
708b725ae77Skettenis
709b725ae77Skettenis #undef I387_ST0_REGNUM
710b725ae77Skettenis #undef I387_NUM_XMM_REGS
711b725ae77Skettenis }
712b725ae77Skettenis
713b725ae77Skettenis /* Fill register REGNUM (if it is a floating-point or SSE register) in
714b725ae77Skettenis *FXSAVE with the value in GDB's register cache. If REGNUM is -1, do
715b725ae77Skettenis this for all registers. This function doesn't touch any of the
716b725ae77Skettenis reserved bits in *FXSAVE. */
717b725ae77Skettenis
718b725ae77Skettenis void
i387_fill_fxsave(void * fxsave,int regnum)719b725ae77Skettenis i387_fill_fxsave (void *fxsave, int regnum)
720b725ae77Skettenis {
721b725ae77Skettenis i387_collect_fxsave (current_regcache, regnum, fxsave);
722b725ae77Skettenis }
723b725ae77Skettenis
724b725ae77Skettenis /* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
725b725ae77Skettenis *RAW. */
726b725ae77Skettenis
727b725ae77Skettenis static int
i387_tag(const unsigned char * raw)728b725ae77Skettenis i387_tag (const unsigned char *raw)
729b725ae77Skettenis {
730b725ae77Skettenis int integer;
731b725ae77Skettenis unsigned int exponent;
732b725ae77Skettenis unsigned long fraction[2];
733b725ae77Skettenis
734b725ae77Skettenis integer = raw[7] & 0x80;
735b725ae77Skettenis exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
736b725ae77Skettenis fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
737b725ae77Skettenis fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
738b725ae77Skettenis | (raw[5] << 8) | raw[4]);
739b725ae77Skettenis
740b725ae77Skettenis if (exponent == 0x7fff)
741b725ae77Skettenis {
742b725ae77Skettenis /* Special. */
743b725ae77Skettenis return (2);
744b725ae77Skettenis }
745b725ae77Skettenis else if (exponent == 0x0000)
746b725ae77Skettenis {
747b725ae77Skettenis if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
748b725ae77Skettenis {
749b725ae77Skettenis /* Zero. */
750b725ae77Skettenis return (1);
751b725ae77Skettenis }
752b725ae77Skettenis else
753b725ae77Skettenis {
754b725ae77Skettenis /* Special. */
755b725ae77Skettenis return (2);
756b725ae77Skettenis }
757b725ae77Skettenis }
758b725ae77Skettenis else
759b725ae77Skettenis {
760b725ae77Skettenis if (integer)
761b725ae77Skettenis {
762b725ae77Skettenis /* Valid. */
763b725ae77Skettenis return (0);
764b725ae77Skettenis }
765b725ae77Skettenis else
766b725ae77Skettenis {
767b725ae77Skettenis /* Special. */
768b725ae77Skettenis return (2);
769b725ae77Skettenis }
770b725ae77Skettenis }
771b725ae77Skettenis }
772b725ae77Skettenis
773b725ae77Skettenis /* Prepare the FPU stack in REGCACHE for a function return. */
774b725ae77Skettenis
775b725ae77Skettenis void
i387_return_value(struct gdbarch * gdbarch,struct regcache * regcache)776b725ae77Skettenis i387_return_value (struct gdbarch *gdbarch, struct regcache *regcache)
777b725ae77Skettenis {
778b725ae77Skettenis struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
779b725ae77Skettenis ULONGEST fstat;
780b725ae77Skettenis
781b725ae77Skettenis /* Define I387_ST0_REGNUM such that we use the proper
782b725ae77Skettenis definitions for the architecture. */
783b725ae77Skettenis #define I387_ST0_REGNUM tdep->st0_regnum
784b725ae77Skettenis
785b725ae77Skettenis /* Set the top of the floating-point register stack to 7. The
786b725ae77Skettenis actual value doesn't really matter, but 7 is what a normal
787b725ae77Skettenis function return would end up with if the program started out with
788b725ae77Skettenis a freshly initialized FPU. */
789b725ae77Skettenis regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
790b725ae77Skettenis fstat |= (7 << 11);
791b725ae77Skettenis regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM, fstat);
792b725ae77Skettenis
793b725ae77Skettenis /* Mark %st(1) through %st(7) as empty. Since we set the top of the
794b725ae77Skettenis floating-point register stack to 7, the appropriate value for the
795b725ae77Skettenis tag word is 0x3fff. */
796b725ae77Skettenis regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM, 0x3fff);
797b725ae77Skettenis
798b725ae77Skettenis #undef I387_ST0_REGNUM
799e93f7393Sniklas }
800