gdb: small cleanup of async-event.c structs
[deliverable/binutils-gdb.git] / gdbserver / win32-i386-low.cc
1 /* Copyright (C) 2007-2020 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 #include "x86-low.h"
21 #include "gdbsupport/x86-xstate.h"
22 #ifdef __x86_64__
23 #include "arch/amd64.h"
24 #endif
25 #include "arch/i386.h"
26 #include "tdesc.h"
27 #include "x86-tdesc.h"
28
29 using namespace windows_nat;
30
31 #ifndef CONTEXT_EXTENDED_REGISTERS
32 #define CONTEXT_EXTENDED_REGISTERS 0
33 #endif
34
35 #define FCS_REGNUM 27
36 #define FOP_REGNUM 31
37
38 #define FLAG_TRACE_BIT 0x100
39
40 static struct x86_debug_reg_state debug_reg_state;
41
42 static void
43 update_debug_registers (thread_info *thread)
44 {
45 windows_thread_info *th = (windows_thread_info *) thread_target_data (thread);
46
47 /* The actual update is done later just before resuming the lwp,
48 we just mark that the registers need updating. */
49 th->debug_registers_changed = true;
50 }
51
52 /* Update the inferior's debug register REGNUM from STATE. */
53
54 static void
55 x86_dr_low_set_addr (int regnum, CORE_ADDR addr)
56 {
57 gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
58
59 /* Only update the threads of this process. */
60 for_each_thread (current_thread->id.pid (), update_debug_registers);
61 }
62
63 /* Update the inferior's DR7 debug control register from STATE. */
64
65 static void
66 x86_dr_low_set_control (unsigned long control)
67 {
68 /* Only update the threads of this process. */
69 for_each_thread (current_thread->id.pid (), update_debug_registers);
70 }
71
72 /* Return the current value of a DR register of the current thread's
73 context. */
74
75 static DWORD64
76 win32_get_current_dr (int dr)
77 {
78 windows_thread_info *th
79 = (windows_thread_info *) thread_target_data (current_thread);
80
81 win32_require_context (th);
82
83 #ifdef __x86_64__
84 #define RET_DR(DR) \
85 case DR: \
86 return th->wow64_context.Dr ## DR
87
88 if (wow64_process)
89 {
90 switch (dr)
91 {
92 RET_DR (0);
93 RET_DR (1);
94 RET_DR (2);
95 RET_DR (3);
96 RET_DR (6);
97 RET_DR (7);
98 }
99 }
100 else
101 #undef RET_DR
102 #endif
103 #define RET_DR(DR) \
104 case DR: \
105 return th->context.Dr ## DR
106
107 {
108 switch (dr)
109 {
110 RET_DR (0);
111 RET_DR (1);
112 RET_DR (2);
113 RET_DR (3);
114 RET_DR (6);
115 RET_DR (7);
116 }
117 }
118
119 #undef RET_DR
120
121 gdb_assert_not_reached ("unhandled dr");
122 }
123
124 static CORE_ADDR
125 x86_dr_low_get_addr (int regnum)
126 {
127 gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
128
129 return win32_get_current_dr (regnum - DR_FIRSTADDR);
130 }
131
132 static unsigned long
133 x86_dr_low_get_control (void)
134 {
135 return win32_get_current_dr (7);
136 }
137
138 /* Get the value of the DR6 debug status register from the inferior
139 and record it in STATE. */
140
141 static unsigned long
142 x86_dr_low_get_status (void)
143 {
144 return win32_get_current_dr (6);
145 }
146
147 /* Low-level function vector. */
148 struct x86_dr_low_type x86_dr_low =
149 {
150 x86_dr_low_set_control,
151 x86_dr_low_set_addr,
152 x86_dr_low_get_addr,
153 x86_dr_low_get_status,
154 x86_dr_low_get_control,
155 sizeof (void *),
156 };
157
158 /* Breakpoint/watchpoint support. */
159
160 static int
161 i386_supports_z_point_type (char z_type)
162 {
163 switch (z_type)
164 {
165 case Z_PACKET_WRITE_WP:
166 case Z_PACKET_ACCESS_WP:
167 return 1;
168 default:
169 return 0;
170 }
171 }
172
173 static int
174 i386_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
175 int size, struct raw_breakpoint *bp)
176 {
177 switch (type)
178 {
179 case raw_bkpt_type_write_wp:
180 case raw_bkpt_type_access_wp:
181 {
182 enum target_hw_bp_type hw_type
183 = raw_bkpt_type_to_target_hw_bp_type (type);
184
185 return x86_dr_insert_watchpoint (&debug_reg_state,
186 hw_type, addr, size);
187 }
188 default:
189 /* Unsupported. */
190 return 1;
191 }
192 }
193
194 static int
195 i386_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
196 int size, struct raw_breakpoint *bp)
197 {
198 switch (type)
199 {
200 case raw_bkpt_type_write_wp:
201 case raw_bkpt_type_access_wp:
202 {
203 enum target_hw_bp_type hw_type
204 = raw_bkpt_type_to_target_hw_bp_type (type);
205
206 return x86_dr_remove_watchpoint (&debug_reg_state,
207 hw_type, addr, size);
208 }
209 default:
210 /* Unsupported. */
211 return 1;
212 }
213 }
214
215 static int
216 x86_stopped_by_watchpoint (void)
217 {
218 return x86_dr_stopped_by_watchpoint (&debug_reg_state);
219 }
220
221 static CORE_ADDR
222 x86_stopped_data_address (void)
223 {
224 CORE_ADDR addr;
225 if (x86_dr_stopped_data_address (&debug_reg_state, &addr))
226 return addr;
227 return 0;
228 }
229
230 static void
231 i386_initial_stuff (void)
232 {
233 x86_low_init_dregs (&debug_reg_state);
234 }
235
236 static void
237 i386_get_thread_context (windows_thread_info *th)
238 {
239 /* Requesting the CONTEXT_EXTENDED_REGISTERS register set fails if
240 the system doesn't support extended registers. */
241 static DWORD extended_registers = CONTEXT_EXTENDED_REGISTERS;
242
243 again:
244 #ifdef __x86_64__
245 if (wow64_process)
246 th->wow64_context.ContextFlags = (CONTEXT_FULL
247 | CONTEXT_FLOATING_POINT
248 | CONTEXT_DEBUG_REGISTERS
249 | extended_registers);
250 else
251 #endif
252 th->context.ContextFlags = (CONTEXT_FULL
253 | CONTEXT_FLOATING_POINT
254 | CONTEXT_DEBUG_REGISTERS
255 | extended_registers);
256
257 BOOL ret;
258 #ifdef __x86_64__
259 if (wow64_process)
260 ret = win32_Wow64GetThreadContext (th->h, &th->wow64_context);
261 else
262 #endif
263 ret = GetThreadContext (th->h, &th->context);
264 if (!ret)
265 {
266 DWORD e = GetLastError ();
267
268 if (extended_registers && e == ERROR_INVALID_PARAMETER)
269 {
270 extended_registers = 0;
271 goto again;
272 }
273
274 error ("GetThreadContext failure %ld\n", (long) e);
275 }
276 }
277
278 static void
279 i386_prepare_to_resume (windows_thread_info *th)
280 {
281 if (th->debug_registers_changed)
282 {
283 struct x86_debug_reg_state *dr = &debug_reg_state;
284
285 win32_require_context (th);
286
287 #ifdef __x86_64__
288 if (wow64_process)
289 {
290 th->wow64_context.Dr0 = dr->dr_mirror[0];
291 th->wow64_context.Dr1 = dr->dr_mirror[1];
292 th->wow64_context.Dr2 = dr->dr_mirror[2];
293 th->wow64_context.Dr3 = dr->dr_mirror[3];
294 /* th->wow64_context.Dr6 = dr->dr_status_mirror;
295 FIXME: should we set dr6 also ?? */
296 th->wow64_context.Dr7 = dr->dr_control_mirror;
297 }
298 else
299 #endif
300 {
301 th->context.Dr0 = dr->dr_mirror[0];
302 th->context.Dr1 = dr->dr_mirror[1];
303 th->context.Dr2 = dr->dr_mirror[2];
304 th->context.Dr3 = dr->dr_mirror[3];
305 /* th->context.Dr6 = dr->dr_status_mirror;
306 FIXME: should we set dr6 also ?? */
307 th->context.Dr7 = dr->dr_control_mirror;
308 }
309
310 th->debug_registers_changed = false;
311 }
312 }
313
314 static void
315 i386_thread_added (windows_thread_info *th)
316 {
317 th->debug_registers_changed = true;
318 }
319
320 static void
321 i386_single_step (windows_thread_info *th)
322 {
323 #ifdef __x86_64__
324 if (wow64_process)
325 th->wow64_context.EFlags |= FLAG_TRACE_BIT;
326 else
327 #endif
328 th->context.EFlags |= FLAG_TRACE_BIT;
329 }
330
331 /* An array of offset mappings into a Win32 Context structure.
332 This is a one-to-one mapping which is indexed by gdb's register
333 numbers. It retrieves an offset into the context structure where
334 the 4 byte register is located.
335 An offset value of -1 indicates that Win32 does not provide this
336 register in it's CONTEXT structure. In this case regptr will return
337 a pointer into a dummy register. */
338 #ifdef __x86_64__
339 #define context_offset(x) (offsetof (WOW64_CONTEXT, x))
340 #else
341 #define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
342 #endif
343 static const int i386_mappings[] = {
344 context_offset (Eax),
345 context_offset (Ecx),
346 context_offset (Edx),
347 context_offset (Ebx),
348 context_offset (Esp),
349 context_offset (Ebp),
350 context_offset (Esi),
351 context_offset (Edi),
352 context_offset (Eip),
353 context_offset (EFlags),
354 context_offset (SegCs),
355 context_offset (SegSs),
356 context_offset (SegDs),
357 context_offset (SegEs),
358 context_offset (SegFs),
359 context_offset (SegGs),
360 context_offset (FloatSave.RegisterArea[0 * 10]),
361 context_offset (FloatSave.RegisterArea[1 * 10]),
362 context_offset (FloatSave.RegisterArea[2 * 10]),
363 context_offset (FloatSave.RegisterArea[3 * 10]),
364 context_offset (FloatSave.RegisterArea[4 * 10]),
365 context_offset (FloatSave.RegisterArea[5 * 10]),
366 context_offset (FloatSave.RegisterArea[6 * 10]),
367 context_offset (FloatSave.RegisterArea[7 * 10]),
368 context_offset (FloatSave.ControlWord),
369 context_offset (FloatSave.StatusWord),
370 context_offset (FloatSave.TagWord),
371 context_offset (FloatSave.ErrorSelector),
372 context_offset (FloatSave.ErrorOffset),
373 context_offset (FloatSave.DataSelector),
374 context_offset (FloatSave.DataOffset),
375 context_offset (FloatSave.ErrorSelector),
376 /* XMM0-7 */
377 context_offset (ExtendedRegisters[10 * 16]),
378 context_offset (ExtendedRegisters[11 * 16]),
379 context_offset (ExtendedRegisters[12 * 16]),
380 context_offset (ExtendedRegisters[13 * 16]),
381 context_offset (ExtendedRegisters[14 * 16]),
382 context_offset (ExtendedRegisters[15 * 16]),
383 context_offset (ExtendedRegisters[16 * 16]),
384 context_offset (ExtendedRegisters[17 * 16]),
385 /* MXCSR */
386 context_offset (ExtendedRegisters[24])
387 };
388 #undef context_offset
389
390 #ifdef __x86_64__
391
392 #define context_offset(x) (offsetof (CONTEXT, x))
393 static const int amd64_mappings[] =
394 {
395 context_offset (Rax),
396 context_offset (Rbx),
397 context_offset (Rcx),
398 context_offset (Rdx),
399 context_offset (Rsi),
400 context_offset (Rdi),
401 context_offset (Rbp),
402 context_offset (Rsp),
403 context_offset (R8),
404 context_offset (R9),
405 context_offset (R10),
406 context_offset (R11),
407 context_offset (R12),
408 context_offset (R13),
409 context_offset (R14),
410 context_offset (R15),
411 context_offset (Rip),
412 context_offset (EFlags),
413 context_offset (SegCs),
414 context_offset (SegSs),
415 context_offset (SegDs),
416 context_offset (SegEs),
417 context_offset (SegFs),
418 context_offset (SegGs),
419 context_offset (FloatSave.FloatRegisters[0]),
420 context_offset (FloatSave.FloatRegisters[1]),
421 context_offset (FloatSave.FloatRegisters[2]),
422 context_offset (FloatSave.FloatRegisters[3]),
423 context_offset (FloatSave.FloatRegisters[4]),
424 context_offset (FloatSave.FloatRegisters[5]),
425 context_offset (FloatSave.FloatRegisters[6]),
426 context_offset (FloatSave.FloatRegisters[7]),
427 context_offset (FloatSave.ControlWord),
428 context_offset (FloatSave.StatusWord),
429 context_offset (FloatSave.TagWord),
430 context_offset (FloatSave.ErrorSelector),
431 context_offset (FloatSave.ErrorOffset),
432 context_offset (FloatSave.DataSelector),
433 context_offset (FloatSave.DataOffset),
434 context_offset (FloatSave.ErrorSelector)
435 /* XMM0-7 */ ,
436 context_offset (Xmm0),
437 context_offset (Xmm1),
438 context_offset (Xmm2),
439 context_offset (Xmm3),
440 context_offset (Xmm4),
441 context_offset (Xmm5),
442 context_offset (Xmm6),
443 context_offset (Xmm7),
444 context_offset (Xmm8),
445 context_offset (Xmm9),
446 context_offset (Xmm10),
447 context_offset (Xmm11),
448 context_offset (Xmm12),
449 context_offset (Xmm13),
450 context_offset (Xmm14),
451 context_offset (Xmm15),
452 /* MXCSR */
453 context_offset (FloatSave.MxCsr)
454 };
455 #undef context_offset
456
457 #endif /* __x86_64__ */
458
459 /* Fetch register from gdbserver regcache data. */
460 static void
461 i386_fetch_inferior_register (struct regcache *regcache,
462 windows_thread_info *th, int r)
463 {
464 const int *mappings;
465 #ifdef __x86_64__
466 if (!wow64_process)
467 mappings = amd64_mappings;
468 else
469 #endif
470 mappings = i386_mappings;
471
472 char *context_offset;
473 #ifdef __x86_64__
474 if (wow64_process)
475 context_offset = (char *) &th->wow64_context + mappings[r];
476 else
477 #endif
478 context_offset = (char *) &th->context + mappings[r];
479
480 long l;
481 if (r == FCS_REGNUM)
482 {
483 l = *((long *) context_offset) & 0xffff;
484 supply_register (regcache, r, (char *) &l);
485 }
486 else if (r == FOP_REGNUM)
487 {
488 l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
489 supply_register (regcache, r, (char *) &l);
490 }
491 else
492 supply_register (regcache, r, context_offset);
493 }
494
495 /* Store a new register value into the thread context of TH. */
496 static void
497 i386_store_inferior_register (struct regcache *regcache,
498 windows_thread_info *th, int r)
499 {
500 const int *mappings;
501 #ifdef __x86_64__
502 if (!wow64_process)
503 mappings = amd64_mappings;
504 else
505 #endif
506 mappings = i386_mappings;
507
508 char *context_offset;
509 #ifdef __x86_64__
510 if (wow64_process)
511 context_offset = (char *) &th->wow64_context + mappings[r];
512 else
513 #endif
514 context_offset = (char *) &th->context + mappings[r];
515
516 collect_register (regcache, r, context_offset);
517 }
518
519 static const unsigned char i386_win32_breakpoint = 0xcc;
520 #define i386_win32_breakpoint_len 1
521
522 static void
523 i386_arch_setup (void)
524 {
525 struct target_desc *tdesc;
526
527 #ifdef __x86_64__
528 tdesc = amd64_create_target_description (X86_XSTATE_SSE_MASK, false,
529 false, false);
530 init_target_desc (tdesc, amd64_expedite_regs);
531 win32_tdesc = tdesc;
532 #endif
533
534 tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false);
535 init_target_desc (tdesc, i386_expedite_regs);
536 #ifdef __x86_64__
537 wow64_win32_tdesc = tdesc;
538 #else
539 win32_tdesc = tdesc;
540 #endif
541 }
542
543 /* Implement win32_target_ops "num_regs" method. */
544
545 static int
546 i386_win32_num_regs (void)
547 {
548 int num_regs;
549 #ifdef __x86_64__
550 if (!wow64_process)
551 num_regs = sizeof (amd64_mappings) / sizeof (amd64_mappings[0]);
552 else
553 #endif
554 num_regs = sizeof (i386_mappings) / sizeof (i386_mappings[0]);
555 return num_regs;
556 }
557
558 /* Implement win32_target_ops "get_pc" method. */
559
560 static CORE_ADDR
561 i386_win32_get_pc (struct regcache *regcache)
562 {
563 bool use_64bit = register_size (regcache->tdesc, 0) == 8;
564
565 if (use_64bit)
566 {
567 uint64_t pc;
568
569 collect_register_by_name (regcache, "rip", &pc);
570 return (CORE_ADDR) pc;
571 }
572 else
573 {
574 uint32_t pc;
575
576 collect_register_by_name (regcache, "eip", &pc);
577 return (CORE_ADDR) pc;
578 }
579 }
580
581 /* Implement win32_target_ops "set_pc" method. */
582
583 static void
584 i386_win32_set_pc (struct regcache *regcache, CORE_ADDR pc)
585 {
586 bool use_64bit = register_size (regcache->tdesc, 0) == 8;
587
588 if (use_64bit)
589 {
590 uint64_t newpc = pc;
591
592 supply_register_by_name (regcache, "rip", &newpc);
593 }
594 else
595 {
596 uint32_t newpc = pc;
597
598 supply_register_by_name (regcache, "eip", &newpc);
599 }
600 }
601
602 struct win32_target_ops the_low_target = {
603 i386_arch_setup,
604 i386_win32_num_regs,
605 i386_initial_stuff,
606 i386_get_thread_context,
607 i386_prepare_to_resume,
608 i386_thread_added,
609 i386_fetch_inferior_register,
610 i386_store_inferior_register,
611 i386_single_step,
612 &i386_win32_breakpoint,
613 i386_win32_breakpoint_len,
614 1,
615 i386_win32_get_pc,
616 i386_win32_set_pc,
617 i386_supports_z_point_type,
618 i386_insert_point,
619 i386_remove_point,
620 x86_stopped_by_watchpoint,
621 x86_stopped_data_address
622 };
This page took 0.054217 seconds and 4 git commands to generate.