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