xref: /openbsd/gnu/usr.bin/binutils/gdb/i386v-nat.c (revision 07ea8d15)
1 /* Intel 386 native support for SYSV systems (pre-SVR4).
2    Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996 Free Software Foundation, Inc.
3 
4 This file is part of GDB.
5 
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.
10 
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.
15 
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, Boston, MA 02111-1307, USA.  */
19 
20 #include "defs.h"
21 #include "frame.h"
22 #include "inferior.h"
23 #include "language.h"
24 #include "gdbcore.h"
25 
26 #ifdef USG
27 #include <sys/types.h>
28 #endif
29 
30 #include <sys/param.h>
31 #include <sys/dir.h>
32 #include <signal.h>
33 #include <sys/user.h>
34 #include <sys/ioctl.h>
35 #include <fcntl.h>
36 
37 #ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
38 #include <sys/debugreg.h>
39 #endif
40 
41 #include <sys/file.h>
42 #include "gdb_stat.h"
43 
44 #ifndef NO_SYS_REG_H
45 #include <sys/reg.h>
46 #endif
47 
48 #include "floatformat.h"
49 
50 #include "target.h"
51 
52 
53 /* this table must line up with REGISTER_NAMES in tm-i386v.h */
54 /* symbols like 'EAX' come from <sys/reg.h> */
55 static int regmap[] =
56 {
57   EAX, ECX, EDX, EBX,
58   UESP, EBP, ESI, EDI,
59   EIP, EFL, CS, SS,
60   DS, ES, FS, GS,
61 };
62 
63 /* blockend is the value of u.u_ar0, and points to the
64  * place where GS is stored
65  */
66 
67 int
68 i386_register_u_addr (blockend, regnum)
69      int blockend;
70      int regnum;
71 {
72   struct user u;
73   int fpstate;
74   int ubase;
75 
76   ubase = blockend;
77   /* FIXME:  Should have better way to test floating point range */
78   if (regnum >= FP0_REGNUM && regnum <= (FP0_REGNUM + 7))
79     {
80 #ifdef KSTKSZ	/* SCO, and others? */
81       ubase += 4 * (SS + 1) - KSTKSZ;
82       fpstate = ubase + ((char *)&u.u_fps.u_fpstate - (char *)&u);
83       return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
84 #else
85       fpstate = ubase + ((char *)&u.i387.st_space - (char *)&u);
86       return (fpstate + 10 * (regnum - FP0_REGNUM));
87 #endif
88     }
89   else
90     {
91       return (ubase + 4 * regmap[regnum]);
92     }
93 
94 }
95 
96 int
97 kernel_u_size ()
98 {
99   return (sizeof (struct user));
100 }
101 
102 #ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
103 
104 #if !defined (offsetof)
105 #define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
106 #endif
107 
108 /* Record the value of the debug control register.  */
109 static int debug_control_mirror;
110 
111 /* Record which address associates with which register.  */
112 static CORE_ADDR address_lookup[DR_LASTADDR - DR_FIRSTADDR + 1];
113 
114 static int
115 i386_insert_aligned_watchpoint PARAMS ((int, CORE_ADDR, CORE_ADDR, int,
116 					   int));
117 
118 static int
119 i386_insert_nonaligned_watchpoint PARAMS ((int, CORE_ADDR, CORE_ADDR, int,
120 					   int));
121 
122 /* Insert a watchpoint.  */
123 
124 int
125 i386_insert_watchpoint (pid, addr, len, rw)
126      int pid;
127      CORE_ADDR addr;
128      int len;
129      int rw;
130 {
131   return i386_insert_aligned_watchpoint (pid, addr, addr, len, rw);
132 }
133 
134 static int
135 i386_insert_aligned_watchpoint (pid, waddr, addr, len, rw)
136      int pid;
137      CORE_ADDR waddr;
138      CORE_ADDR addr;
139      int len;
140      int rw;
141 {
142   int i;
143   int read_write_bits, len_bits;
144   int free_debug_register;
145   int register_number;
146 
147   /* Look for a free debug register.  */
148   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
149     {
150       if (address_lookup[i - DR_FIRSTADDR] == 0)
151 	break;
152     }
153 
154   /* No more debug registers!  */
155   if (i > DR_LASTADDR)
156     return -1;
157 
158   read_write_bits = ((rw & 1) ? DR_RW_READ : 0) | ((rw & 2) ? DR_RW_WRITE : 0);
159 
160   if (len == 1)
161     len_bits = DR_LEN_1;
162   else if (len == 2)
163     {
164       if (addr % 2)
165 	return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
166       len_bits = DR_LEN_2;
167     }
168 
169   else if (len == 4)
170     {
171       if (addr % 4)
172 	return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
173       len_bits = DR_LEN_4;
174     }
175   else
176     return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
177 
178   free_debug_register = i;
179   register_number = free_debug_register - DR_FIRSTADDR;
180   debug_control_mirror |=
181     ((read_write_bits | len_bits)
182      << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number));
183   debug_control_mirror |=
184     (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
185   debug_control_mirror |= DR_LOCAL_SLOWDOWN;
186   debug_control_mirror &= ~DR_CONTROL_RESERVED;
187 
188   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
189 	  debug_control_mirror);
190   ptrace (6, pid, offsetof (struct user, u_debugreg[free_debug_register]),
191 	  addr);
192 
193   /* Record where we came from.  */
194   address_lookup[register_number] = addr;
195   return 0;
196 }
197 
198 static int
199 i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw)
200      int pid;
201      CORE_ADDR waddr;
202      CORE_ADDR addr;
203      int len;
204      int rw;
205 {
206   int align;
207   int size;
208   int rv;
209 
210   static int size_try_array[16] = {
211     1, 1, 1, 1,			/* trying size one */
212     2, 1, 2, 1,			/* trying size two */
213     2, 1, 2, 1,			/* trying size three */
214     4, 1, 2, 1			/* trying size four */
215   };
216 
217   rv = 0;
218   while (len > 0)
219     {
220       align = addr % 4;
221       /* Four is the maximum length for 386.  */
222       size = (len > 4) ? 3 : len - 1;
223       size = size_try_array[size * 4 + align];
224 
225       rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
226       if (rv)
227 	{
228 	  i386_remove_watchpoint (pid, waddr, size);
229 	  return rv;
230 	}
231       addr += size;
232       len -= size;
233     }
234   return rv;
235 }
236 
237 /* Remove a watchpoint.  */
238 
239 int
240 i386_remove_watchpoint (pid, addr, len)
241      int pid;
242      CORE_ADDR addr;
243      int len;
244 {
245   int i;
246   int register_number;
247 
248   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
249     {
250       register_number = i - DR_FIRSTADDR;
251       if (address_lookup[register_number] == addr)
252 	{
253 	  debug_control_mirror &=
254 	    ~(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
255 	  address_lookup[register_number] = 0;
256 	}
257     }
258   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
259 	  debug_control_mirror);
260   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
261 
262   return 0;
263 }
264 
265 /* Check if stopped by a watchpoint.  */
266 
267 CORE_ADDR
268 i386_stopped_by_watchpoint (pid)
269     int pid;
270 {
271   int i;
272   int status;
273 
274   status = ptrace (3, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
275   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
276 
277   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
278     {
279       if (status & (1 << (i - DR_FIRSTADDR)))
280 	return address_lookup[i - DR_FIRSTADDR];
281     }
282 
283   return 0;
284 }
285 
286 #endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */
287 
288 #if 0
289 /* using FLOAT_INFO as is would be a problem.  FLOAT_INFO is called
290    via a command xxx and eventually calls ptrace without ever having
291    traversed the target vector.  This would be terribly impolite
292    behaviour for a sun4 hosted remote gdb.
293 
294    A fix might be to move this code into the "info registers" command.
295    rich@cygnus.com 15 Sept 92. */
296 i386_float_info ()
297 {
298   struct user u; /* just for address computations */
299   int i;
300   /* fpstate defined in <sys/user.h> */
301   struct fpstate *fpstatep;
302   char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
303   unsigned int uaddr;
304   char fpvalid = 0;
305   unsigned int rounded_addr;
306   unsigned int rounded_size;
307   extern int corechan;
308   int skip;
309 
310   uaddr = (char *)&u.u_fpvalid - (char *)&u;
311   if (target_has_execution)
312     {
313       unsigned int data;
314       unsigned int mask;
315 
316       rounded_addr = uaddr & -sizeof (int);
317       data = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) rounded_addr, 0);
318       mask = 0xff << ((uaddr - rounded_addr) * 8);
319 
320       fpvalid = ((data & mask) != 0);
321     }
322 #if 0
323   else
324     {
325       if (lseek (corechan, uaddr, 0) < 0)
326 	perror ("seek on core file");
327       if (myread (corechan, &fpvalid, 1) < 0)
328 	perror ("read on core file");
329 
330     }
331 #endif	/* no core support yet */
332 
333   if (fpvalid == 0)
334     {
335       printf_unfiltered ("no floating point status saved\n");
336       return;
337     }
338 
339   uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
340   if (target_has_execution)
341     {
342       int *ip;
343 
344       rounded_addr = uaddr & -sizeof (int);
345       rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) +
346 		      sizeof (int) - 1) / sizeof (int);
347       skip = uaddr - rounded_addr;
348 
349       ip = (int *)buf;
350       for (i = 0; i < rounded_size; i++)
351 	{
352 	  *ip++ = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) rounded_addr, 0);
353 	  rounded_addr += sizeof (int);
354 	}
355     }
356 #if 0
357   else
358     {
359       if (lseek (corechan, uaddr, 0) < 0)
360 	perror_with_name ("seek on core file");
361       if (myread (corechan, buf, sizeof (struct fpstate)) < 0)
362 	perror_with_name ("read from core file");
363       skip = 0;
364     }
365 #endif	/* 0 */
366 
367   fpstatep = (struct fpstate *)(buf + skip);
368   print_387_status (fpstatep->status, (struct env387 *)fpstatep->state);
369 }
370 
371 #endif /* never */
372