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