1/* Copyright (C) 2007 Free Software Foundation, Inc. 2 3 This file is part of GDB. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18#include "server.h" 19#include "win32-low.h" 20 21#define FCS_REGNUM 27 22#define FOP_REGNUM 31 23 24#define FLAG_TRACE_BIT 0x100 25 26static unsigned dr[8]; 27 28static int debug_registers_changed = 0; 29static int debug_registers_used = 0; 30 31static void 32i386_initial_stuff (void) 33{ 34 memset (&dr, 0, sizeof (dr)); 35 debug_registers_changed = 0; 36 debug_registers_used = 0; 37} 38 39static void 40i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event) 41{ 42 th->context.ContextFlags = \ 43 CONTEXT_FULL | \ 44 CONTEXT_FLOATING_POINT | \ 45 CONTEXT_EXTENDED_REGISTERS | \ 46 CONTEXT_DEBUG_REGISTERS; 47 48 GetThreadContext (th->h, &th->context); 49 50 debug_registers_changed = 0; 51 52 if (th->tid == current_event->dwThreadId) 53 { 54 /* Copy dr values from the current thread. */ 55 dr[0] = th->context.Dr0; 56 dr[1] = th->context.Dr1; 57 dr[2] = th->context.Dr2; 58 dr[3] = th->context.Dr3; 59 dr[6] = th->context.Dr6; 60 dr[7] = th->context.Dr7; 61 } 62} 63 64static void 65i386_set_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event) 66{ 67 if (debug_registers_changed) 68 { 69 th->context.Dr0 = dr[0]; 70 th->context.Dr1 = dr[1]; 71 th->context.Dr2 = dr[2]; 72 th->context.Dr3 = dr[3]; 73 /* th->context.Dr6 = dr[6]; 74 FIXME: should we set dr6 also ?? */ 75 th->context.Dr7 = dr[7]; 76 } 77 78 SetThreadContext (th->h, &th->context); 79} 80 81static void 82i386_thread_added (win32_thread_info *th) 83{ 84 /* Set the debug registers for the new thread if they are used. */ 85 if (debug_registers_used) 86 { 87 th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS; 88 GetThreadContext (th->h, &th->context); 89 90 th->context.Dr0 = dr[0]; 91 th->context.Dr1 = dr[1]; 92 th->context.Dr2 = dr[2]; 93 th->context.Dr3 = dr[3]; 94 /* th->context.Dr6 = dr[6]; 95 FIXME: should we set dr6 also ?? */ 96 th->context.Dr7 = dr[7]; 97 98 SetThreadContext (th->h, &th->context); 99 th->context.ContextFlags = 0; 100 } 101} 102 103static void 104i386_single_step (win32_thread_info *th) 105{ 106 th->context.EFlags |= FLAG_TRACE_BIT; 107} 108 109/* An array of offset mappings into a Win32 Context structure. 110 This is a one-to-one mapping which is indexed by gdb's register 111 numbers. It retrieves an offset into the context structure where 112 the 4 byte register is located. 113 An offset value of -1 indicates that Win32 does not provide this 114 register in it's CONTEXT structure. In this case regptr will return 115 a pointer into a dummy register. */ 116#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x)) 117static const int mappings[] = { 118 context_offset (Eax), 119 context_offset (Ecx), 120 context_offset (Edx), 121 context_offset (Ebx), 122 context_offset (Esp), 123 context_offset (Ebp), 124 context_offset (Esi), 125 context_offset (Edi), 126 context_offset (Eip), 127 context_offset (EFlags), 128 context_offset (SegCs), 129 context_offset (SegSs), 130 context_offset (SegDs), 131 context_offset (SegEs), 132 context_offset (SegFs), 133 context_offset (SegGs), 134 context_offset (FloatSave.RegisterArea[0 * 10]), 135 context_offset (FloatSave.RegisterArea[1 * 10]), 136 context_offset (FloatSave.RegisterArea[2 * 10]), 137 context_offset (FloatSave.RegisterArea[3 * 10]), 138 context_offset (FloatSave.RegisterArea[4 * 10]), 139 context_offset (FloatSave.RegisterArea[5 * 10]), 140 context_offset (FloatSave.RegisterArea[6 * 10]), 141 context_offset (FloatSave.RegisterArea[7 * 10]), 142 context_offset (FloatSave.ControlWord), 143 context_offset (FloatSave.StatusWord), 144 context_offset (FloatSave.TagWord), 145 context_offset (FloatSave.ErrorSelector), 146 context_offset (FloatSave.ErrorOffset), 147 context_offset (FloatSave.DataSelector), 148 context_offset (FloatSave.DataOffset), 149 context_offset (FloatSave.ErrorSelector), 150 /* XMM0-7 */ 151 context_offset (ExtendedRegisters[10 * 16]), 152 context_offset (ExtendedRegisters[11 * 16]), 153 context_offset (ExtendedRegisters[12 * 16]), 154 context_offset (ExtendedRegisters[13 * 16]), 155 context_offset (ExtendedRegisters[14 * 16]), 156 context_offset (ExtendedRegisters[15 * 16]), 157 context_offset (ExtendedRegisters[16 * 16]), 158 context_offset (ExtendedRegisters[17 * 16]), 159 /* MXCSR */ 160 context_offset (ExtendedRegisters[24]) 161}; 162#undef context_offset 163 164/* Fetch register from gdbserver regcache data. */ 165static void 166i386_fetch_inferior_register (win32_thread_info *th, int r) 167{ 168 char *context_offset = (char *) &th->context + mappings[r]; 169 170 long l; 171 if (r == FCS_REGNUM) 172 { 173 l = *((long *) context_offset) & 0xffff; 174 supply_register (r, (char *) &l); 175 } 176 else if (r == FOP_REGNUM) 177 { 178 l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1); 179 supply_register (r, (char *) &l); 180 } 181 else 182 supply_register (r, context_offset); 183} 184 185/* Store a new register value into the thread context of TH. */ 186static void 187i386_store_inferior_register (win32_thread_info *th, int r) 188{ 189 char *context_offset = (char *) &th->context + mappings[r]; 190 collect_register (r, context_offset); 191} 192 193struct win32_target_ops the_low_target = { 194 sizeof (mappings) / sizeof (mappings[0]), 195 i386_initial_stuff, 196 i386_get_thread_context, 197 i386_set_thread_context, 198 i386_thread_added, 199 i386_fetch_inferior_register, 200 i386_store_inferior_register, 201 i386_single_step, 202 NULL, /* breakpoint */ 203 0, /* breakpoint_len */ 204 "i386" /* arch_string */ 205}; 206