198944Sobrien/* i387-specific utility functions, for the remote server for GDB. 298944Sobrien Copyright 2000, 2001, 2002 398944Sobrien Free Software Foundation, Inc. 498944Sobrien 598944Sobrien This file is part of GDB. 698944Sobrien 798944Sobrien This program is free software; you can redistribute it and/or modify 898944Sobrien it under the terms of the GNU General Public License as published by 998944Sobrien the Free Software Foundation; either version 2 of the License, or 1098944Sobrien (at your option) any later version. 1198944Sobrien 1298944Sobrien This program is distributed in the hope that it will be useful, 1398944Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1498944Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1598944Sobrien GNU General Public License for more details. 1698944Sobrien 1798944Sobrien You should have received a copy of the GNU General Public License 1898944Sobrien along with this program; if not, write to the Free Software 1998944Sobrien Foundation, Inc., 59 Temple Place - Suite 330, 2098944Sobrien Boston, MA 02111-1307, USA. */ 2198944Sobrien 2298944Sobrien#include "server.h" 23130803Smarcel#include "i387-fp.h" 2498944Sobrien 2598944Sobrienint num_xmm_registers = 8; 2698944Sobrien 2798944Sobrien/* Note: These functions preserve the reserved bits in control registers. 2898944Sobrien However, gdbserver promptly throws away that information. */ 2998944Sobrien 3098944Sobrien/* These structs should have the proper sizes and alignment on both 3198944Sobrien i386 and x86-64 machines. */ 3298944Sobrien 3398944Sobrienstruct i387_fsave { 3498944Sobrien /* All these are only sixteen bits, plus padding, except for fop (which 3598944Sobrien is only eleven bits), and fooff / fioff (which are 32 bits each). */ 3698944Sobrien unsigned int fctrl; 3798944Sobrien unsigned int fstat; 3898944Sobrien unsigned int ftag; 3998944Sobrien unsigned int fioff; 4098944Sobrien unsigned short fiseg; 4198944Sobrien unsigned short fop; 4298944Sobrien unsigned int fooff; 4398944Sobrien unsigned int foseg; 4498944Sobrien 4598944Sobrien /* Space for eight 80-bit FP values. */ 4698944Sobrien char st_space[80]; 4798944Sobrien}; 4898944Sobrien 4998944Sobrienstruct i387_fxsave { 5098944Sobrien /* All these are only sixteen bits, plus padding, except for fop (which 5198944Sobrien is only eleven bits), and fooff / fioff (which are 32 bits each). */ 5298944Sobrien unsigned short fctrl; 5398944Sobrien unsigned short fstat; 5498944Sobrien unsigned short ftag; 5598944Sobrien unsigned short fop; 5698944Sobrien unsigned int fioff; 5798944Sobrien unsigned int fiseg; 5898944Sobrien unsigned int fooff; 5998944Sobrien unsigned int foseg; 6098944Sobrien 6198944Sobrien unsigned int mxcsr; 6298944Sobrien 6398944Sobrien unsigned int _pad1; 6498944Sobrien 6598944Sobrien /* Space for eight 80-bit FP values in 128-bit spaces. */ 6698944Sobrien char st_space[128]; 6798944Sobrien 6898944Sobrien /* Space for eight 128-bit XMM values, or 16 on x86-64. */ 6998944Sobrien char xmm_space[256]; 7098944Sobrien}; 7198944Sobrien 7298944Sobrienvoid 7398944Sobrieni387_cache_to_fsave (void *buf) 7498944Sobrien{ 7598944Sobrien struct i387_fsave *fp = (struct i387_fsave *) buf; 7698944Sobrien int i; 7798944Sobrien int st0_regnum = find_regno ("st0"); 7898944Sobrien unsigned long val, val2; 7998944Sobrien 8098944Sobrien for (i = 0; i < 8; i++) 8198944Sobrien collect_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 10); 8298944Sobrien 8398944Sobrien collect_register_by_name ("fioff", &fp->fioff); 8498944Sobrien collect_register_by_name ("fooff", &fp->fooff); 8598944Sobrien 8698944Sobrien /* This one's 11 bits... */ 8798944Sobrien collect_register_by_name ("fop", &val2); 8898944Sobrien fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800); 8998944Sobrien 9098944Sobrien /* Some registers are 16-bit. */ 9198944Sobrien collect_register_by_name ("fctrl", &val); 9298944Sobrien *(unsigned short *) &fp->fctrl = val; 9398944Sobrien 9498944Sobrien collect_register_by_name ("fstat", &val); 9598944Sobrien val &= 0xFFFF; 9698944Sobrien *(unsigned short *) &fp->fstat = val; 9798944Sobrien 9898944Sobrien collect_register_by_name ("ftag", &val); 9998944Sobrien val &= 0xFFFF; 10098944Sobrien *(unsigned short *) &fp->ftag = val; 10198944Sobrien 10298944Sobrien collect_register_by_name ("fiseg", &val); 10398944Sobrien val &= 0xFFFF; 10498944Sobrien *(unsigned short *) &fp->fiseg = val; 10598944Sobrien 10698944Sobrien collect_register_by_name ("foseg", &val); 10798944Sobrien val &= 0xFFFF; 10898944Sobrien *(unsigned short *) &fp->foseg = val; 10998944Sobrien} 11098944Sobrien 11198944Sobrienvoid 112130803Smarceli387_fsave_to_cache (const void *buf) 11398944Sobrien{ 11498944Sobrien struct i387_fsave *fp = (struct i387_fsave *) buf; 11598944Sobrien int i; 11698944Sobrien int st0_regnum = find_regno ("st0"); 11798944Sobrien unsigned long val; 11898944Sobrien 11998944Sobrien for (i = 0; i < 8; i++) 12098944Sobrien supply_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 10); 12198944Sobrien 12298944Sobrien supply_register_by_name ("fioff", &fp->fioff); 12398944Sobrien supply_register_by_name ("fooff", &fp->fooff); 12498944Sobrien 12598944Sobrien /* Some registers are 16-bit. */ 12698944Sobrien val = fp->fctrl & 0xFFFF; 12798944Sobrien supply_register_by_name ("fctrl", &val); 12898944Sobrien 12998944Sobrien val = fp->fstat & 0xFFFF; 13098944Sobrien supply_register_by_name ("fstat", &val); 13198944Sobrien 13298944Sobrien val = fp->ftag & 0xFFFF; 13398944Sobrien supply_register_by_name ("ftag", &val); 13498944Sobrien 13598944Sobrien val = fp->fiseg & 0xFFFF; 13698944Sobrien supply_register_by_name ("fiseg", &val); 13798944Sobrien 13898944Sobrien val = fp->foseg & 0xFFFF; 13998944Sobrien supply_register_by_name ("foseg", &val); 14098944Sobrien 14198944Sobrien val = (fp->fop) & 0x7FF; 14298944Sobrien supply_register_by_name ("fop", &val); 14398944Sobrien} 14498944Sobrien 14598944Sobrienvoid 14698944Sobrieni387_cache_to_fxsave (void *buf) 14798944Sobrien{ 14898944Sobrien struct i387_fxsave *fp = (struct i387_fxsave *) buf; 14998944Sobrien int i; 15098944Sobrien int st0_regnum = find_regno ("st0"); 15198944Sobrien int xmm0_regnum = find_regno ("xmm0"); 15298944Sobrien unsigned long val, val2; 15398944Sobrien 15498944Sobrien for (i = 0; i < 8; i++) 15598944Sobrien collect_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 16); 15698944Sobrien for (i = 0; i < num_xmm_registers; i++) 15798944Sobrien collect_register (i + xmm0_regnum, ((char *) &fp->xmm_space[0]) + i * 16); 15898944Sobrien 15998944Sobrien collect_register_by_name ("fioff", &fp->fioff); 16098944Sobrien collect_register_by_name ("fooff", &fp->fooff); 16198944Sobrien collect_register_by_name ("mxcsr", &fp->mxcsr); 16298944Sobrien 16398944Sobrien /* This one's 11 bits... */ 16498944Sobrien collect_register_by_name ("fop", &val2); 16598944Sobrien fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800); 16698944Sobrien 16798944Sobrien /* Some registers are 16-bit. */ 16898944Sobrien collect_register_by_name ("fctrl", &val); 16998944Sobrien *(unsigned short *) &fp->fctrl = val; 17098944Sobrien 17198944Sobrien collect_register_by_name ("fstat", &val); 17298944Sobrien val &= 0xFFFF; 17398944Sobrien *(unsigned short *) &fp->fstat = val; 17498944Sobrien 17598944Sobrien /* Convert to the simplifed tag form stored in fxsave data. */ 17698944Sobrien collect_register_by_name ("ftag", &val); 17798944Sobrien val &= 0xFFFF; 17898944Sobrien for (i = 7; i >= 0; i--) 17998944Sobrien { 18098944Sobrien int tag = (val >> (i * 2)) & 3; 18198944Sobrien 18298944Sobrien if (tag != 3) 18398944Sobrien val2 |= (1 << i); 18498944Sobrien } 18598944Sobrien *(unsigned short *) &fp->ftag = val2; 18698944Sobrien 18798944Sobrien collect_register_by_name ("fiseg", &val); 18898944Sobrien val &= 0xFFFF; 18998944Sobrien *(unsigned short *) &fp->fiseg = val; 19098944Sobrien 19198944Sobrien collect_register_by_name ("foseg", &val); 19298944Sobrien val &= 0xFFFF; 19398944Sobrien *(unsigned short *) &fp->foseg = val; 19498944Sobrien} 19598944Sobrien 19698944Sobrienstatic int 19798944Sobrieni387_ftag (struct i387_fxsave *fp, int regno) 19898944Sobrien{ 19998944Sobrien unsigned char *raw = &fp->st_space[regno * 16]; 20098944Sobrien unsigned int exponent; 20198944Sobrien unsigned long fraction[2]; 20298944Sobrien int integer; 20398944Sobrien 20498944Sobrien integer = raw[7] & 0x80; 20598944Sobrien exponent = (((raw[9] & 0x7f) << 8) | raw[8]); 20698944Sobrien fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]); 20798944Sobrien fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16) 20898944Sobrien | (raw[5] << 8) | raw[4]); 20998944Sobrien 21098944Sobrien if (exponent == 0x7fff) 21198944Sobrien { 21298944Sobrien /* Special. */ 21398944Sobrien return (2); 21498944Sobrien } 21598944Sobrien else if (exponent == 0x0000) 21698944Sobrien { 21798944Sobrien if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer) 21898944Sobrien { 21998944Sobrien /* Zero. */ 22098944Sobrien return (1); 22198944Sobrien } 22298944Sobrien else 22398944Sobrien { 22498944Sobrien /* Special. */ 22598944Sobrien return (2); 22698944Sobrien } 22798944Sobrien } 22898944Sobrien else 22998944Sobrien { 23098944Sobrien if (integer) 23198944Sobrien { 23298944Sobrien /* Valid. */ 23398944Sobrien return (0); 23498944Sobrien } 23598944Sobrien else 23698944Sobrien { 23798944Sobrien /* Special. */ 23898944Sobrien return (2); 23998944Sobrien } 24098944Sobrien } 24198944Sobrien} 24298944Sobrien 24398944Sobrienvoid 244130803Smarceli387_fxsave_to_cache (const void *buf) 24598944Sobrien{ 24698944Sobrien struct i387_fxsave *fp = (struct i387_fxsave *) buf; 24798944Sobrien int i, top; 24898944Sobrien int st0_regnum = find_regno ("st0"); 24998944Sobrien int xmm0_regnum = find_regno ("xmm0"); 25098944Sobrien unsigned long val; 25198944Sobrien 25298944Sobrien for (i = 0; i < 8; i++) 25398944Sobrien supply_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 16); 25498944Sobrien for (i = 0; i < num_xmm_registers; i++) 25598944Sobrien supply_register (i + xmm0_regnum, ((char *) &fp->xmm_space[0]) + i * 16); 25698944Sobrien 25798944Sobrien supply_register_by_name ("fioff", &fp->fioff); 25898944Sobrien supply_register_by_name ("fooff", &fp->fooff); 25998944Sobrien supply_register_by_name ("mxcsr", &fp->mxcsr); 26098944Sobrien 26198944Sobrien /* Some registers are 16-bit. */ 26298944Sobrien val = fp->fctrl & 0xFFFF; 26398944Sobrien supply_register_by_name ("fctrl", &val); 26498944Sobrien 26598944Sobrien val = fp->fstat & 0xFFFF; 26698944Sobrien supply_register_by_name ("fstat", &val); 26798944Sobrien 26898944Sobrien /* Generate the form of ftag data that GDB expects. */ 26998944Sobrien top = (fp->fstat >> 11) & 0x7; 27098944Sobrien val = 0; 27198944Sobrien for (i = 7; i >= 0; i--) 27298944Sobrien { 27398944Sobrien int tag; 27498944Sobrien if (val & (1 << i)) 27598944Sobrien tag = i387_ftag (fp, (i + 8 - top) % 8); 27698944Sobrien else 27798944Sobrien tag = 3; 27898944Sobrien val |= tag << (2 * i); 27998944Sobrien } 28098944Sobrien supply_register_by_name ("ftag", &val); 28198944Sobrien 28298944Sobrien val = fp->fiseg & 0xFFFF; 28398944Sobrien supply_register_by_name ("fiseg", &val); 28498944Sobrien 28598944Sobrien val = fp->foseg & 0xFFFF; 28698944Sobrien supply_register_by_name ("foseg", &val); 28798944Sobrien 28898944Sobrien val = (fp->fop) & 0x7FF; 28998944Sobrien supply_register_by_name ("fop", &val); 29098944Sobrien} 291