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