xref: /openbsd/gnu/usr.bin/binutils/gdb/i386v-nat.c (revision 63addd46)
1*b725ae77Skettenis /* Intel 386 native support for System V systems (pre-SVR4).
2*b725ae77Skettenis 
3*b725ae77Skettenis    Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
4*b725ae77Skettenis    1999, 2000, 2002 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
20*b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
21*b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
22e93f7393Sniklas 
23e93f7393Sniklas #include "defs.h"
24*b725ae77Skettenis 
25*b725ae77Skettenis #ifdef HAVE_PTRACE_H
26*b725ae77Skettenis #include <ptrace.h>
27*b725ae77Skettenis #else
28*b725ae77Skettenis #ifdef HAVE_SYS_PTRACE_H
29*b725ae77Skettenis #include <sys/ptrace.h>
30*b725ae77Skettenis #endif
31*b725ae77Skettenis #endif
32*b725ae77Skettenis 
33e93f7393Sniklas #include "frame.h"
34e93f7393Sniklas #include "inferior.h"
35e93f7393Sniklas #include "language.h"
36e93f7393Sniklas #include "gdbcore.h"
37e93f7393Sniklas 
38e93f7393Sniklas #include <sys/param.h>
39e93f7393Sniklas #include <sys/dir.h>
40e93f7393Sniklas #include <signal.h>
41e93f7393Sniklas #include <sys/user.h>
42e93f7393Sniklas #include <sys/ioctl.h>
43e93f7393Sniklas #include <fcntl.h>
44e93f7393Sniklas 
45e93f7393Sniklas #ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
46e93f7393Sniklas #include <sys/debugreg.h>
47e93f7393Sniklas #endif
48e93f7393Sniklas 
49e93f7393Sniklas #include <sys/file.h>
50e93f7393Sniklas #include "gdb_stat.h"
51e93f7393Sniklas 
52*b725ae77Skettenis #ifdef HAVE_SYS_REG_H
53e93f7393Sniklas #include <sys/reg.h>
54e93f7393Sniklas #endif
55e93f7393Sniklas 
56e93f7393Sniklas #include "floatformat.h"
57e93f7393Sniklas 
58e93f7393Sniklas #include "target.h"
59e93f7393Sniklas 
60*b725ae77Skettenis #include "i386-tdep.h"
61e93f7393Sniklas 
62*b725ae77Skettenis 
63*b725ae77Skettenis /* Mapping between the general-purpose registers in `struct user'
64*b725ae77Skettenis    format and GDB's register array layout.  */
65e93f7393Sniklas static int regmap[] =
66e93f7393Sniklas {
67e93f7393Sniklas   EAX, ECX, EDX, EBX,
68e93f7393Sniklas   UESP, EBP, ESI, EDI,
69e93f7393Sniklas   EIP, EFL, CS, SS,
70e93f7393Sniklas   DS, ES, FS, GS,
71e93f7393Sniklas };
72e93f7393Sniklas 
73*b725ae77Skettenis /* Support for the user struct.  */
74e93f7393Sniklas 
75*b725ae77Skettenis /* Return the address of register REGNUM.  BLOCKEND is the value of
76*b725ae77Skettenis    u.u_ar0, and points to the place where GS is stored.  */
77*b725ae77Skettenis 
78*b725ae77Skettenis CORE_ADDR
register_u_addr(CORE_ADDR blockend,int regnum)79*b725ae77Skettenis register_u_addr (CORE_ADDR blockend, int regnum)
80e93f7393Sniklas {
81e93f7393Sniklas   struct user u;
82*b725ae77Skettenis   CORE_ADDR fpstate;
83e93f7393Sniklas 
84*b725ae77Skettenis   if (i386_fp_regnum_p (regnum))
85e93f7393Sniklas     {
86e93f7393Sniklas #ifdef KSTKSZ			/* SCO, and others?  */
87*b725ae77Skettenis       blockend += 4 * (SS + 1) - KSTKSZ;
88*b725ae77Skettenis       fpstate = blockend + ((char *) &u.u_fps.u_fpstate - (char *) &u);
89e93f7393Sniklas       return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
90e93f7393Sniklas #else
91*b725ae77Skettenis       fpstate = blockend + ((char *) &u.i387.st_space - (char *) &u);
92e93f7393Sniklas       return (fpstate + 10 * (regnum - FP0_REGNUM));
93e93f7393Sniklas #endif
94e93f7393Sniklas     }
95*b725ae77Skettenis 
96*b725ae77Skettenis   return (blockend + 4 * regmap[regnum]);
97e93f7393Sniklas }
98e93f7393Sniklas 
99*b725ae77Skettenis /* Return the size of the user struct.  */
100*b725ae77Skettenis 
101e93f7393Sniklas int
kernel_u_size(void)102*b725ae77Skettenis kernel_u_size (void)
103e93f7393Sniklas {
104e93f7393Sniklas   return (sizeof (struct user));
105e93f7393Sniklas }
106e93f7393Sniklas 
107e93f7393Sniklas #ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
108e93f7393Sniklas 
109e93f7393Sniklas #if !defined (offsetof)
110e93f7393Sniklas #define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
111e93f7393Sniklas #endif
112e93f7393Sniklas 
113e93f7393Sniklas /* Record the value of the debug control register.  */
114e93f7393Sniklas static int debug_control_mirror;
115e93f7393Sniklas 
116e93f7393Sniklas /* Record which address associates with which register.  */
117e93f7393Sniklas static CORE_ADDR address_lookup[DR_LASTADDR - DR_FIRSTADDR + 1];
118e93f7393Sniklas 
119*b725ae77Skettenis static int i386_insert_aligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int,
120*b725ae77Skettenis 					   int);
121e93f7393Sniklas 
122*b725ae77Skettenis static int i386_insert_nonaligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int,
123*b725ae77Skettenis 					      int);
124e93f7393Sniklas 
125e93f7393Sniklas /* Insert a watchpoint.  */
126e93f7393Sniklas 
127e93f7393Sniklas int
i386_insert_watchpoint(int pid,CORE_ADDR addr,int len,int rw)128*b725ae77Skettenis i386_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
129e93f7393Sniklas {
130e93f7393Sniklas   return i386_insert_aligned_watchpoint (pid, addr, addr, len, rw);
131e93f7393Sniklas }
132e93f7393Sniklas 
133e93f7393Sniklas static int
i386_insert_aligned_watchpoint(int pid,CORE_ADDR waddr,CORE_ADDR addr,int len,int rw)134*b725ae77Skettenis i386_insert_aligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
135*b725ae77Skettenis 				int len, int rw)
136e93f7393Sniklas {
137e93f7393Sniklas   int i;
138e93f7393Sniklas   int read_write_bits, len_bits;
139e93f7393Sniklas   int free_debug_register;
140e93f7393Sniklas   int register_number;
141e93f7393Sniklas 
142e93f7393Sniklas   /* Look for a free debug register.  */
143e93f7393Sniklas   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
144e93f7393Sniklas     {
145e93f7393Sniklas       if (address_lookup[i - DR_FIRSTADDR] == 0)
146e93f7393Sniklas 	break;
147e93f7393Sniklas     }
148e93f7393Sniklas 
149e93f7393Sniklas   /* No more debug registers!  */
150e93f7393Sniklas   if (i > DR_LASTADDR)
151e93f7393Sniklas     return -1;
152e93f7393Sniklas 
153*b725ae77Skettenis   read_write_bits = (rw & 1) ? DR_RW_READ : DR_RW_WRITE;
154e93f7393Sniklas 
155e93f7393Sniklas   if (len == 1)
156e93f7393Sniklas     len_bits = DR_LEN_1;
157e93f7393Sniklas   else if (len == 2)
158e93f7393Sniklas     {
159e93f7393Sniklas       if (addr % 2)
160e93f7393Sniklas 	return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
161e93f7393Sniklas       len_bits = DR_LEN_2;
162e93f7393Sniklas     }
163e93f7393Sniklas 
164e93f7393Sniklas   else if (len == 4)
165e93f7393Sniklas     {
166e93f7393Sniklas       if (addr % 4)
167e93f7393Sniklas 	return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
168e93f7393Sniklas       len_bits = DR_LEN_4;
169e93f7393Sniklas     }
170e93f7393Sniklas   else
171e93f7393Sniklas     return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
172e93f7393Sniklas 
173e93f7393Sniklas   free_debug_register = i;
174e93f7393Sniklas   register_number = free_debug_register - DR_FIRSTADDR;
175e93f7393Sniklas   debug_control_mirror |=
176e93f7393Sniklas     ((read_write_bits | len_bits)
177e93f7393Sniklas      << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number));
178e93f7393Sniklas   debug_control_mirror |=
179e93f7393Sniklas     (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
180e93f7393Sniklas   debug_control_mirror |= DR_LOCAL_SLOWDOWN;
181e93f7393Sniklas   debug_control_mirror &= ~DR_CONTROL_RESERVED;
182e93f7393Sniklas 
183e93f7393Sniklas   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
184e93f7393Sniklas 	  debug_control_mirror);
185e93f7393Sniklas   ptrace (6, pid, offsetof (struct user, u_debugreg[free_debug_register]),
186e93f7393Sniklas 	  addr);
187e93f7393Sniklas 
188e93f7393Sniklas   /* Record where we came from.  */
189e93f7393Sniklas   address_lookup[register_number] = addr;
190e93f7393Sniklas   return 0;
191e93f7393Sniklas }
192e93f7393Sniklas 
193e93f7393Sniklas static int
i386_insert_nonaligned_watchpoint(int pid,CORE_ADDR waddr,CORE_ADDR addr,int len,int rw)194*b725ae77Skettenis i386_insert_nonaligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
195*b725ae77Skettenis 				   int len, int rw)
196e93f7393Sniklas {
197e93f7393Sniklas   int align;
198e93f7393Sniklas   int size;
199e93f7393Sniklas   int rv;
200e93f7393Sniklas 
201*b725ae77Skettenis   static int size_try_array[4][4] =
202*b725ae77Skettenis   {
203*b725ae77Skettenis     { 1, 1, 1, 1 },		/* trying size one */
204*b725ae77Skettenis     { 2, 1, 2, 1 },		/* trying size two */
205*b725ae77Skettenis     { 2, 1, 2, 1 },		/* trying size three */
206*b725ae77Skettenis     { 4, 1, 2, 1 }		/* trying size four */
207e93f7393Sniklas   };
208e93f7393Sniklas 
209e93f7393Sniklas   rv = 0;
210e93f7393Sniklas   while (len > 0)
211e93f7393Sniklas     {
212e93f7393Sniklas       align = addr % 4;
213e93f7393Sniklas       /* Four is the maximum length for 386.  */
214*b725ae77Skettenis       size = size_try_array[len > 4 ? 3 : len - 1][align];
215e93f7393Sniklas 
216e93f7393Sniklas       rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
217e93f7393Sniklas       if (rv)
218e93f7393Sniklas 	{
219e93f7393Sniklas 	  i386_remove_watchpoint (pid, waddr, size);
220e93f7393Sniklas 	  return rv;
221e93f7393Sniklas 	}
222e93f7393Sniklas       addr += size;
223e93f7393Sniklas       len -= size;
224e93f7393Sniklas     }
225e93f7393Sniklas   return rv;
226e93f7393Sniklas }
227e93f7393Sniklas 
228e93f7393Sniklas /* Remove a watchpoint.  */
229e93f7393Sniklas 
230e93f7393Sniklas int
i386_remove_watchpoint(int pid,CORE_ADDR addr,int len)231*b725ae77Skettenis i386_remove_watchpoint (int pid, CORE_ADDR addr, int len)
232e93f7393Sniklas {
233e93f7393Sniklas   int i;
234e93f7393Sniklas   int register_number;
235e93f7393Sniklas 
236e93f7393Sniklas   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
237e93f7393Sniklas     {
238e93f7393Sniklas       register_number = i - DR_FIRSTADDR;
239e93f7393Sniklas       if (address_lookup[register_number] == addr)
240e93f7393Sniklas 	{
241e93f7393Sniklas 	  debug_control_mirror &=
242e93f7393Sniklas 	    ~(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
243e93f7393Sniklas 	  address_lookup[register_number] = 0;
244e93f7393Sniklas 	}
245e93f7393Sniklas     }
246e93f7393Sniklas   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
247e93f7393Sniklas 	  debug_control_mirror);
248e93f7393Sniklas   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
249e93f7393Sniklas 
250e93f7393Sniklas   return 0;
251e93f7393Sniklas }
252e93f7393Sniklas 
253e93f7393Sniklas /* Check if stopped by a watchpoint.  */
254e93f7393Sniklas 
255e93f7393Sniklas CORE_ADDR
i386_stopped_by_watchpoint(int pid)256*b725ae77Skettenis i386_stopped_by_watchpoint (int pid)
257e93f7393Sniklas {
258e93f7393Sniklas   int i;
259e93f7393Sniklas   int status;
260e93f7393Sniklas 
261e93f7393Sniklas   status = ptrace (3, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
262e93f7393Sniklas   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
263e93f7393Sniklas 
264e93f7393Sniklas   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
265e93f7393Sniklas     {
266e93f7393Sniklas       if (status & (1 << (i - DR_FIRSTADDR)))
267e93f7393Sniklas 	return address_lookup[i - DR_FIRSTADDR];
268e93f7393Sniklas     }
269e93f7393Sniklas 
270e93f7393Sniklas   return 0;
271e93f7393Sniklas }
272e93f7393Sniklas 
273e93f7393Sniklas #endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */
274