xref: /openbsd-src/gnu/usr.bin/binutils/gdb/gdbserver/linux-i386-low.c (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
1b725ae77Skettenis /* GNU/Linux/i386 specific low level interface, for the remote server for GDB.
2*11efff7fSkettenis    Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2004
3b725ae77Skettenis    Free Software Foundation, Inc.
4b725ae77Skettenis 
5b725ae77Skettenis    This file is part of GDB.
6b725ae77Skettenis 
7b725ae77Skettenis    This program is free software; you can redistribute it and/or modify
8b725ae77Skettenis    it under the terms of the GNU General Public License as published by
9b725ae77Skettenis    the Free Software Foundation; either version 2 of the License, or
10b725ae77Skettenis    (at your option) any later version.
11b725ae77Skettenis 
12b725ae77Skettenis    This program is distributed in the hope that it will be useful,
13b725ae77Skettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
14b725ae77Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15b725ae77Skettenis    GNU General Public License for more details.
16b725ae77Skettenis 
17b725ae77Skettenis    You should have received a copy of the GNU General Public License
18b725ae77Skettenis    along with this program; if not, write to the Free Software
19b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
20b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
21b725ae77Skettenis 
22b725ae77Skettenis #include "server.h"
23b725ae77Skettenis #include "linux-low.h"
24b725ae77Skettenis #include "i387-fp.h"
25b725ae77Skettenis 
26*11efff7fSkettenis /* Correct for all GNU/Linux targets (for quite some time).  */
27*11efff7fSkettenis #define GDB_GREGSET_T elf_gregset_t
28*11efff7fSkettenis #define GDB_FPREGSET_T elf_fpregset_t
29*11efff7fSkettenis 
30*11efff7fSkettenis #ifndef HAVE_ELF_FPREGSET_T
31*11efff7fSkettenis /* Make sure we have said types.  Not all platforms bring in <linux/elf.h>
32*11efff7fSkettenis    via <sys/procfs.h>.  */
33*11efff7fSkettenis #ifdef HAVE_LINUX_ELF_H
34*11efff7fSkettenis #include <linux/elf.h>
35*11efff7fSkettenis #endif
36*11efff7fSkettenis #endif
37*11efff7fSkettenis 
38*11efff7fSkettenis #include "../gdb_proc_service.h"
39*11efff7fSkettenis 
40*11efff7fSkettenis #include <sys/ptrace.h>
41*11efff7fSkettenis 
42b725ae77Skettenis #ifdef HAVE_SYS_REG_H
43b725ae77Skettenis #include <sys/reg.h>
44b725ae77Skettenis #endif
45b725ae77Skettenis 
46*11efff7fSkettenis #ifndef PTRACE_GET_THREAD_AREA
47*11efff7fSkettenis #define PTRACE_GET_THREAD_AREA 25
48*11efff7fSkettenis #endif
49*11efff7fSkettenis 
50b725ae77Skettenis /* This module only supports access to the general purpose registers.  */
51b725ae77Skettenis 
52b725ae77Skettenis #define i386_num_regs 16
53b725ae77Skettenis 
54b725ae77Skettenis /* This stuff comes from i386-linux-nat.c.  */
55b725ae77Skettenis 
56b725ae77Skettenis /* Mapping between the general-purpose registers in `struct user'
57b725ae77Skettenis    format and GDB's register array layout.  */
58b725ae77Skettenis static int i386_regmap[] =
59b725ae77Skettenis {
60b725ae77Skettenis   EAX * 4, ECX * 4, EDX * 4, EBX * 4,
61b725ae77Skettenis   UESP * 4, EBP * 4, ESI * 4, EDI * 4,
62b725ae77Skettenis   EIP * 4, EFL * 4, CS * 4, SS * 4,
63b725ae77Skettenis   DS * 4, ES * 4, FS * 4, GS * 4
64b725ae77Skettenis };
65b725ae77Skettenis 
66*11efff7fSkettenis /* Called by libthread_db.  */
67*11efff7fSkettenis 
68*11efff7fSkettenis ps_err_e
ps_get_thread_area(const struct ps_prochandle * ph,lwpid_t lwpid,int idx,void ** base)69*11efff7fSkettenis ps_get_thread_area (const struct ps_prochandle *ph,
70*11efff7fSkettenis 		    lwpid_t lwpid, int idx, void **base)
71*11efff7fSkettenis {
72*11efff7fSkettenis   unsigned int desc[4];
73*11efff7fSkettenis 
74*11efff7fSkettenis   if (ptrace (PTRACE_GET_THREAD_AREA, lwpid,
75*11efff7fSkettenis 	      (void *) idx, (unsigned long) &desc) < 0)
76*11efff7fSkettenis     return PS_ERR;
77*11efff7fSkettenis 
78*11efff7fSkettenis   *(int *)base = desc[1];
79*11efff7fSkettenis   return PS_OK;
80*11efff7fSkettenis }
81*11efff7fSkettenis 
82b725ae77Skettenis static int
i386_cannot_store_register(int regno)83b725ae77Skettenis i386_cannot_store_register (int regno)
84b725ae77Skettenis {
85b725ae77Skettenis   return (regno >= i386_num_regs);
86b725ae77Skettenis }
87b725ae77Skettenis 
88b725ae77Skettenis static int
i386_cannot_fetch_register(int regno)89b725ae77Skettenis i386_cannot_fetch_register (int regno)
90b725ae77Skettenis {
91b725ae77Skettenis   return (regno >= i386_num_regs);
92b725ae77Skettenis }
93b725ae77Skettenis 
94b725ae77Skettenis 
95b725ae77Skettenis #ifdef HAVE_LINUX_REGSETS
96b725ae77Skettenis #include <sys/procfs.h>
97b725ae77Skettenis #include <sys/ptrace.h>
98b725ae77Skettenis 
99b725ae77Skettenis static void
i386_fill_gregset(void * buf)100b725ae77Skettenis i386_fill_gregset (void *buf)
101b725ae77Skettenis {
102b725ae77Skettenis   int i;
103b725ae77Skettenis 
104b725ae77Skettenis   for (i = 0; i < i386_num_regs; i++)
105b725ae77Skettenis     collect_register (i, ((char *) buf) + i386_regmap[i]);
106b725ae77Skettenis 
107b725ae77Skettenis   collect_register_by_name ("orig_eax", ((char *) buf) + ORIG_EAX * 4);
108b725ae77Skettenis }
109b725ae77Skettenis 
110b725ae77Skettenis static void
i386_store_gregset(const void * buf)111b725ae77Skettenis i386_store_gregset (const void *buf)
112b725ae77Skettenis {
113b725ae77Skettenis   int i;
114b725ae77Skettenis 
115b725ae77Skettenis   for (i = 0; i < i386_num_regs; i++)
116b725ae77Skettenis     supply_register (i, ((char *) buf) + i386_regmap[i]);
117b725ae77Skettenis 
118b725ae77Skettenis   supply_register_by_name ("orig_eax", ((char *) buf) + ORIG_EAX * 4);
119b725ae77Skettenis }
120b725ae77Skettenis 
121b725ae77Skettenis static void
i386_fill_fpregset(void * buf)122b725ae77Skettenis i386_fill_fpregset (void *buf)
123b725ae77Skettenis {
124b725ae77Skettenis   i387_cache_to_fsave (buf);
125b725ae77Skettenis }
126b725ae77Skettenis 
127b725ae77Skettenis static void
i386_store_fpregset(const void * buf)128b725ae77Skettenis i386_store_fpregset (const void *buf)
129b725ae77Skettenis {
130b725ae77Skettenis   i387_fsave_to_cache (buf);
131b725ae77Skettenis }
132b725ae77Skettenis 
133b725ae77Skettenis static void
i386_fill_fpxregset(void * buf)134b725ae77Skettenis i386_fill_fpxregset (void *buf)
135b725ae77Skettenis {
136b725ae77Skettenis   i387_cache_to_fxsave (buf);
137b725ae77Skettenis }
138b725ae77Skettenis 
139b725ae77Skettenis static void
i386_store_fpxregset(const void * buf)140b725ae77Skettenis i386_store_fpxregset (const void *buf)
141b725ae77Skettenis {
142b725ae77Skettenis   i387_fxsave_to_cache (buf);
143b725ae77Skettenis }
144b725ae77Skettenis 
145b725ae77Skettenis 
146b725ae77Skettenis struct regset_info target_regsets[] = {
147b725ae77Skettenis   { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
148b725ae77Skettenis     GENERAL_REGS,
149b725ae77Skettenis     i386_fill_gregset, i386_store_gregset },
150b725ae77Skettenis #ifdef HAVE_PTRACE_GETFPXREGS
151b725ae77Skettenis   { PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, sizeof (elf_fpxregset_t),
152b725ae77Skettenis     EXTENDED_REGS,
153b725ae77Skettenis     i386_fill_fpxregset, i386_store_fpxregset },
154b725ae77Skettenis #endif
155b725ae77Skettenis   { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
156b725ae77Skettenis     FP_REGS,
157b725ae77Skettenis     i386_fill_fpregset, i386_store_fpregset },
158b725ae77Skettenis   { 0, 0, -1, -1, NULL, NULL }
159b725ae77Skettenis };
160b725ae77Skettenis 
161b725ae77Skettenis #endif /* HAVE_LINUX_REGSETS */
162b725ae77Skettenis 
163b725ae77Skettenis static const char i386_breakpoint[] = { 0xCC };
164b725ae77Skettenis #define i386_breakpoint_len 1
165b725ae77Skettenis 
166b725ae77Skettenis extern int debug_threads;
167b725ae77Skettenis 
168b725ae77Skettenis static CORE_ADDR
i386_get_pc()169b725ae77Skettenis i386_get_pc ()
170b725ae77Skettenis {
171b725ae77Skettenis   unsigned long pc;
172b725ae77Skettenis 
173b725ae77Skettenis   collect_register_by_name ("eip", &pc);
174b725ae77Skettenis 
175b725ae77Skettenis   if (debug_threads)
176b725ae77Skettenis     fprintf (stderr, "stop pc (before any decrement) is %08lx\n", pc);
177b725ae77Skettenis   return pc;
178b725ae77Skettenis }
179b725ae77Skettenis 
180b725ae77Skettenis static void
i386_set_pc(CORE_ADDR newpc)181b725ae77Skettenis i386_set_pc (CORE_ADDR newpc)
182b725ae77Skettenis {
183b725ae77Skettenis   if (debug_threads)
184b725ae77Skettenis     fprintf (stderr, "set pc to %08lx\n", (long) newpc);
185b725ae77Skettenis   supply_register_by_name ("eip", &newpc);
186b725ae77Skettenis }
187b725ae77Skettenis 
188b725ae77Skettenis static int
i386_breakpoint_at(CORE_ADDR pc)189b725ae77Skettenis i386_breakpoint_at (CORE_ADDR pc)
190b725ae77Skettenis {
191b725ae77Skettenis   unsigned char c;
192b725ae77Skettenis 
193b725ae77Skettenis   read_inferior_memory (pc, &c, 1);
194b725ae77Skettenis   if (c == 0xCC)
195b725ae77Skettenis     return 1;
196b725ae77Skettenis 
197b725ae77Skettenis   return 0;
198b725ae77Skettenis }
199b725ae77Skettenis 
200b725ae77Skettenis struct linux_target_ops the_low_target = {
201b725ae77Skettenis   i386_num_regs,
202b725ae77Skettenis   i386_regmap,
203b725ae77Skettenis   i386_cannot_fetch_register,
204b725ae77Skettenis   i386_cannot_store_register,
205b725ae77Skettenis   i386_get_pc,
206b725ae77Skettenis   i386_set_pc,
207b725ae77Skettenis   i386_breakpoint,
208b725ae77Skettenis   i386_breakpoint_len,
209b725ae77Skettenis   NULL,
210b725ae77Skettenis   1,
211b725ae77Skettenis   i386_breakpoint_at,
212b725ae77Skettenis };
213