Implement debugging of WOW64 processes in gdbserver
[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 {
165 case Z_PACKET_WRITE_WP:
166 case Z_PACKET_ACCESS_WP:
167 return 1;
168 default:
169 return 0;
170 }
171}
172
173static int
174i386_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
175 int size, struct raw_breakpoint *bp)
aa5ca48f
DE
176{
177 switch (type)
178 {
802e8e6d
PA
179 case raw_bkpt_type_write_wp:
180 case raw_bkpt_type_access_wp:
a4165e94 181 {
802e8e6d
PA
182 enum target_hw_bp_type hw_type
183 = raw_bkpt_type_to_target_hw_bp_type (type);
a4165e94 184
df7e5265
GB
185 return x86_dr_insert_watchpoint (&debug_reg_state,
186 hw_type, addr, size);
a4165e94 187 }
aa5ca48f
DE
188 default:
189 /* Unsupported. */
190 return 1;
191 }
192}
193
194static int
802e8e6d
PA
195i386_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
196 int size, struct raw_breakpoint *bp)
aa5ca48f
DE
197{
198 switch (type)
199 {
802e8e6d
PA
200 case raw_bkpt_type_write_wp:
201 case raw_bkpt_type_access_wp:
a4165e94 202 {
802e8e6d
PA
203 enum target_hw_bp_type hw_type
204 = raw_bkpt_type_to_target_hw_bp_type (type);
a4165e94 205
df7e5265
GB
206 return x86_dr_remove_watchpoint (&debug_reg_state,
207 hw_type, addr, size);
a4165e94 208 }
aa5ca48f
DE
209 default:
210 /* Unsupported. */
211 return 1;
212 }
213}
214
215static int
df7e5265 216x86_stopped_by_watchpoint (void)
aa5ca48f 217{
df7e5265 218 return x86_dr_stopped_by_watchpoint (&debug_reg_state);
aa5ca48f
DE
219}
220
221static CORE_ADDR
df7e5265 222x86_stopped_data_address (void)
aa5ca48f
DE
223{
224 CORE_ADDR addr;
df7e5265 225 if (x86_dr_stopped_data_address (&debug_reg_state, &addr))
aa5ca48f
DE
226 return addr;
227 return 0;
228}
229
68070c10 230static void
34b34921 231i386_initial_stuff (void)
68070c10 232{
df7e5265 233 x86_low_init_dregs (&debug_reg_state);
68070c10
PA
234}
235
236static void
e56f8ccb 237i386_get_thread_context (windows_thread_info *th)
68070c10 238{
912cf4ba
PA
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;
34b34921 242
912cf4ba 243 again:
7d186bc0
HD
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);
912cf4ba 256
7d186bc0
HD
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)
912cf4ba
PA
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 }
68070c10
PA
276}
277
278static void
e56f8ccb 279i386_prepare_to_resume (windows_thread_info *th)
68070c10 280{
a2abc7de 281 if (th->debug_registers_changed)
34b34921 282 {
df7e5265 283 struct x86_debug_reg_state *dr = &debug_reg_state;
a2abc7de
PA
284
285 win32_require_context (th);
286
7d186bc0
HD
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 }
34b34921 309
62fe396b 310 th->debug_registers_changed = false;
a2abc7de 311 }
68070c10
PA
312}
313
68070c10 314static void
e56f8ccb 315i386_thread_added (windows_thread_info *th)
68070c10 316{
62fe396b 317 th->debug_registers_changed = true;
68070c10
PA
318}
319
320static void
e56f8ccb 321i386_single_step (windows_thread_info *th)
68070c10 322{
7d186bc0
HD
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;
68070c10
PA
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. */
7d186bc0
HD
338#ifdef __x86_64__
339#define context_offset(x) (offsetof (WOW64_CONTEXT, x))
340#else
68070c10 341#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
7d186bc0
HD
342#endif
343static const int i386_mappings[] = {
68070c10
PA
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
7d186bc0 390#ifdef __x86_64__
54709339
PM
391
392#define context_offset(x) (offsetof (CONTEXT, x))
7d186bc0 393static const int amd64_mappings[] =
54709339
PM
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
1c07cc19 457#endif /* __x86_64__ */
54709339 458
34b34921
PA
459/* Fetch register from gdbserver regcache data. */
460static void
442ea881 461i386_fetch_inferior_register (struct regcache *regcache,
e56f8ccb 462 windows_thread_info *th, int r)
34b34921 463{
7d186bc0
HD
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];
34b34921
PA
479
480 long l;
481 if (r == FCS_REGNUM)
482 {
483 l = *((long *) context_offset) & 0xffff;
442ea881 484 supply_register (regcache, r, (char *) &l);
34b34921
PA
485 }
486 else if (r == FOP_REGNUM)
487 {
488 l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
442ea881 489 supply_register (regcache, r, (char *) &l);
34b34921
PA
490 }
491 else
442ea881 492 supply_register (regcache, r, context_offset);
34b34921
PA
493}
494
495/* Store a new register value into the thread context of TH. */
496static void
442ea881 497i386_store_inferior_register (struct regcache *regcache,
e56f8ccb 498 windows_thread_info *th, int r)
34b34921 499{
7d186bc0
HD
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
442ea881 516 collect_register (regcache, r, context_offset);
34b34921
PA
517}
518
912cf4ba
PA
519static const unsigned char i386_win32_breakpoint = 0xcc;
520#define i386_win32_breakpoint_len 1
521
54709339 522static void
3aee8918 523i386_arch_setup (void)
54709339 524{
cc4d742f
SM
525 struct target_desc *tdesc;
526
1c07cc19 527#ifdef __x86_64__
cc4d742f 528 tdesc = amd64_create_target_description (X86_XSTATE_SSE_MASK, false,
de52b960 529 false, false);
7d186bc0
HD
530 init_target_desc (tdesc, amd64_expedite_regs);
531 win32_tdesc = tdesc;
532#endif
533
1163a4b7 534 tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false);
7d186bc0
HD
535 init_target_desc (tdesc, i386_expedite_regs);
536#ifdef __x86_64__
537 wow64_win32_tdesc = tdesc;
538#else
539 win32_tdesc = tdesc;
54709339 540#endif
7d186bc0 541}
cc4d742f 542
7d186bc0 543/* Implement win32_target_ops "num_regs" method. */
cc4d742f 544
7d186bc0
HD
545static int
546i386_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;
54709339
PM
556}
557
d6225aff
TT
558/* Implement win32_target_ops "get_pc" method. */
559
560static CORE_ADDR
561i386_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
583static void
584i386_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
68070c10 602struct win32_target_ops the_low_target = {
3aee8918 603 i386_arch_setup,
7d186bc0 604 i386_win32_num_regs,
34b34921
PA
605 i386_initial_stuff,
606 i386_get_thread_context,
a2abc7de 607 i386_prepare_to_resume,
34b34921
PA
608 i386_thread_added,
609 i386_fetch_inferior_register,
610 i386_store_inferior_register,
611 i386_single_step,
912cf4ba
PA
612 &i386_win32_breakpoint,
613 i386_win32_breakpoint_len,
e54e5929 614 1,
d6225aff
TT
615 i386_win32_get_pc,
616 i386_win32_set_pc,
802e8e6d 617 i386_supports_z_point_type,
aa5ca48f
DE
618 i386_insert_point,
619 i386_remove_point,
df7e5265
GB
620 x86_stopped_by_watchpoint,
621 x86_stopped_data_address
68070c10 622};
This page took 1.240364 seconds and 4 git commands to generate.