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