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