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