1130812Smarcel/* Intel 386 native support for System V systems (pre-SVR4). 2130812Smarcel 3130812Smarcel Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 4130812Smarcel 1999, 2000, 2002 Free Software Foundation, Inc. 5130812Smarcel 6130812Smarcel This file is part of GDB. 7130812Smarcel 8130812Smarcel This program is free software; you can redistribute it and/or modify 9130812Smarcel it under the terms of the GNU General Public License as published by 10130812Smarcel the Free Software Foundation; either version 2 of the License, or 11130812Smarcel (at your option) any later version. 12130812Smarcel 13130812Smarcel This program is distributed in the hope that it will be useful, 14130812Smarcel but WITHOUT ANY WARRANTY; without even the implied warranty of 15130812Smarcel MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16130812Smarcel GNU General Public License for more details. 17130812Smarcel 18130812Smarcel You should have received a copy of the GNU General Public License 19130812Smarcel along with this program; if not, write to the Free Software 20130812Smarcel Foundation, Inc., 59 Temple Place - Suite 330, 21130812Smarcel Boston, MA 02111-1307, USA. */ 22130812Smarcel 23130812Smarcel#include "defs.h" 24130812Smarcel 25130812Smarcel#ifdef HAVE_PTRACE_H 26130812Smarcel#include <ptrace.h> 27130812Smarcel#else 28130812Smarcel#ifdef HAVE_SYS_PTRACE_H 29130812Smarcel#include <sys/ptrace.h> 30130812Smarcel#endif 31130812Smarcel#endif 32130812Smarcel 33130812Smarcel#include "frame.h" 34130812Smarcel#include "inferior.h" 35130812Smarcel#include "language.h" 36130812Smarcel#include "gdbcore.h" 37130812Smarcel 38130812Smarcel#ifdef USG 39130812Smarcel#include <sys/types.h> 40130812Smarcel#endif 41130812Smarcel 42130812Smarcel#include <sys/param.h> 43130812Smarcel#include <sys/dir.h> 44130812Smarcel#include <signal.h> 45130812Smarcel#include <sys/user.h> 46130812Smarcel#include <sys/ioctl.h> 47130812Smarcel#include <fcntl.h> 48130812Smarcel 49130812Smarcel#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS 50130812Smarcel#include <sys/debugreg.h> 51130812Smarcel#endif 52130812Smarcel 53130812Smarcel#include <sys/file.h> 54130812Smarcel#include "gdb_stat.h" 55130812Smarcel 56130812Smarcel#ifdef HAVE_SYS_REG_H 57130812Smarcel#include <sys/reg.h> 58130812Smarcel#endif 59130812Smarcel 60130812Smarcel#include "floatformat.h" 61130812Smarcel 62130812Smarcel#include "target.h" 63130812Smarcel 64130812Smarcel#include "i386-tdep.h" 65130812Smarcel 66130812Smarcel 67130812Smarcel/* Mapping between the general-purpose registers in `struct user' 68130812Smarcel format and GDB's register array layout. */ 69130812Smarcelstatic int regmap[] = 70130812Smarcel{ 71130812Smarcel EAX, ECX, EDX, EBX, 72130812Smarcel UESP, EBP, ESI, EDI, 73130812Smarcel EIP, EFL, CS, SS, 74130812Smarcel DS, ES, FS, GS, 75130812Smarcel}; 76130812Smarcel 77130812Smarcel/* Support for the user struct. */ 78130812Smarcel 79130812Smarcel/* Return the address of register REGNUM. BLOCKEND is the value of 80130812Smarcel u.u_ar0, and points to the place where GS is stored. */ 81130812Smarcel 82130812SmarcelCORE_ADDR 83130812Smarcelregister_u_addr (CORE_ADDR blockend, int regnum) 84130812Smarcel{ 85130812Smarcel struct user u; 86130812Smarcel CORE_ADDR fpstate; 87130812Smarcel 88130812Smarcel if (i386_fp_regnum_p (regnum)) 89130812Smarcel { 90130812Smarcel#ifdef KSTKSZ /* SCO, and others? */ 91130812Smarcel blockend += 4 * (SS + 1) - KSTKSZ; 92130812Smarcel fpstate = blockend + ((char *) &u.u_fps.u_fpstate - (char *) &u); 93130812Smarcel return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM)); 94130812Smarcel#else 95130812Smarcel fpstate = blockend + ((char *) &u.i387.st_space - (char *) &u); 96130812Smarcel return (fpstate + 10 * (regnum - FP0_REGNUM)); 97130812Smarcel#endif 98130812Smarcel } 99130812Smarcel 100130812Smarcel return (blockend + 4 * regmap[regnum]); 101130812Smarcel} 102130812Smarcel 103130812Smarcel/* Return the size of the user struct. */ 104130812Smarcel 105130812Smarcelint 106130812Smarcelkernel_u_size (void) 107130812Smarcel{ 108130812Smarcel return (sizeof (struct user)); 109130812Smarcel} 110130812Smarcel 111130812Smarcel#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS 112130812Smarcel 113130812Smarcel#if !defined (offsetof) 114130812Smarcel#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) 115130812Smarcel#endif 116130812Smarcel 117130812Smarcel/* Record the value of the debug control register. */ 118130812Smarcelstatic int debug_control_mirror; 119130812Smarcel 120130812Smarcel/* Record which address associates with which register. */ 121130812Smarcelstatic CORE_ADDR address_lookup[DR_LASTADDR - DR_FIRSTADDR + 1]; 122130812Smarcel 123130812Smarcelstatic int i386_insert_aligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int, 124130812Smarcel int); 125130812Smarcel 126130812Smarcelstatic int i386_insert_nonaligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int, 127130812Smarcel int); 128130812Smarcel 129130812Smarcel/* Insert a watchpoint. */ 130130812Smarcel 131130812Smarcelint 132130812Smarceli386_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw) 133130812Smarcel{ 134130812Smarcel return i386_insert_aligned_watchpoint (pid, addr, addr, len, rw); 135130812Smarcel} 136130812Smarcel 137130812Smarcelstatic int 138130812Smarceli386_insert_aligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr, 139130812Smarcel int len, int rw) 140130812Smarcel{ 141130812Smarcel int i; 142130812Smarcel int read_write_bits, len_bits; 143130812Smarcel int free_debug_register; 144130812Smarcel int register_number; 145130812Smarcel 146130812Smarcel /* Look for a free debug register. */ 147130812Smarcel for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) 148130812Smarcel { 149130812Smarcel if (address_lookup[i - DR_FIRSTADDR] == 0) 150130812Smarcel break; 151130812Smarcel } 152130812Smarcel 153130812Smarcel /* No more debug registers! */ 154130812Smarcel if (i > DR_LASTADDR) 155130812Smarcel return -1; 156130812Smarcel 157130812Smarcel read_write_bits = (rw & 1) ? DR_RW_READ : DR_RW_WRITE; 158130812Smarcel 159130812Smarcel if (len == 1) 160130812Smarcel len_bits = DR_LEN_1; 161130812Smarcel else if (len == 2) 162130812Smarcel { 163130812Smarcel if (addr % 2) 164130812Smarcel return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw); 165130812Smarcel len_bits = DR_LEN_2; 166130812Smarcel } 167130812Smarcel 168130812Smarcel else if (len == 4) 169130812Smarcel { 170130812Smarcel if (addr % 4) 171130812Smarcel return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw); 172130812Smarcel len_bits = DR_LEN_4; 173130812Smarcel } 174130812Smarcel else 175130812Smarcel return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw); 176130812Smarcel 177130812Smarcel free_debug_register = i; 178130812Smarcel register_number = free_debug_register - DR_FIRSTADDR; 179130812Smarcel debug_control_mirror |= 180130812Smarcel ((read_write_bits | len_bits) 181130812Smarcel << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number)); 182130812Smarcel debug_control_mirror |= 183130812Smarcel (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number)); 184130812Smarcel debug_control_mirror |= DR_LOCAL_SLOWDOWN; 185130812Smarcel debug_control_mirror &= ~DR_CONTROL_RESERVED; 186130812Smarcel 187130812Smarcel ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]), 188130812Smarcel debug_control_mirror); 189130812Smarcel ptrace (6, pid, offsetof (struct user, u_debugreg[free_debug_register]), 190130812Smarcel addr); 191130812Smarcel 192130812Smarcel /* Record where we came from. */ 193130812Smarcel address_lookup[register_number] = addr; 194130812Smarcel return 0; 195130812Smarcel} 196130812Smarcel 197130812Smarcelstatic int 198130812Smarceli386_insert_nonaligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr, 199130812Smarcel int len, int rw) 200130812Smarcel{ 201130812Smarcel int align; 202130812Smarcel int size; 203130812Smarcel int rv; 204130812Smarcel 205130812Smarcel static int size_try_array[4][4] = 206130812Smarcel { 207130812Smarcel { 1, 1, 1, 1 }, /* trying size one */ 208130812Smarcel { 2, 1, 2, 1 }, /* trying size two */ 209130812Smarcel { 2, 1, 2, 1 }, /* trying size three */ 210130812Smarcel { 4, 1, 2, 1 } /* trying size four */ 211130812Smarcel }; 212130812Smarcel 213130812Smarcel rv = 0; 214130812Smarcel while (len > 0) 215130812Smarcel { 216130812Smarcel align = addr % 4; 217130812Smarcel /* Four is the maximum length for 386. */ 218130812Smarcel size = size_try_array[len > 4 ? 3 : len - 1][align]; 219130812Smarcel 220130812Smarcel rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw); 221130812Smarcel if (rv) 222130812Smarcel { 223130812Smarcel i386_remove_watchpoint (pid, waddr, size); 224130812Smarcel return rv; 225130812Smarcel } 226130812Smarcel addr += size; 227130812Smarcel len -= size; 228130812Smarcel } 229130812Smarcel return rv; 230130812Smarcel} 231130812Smarcel 232130812Smarcel/* Remove a watchpoint. */ 233130812Smarcel 234130812Smarcelint 235130812Smarceli386_remove_watchpoint (int pid, CORE_ADDR addr, int len) 236130812Smarcel{ 237130812Smarcel int i; 238130812Smarcel int register_number; 239130812Smarcel 240130812Smarcel for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) 241130812Smarcel { 242130812Smarcel register_number = i - DR_FIRSTADDR; 243130812Smarcel if (address_lookup[register_number] == addr) 244130812Smarcel { 245130812Smarcel debug_control_mirror &= 246130812Smarcel ~(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number)); 247130812Smarcel address_lookup[register_number] = 0; 248130812Smarcel } 249130812Smarcel } 250130812Smarcel ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]), 251130812Smarcel debug_control_mirror); 252130812Smarcel ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0); 253130812Smarcel 254130812Smarcel return 0; 255130812Smarcel} 256130812Smarcel 257130812Smarcel/* Check if stopped by a watchpoint. */ 258130812Smarcel 259130812SmarcelCORE_ADDR 260130812Smarceli386_stopped_by_watchpoint (int pid) 261130812Smarcel{ 262130812Smarcel int i; 263130812Smarcel int status; 264130812Smarcel 265130812Smarcel status = ptrace (3, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0); 266130812Smarcel ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0); 267130812Smarcel 268130812Smarcel for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) 269130812Smarcel { 270130812Smarcel if (status & (1 << (i - DR_FIRSTADDR))) 271130812Smarcel return address_lookup[i - DR_FIRSTADDR]; 272130812Smarcel } 273130812Smarcel 274130812Smarcel return 0; 275130812Smarcel} 276130812Smarcel 277130812Smarcel#endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */ 278