| /* Target-dependent code for Windows (including Cygwin) running on i386's, | 
 |    for GDB. | 
 |  | 
 |    Copyright (C) 2003-2023 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "defs.h" | 
 | #include "osabi.h" | 
 | #include "i386-tdep.h" | 
 | #include "windows-tdep.h" | 
 | #include "regset.h" | 
 | #include "gdbsupport/gdb_obstack.h" | 
 | #include "xml-support.h" | 
 | #include "gdbcore.h" | 
 | #include "inferior.h" | 
 |  | 
 | /* Core file support.  */ | 
 |  | 
 | /* This vector maps GDB's idea of a register's number into an address | 
 |    in the windows exception context vector.  */ | 
 |  | 
 | static int i386_windows_gregset_reg_offset[] = | 
 | { | 
 |   176, /* eax */ | 
 |   172, /* ecx */ | 
 |   168, /* edx */ | 
 |   164, /* ebx */ | 
 |  | 
 |   196, /* esp */ | 
 |   180, /* ebp */ | 
 |   160, /* esi */ | 
 |   156, /* edi */ | 
 |  | 
 |   184, /* eip */ | 
 |   192, /* eflags */ | 
 |   188, /* cs */ | 
 |   200, /* ss */ | 
 |  | 
 |   152, /* ds */ | 
 |   148, /* es */ | 
 |   144, /* fs */ | 
 |   140, /* gs */ | 
 |  | 
 |   56, /* FloatSave.RegisterArea[0 * 10] */ | 
 |   66, /* FloatSave.RegisterArea[1 * 10] */ | 
 |   76, /* FloatSave.RegisterArea[2 * 10] */ | 
 |   86, /* FloatSave.RegisterArea[3 * 10] */ | 
 |   96, /* FloatSave.RegisterArea[4 * 10] */ | 
 |   106, /* FloatSave.RegisterArea[5 * 10] */ | 
 |   116, /* FloatSave.RegisterArea[6 * 10] */ | 
 |   126, /* FloatSave.RegisterArea[7 * 10] */ | 
 |  | 
 |   28, /* FloatSave.ControlWord */ | 
 |   32, /* FloatSave.StatusWord */ | 
 |   36, /* FloatSave.TagWord */ | 
 |   44, /* FloatSave.ErrorSelector */ | 
 |   40, /* FloatSave.ErrorOffset */ | 
 |   52, /* FloatSave.DataSelector */ | 
 |   48, /* FloatSave.DataOffset */ | 
 |   44, /* FloatSave.ErrorSelector */ | 
 |  | 
 |   /* XMM0-7 */ | 
 |   364, /* ExtendedRegisters[10*16] */ | 
 |   380, /* ExtendedRegisters[11*16] */ | 
 |   396, /* ExtendedRegisters[12*16] */ | 
 |   412, /* ExtendedRegisters[13*16] */ | 
 |   428, /* ExtendedRegisters[14*16] */ | 
 |   444, /* ExtendedRegisters[15*16] */ | 
 |   460, /* ExtendedRegisters[16*16] */ | 
 |   476, /* ExtendedRegisters[17*16] */ | 
 |  | 
 |   /* MXCSR */ | 
 |   228 /* ExtendedRegisters[24] */ | 
 | }; | 
 |  | 
 | #define I386_WINDOWS_SIZEOF_GREGSET 716 | 
 |  | 
 | static CORE_ADDR | 
 | i386_windows_skip_trampoline_code (frame_info_ptr frame, CORE_ADDR pc) | 
 | { | 
 |   return i386_pe_skip_trampoline_code (frame, pc, NULL); | 
 | } | 
 |  | 
 | static const char * | 
 | i386_windows_auto_wide_charset (void) | 
 | { | 
 |   return "UTF-16"; | 
 | } | 
 |  | 
 | /* Implement the "push_dummy_call" gdbarch method.  */ | 
 |  | 
 | static CORE_ADDR | 
 | i386_windows_push_dummy_call (struct gdbarch *gdbarch, struct value *function, | 
 | 			      struct regcache *regcache, CORE_ADDR bp_addr, | 
 | 			      int nargs, struct value **args, CORE_ADDR sp, | 
 | 			      function_call_return_method return_method, | 
 | 			      CORE_ADDR struct_addr) | 
 | { | 
 |   /* For non-static member functions of 32bit Windows programs, the thiscall | 
 |      calling convention is used, so the 'this' pointer is passed in ECX.  */ | 
 |   bool thiscall = false; | 
 |  | 
 |   struct type *type = check_typedef (function->type ()); | 
 |   if (type->code () == TYPE_CODE_PTR) | 
 |     type = check_typedef (type->target_type ()); | 
 |  | 
 |   /* read_subroutine_type sets for non-static member functions the | 
 |      artificial flag of the first parameter ('this' pointer).  */ | 
 |   if (type->code () == TYPE_CODE_METHOD | 
 |       && type->num_fields () > 0 | 
 |       && TYPE_FIELD_ARTIFICIAL (type, 0) | 
 |       && type->field (0).type ()->code () == TYPE_CODE_PTR) | 
 |     thiscall = 1; | 
 |  | 
 |   return i386_thiscall_push_dummy_call (gdbarch, function, regcache, bp_addr, | 
 | 					nargs, args, sp, return_method, | 
 | 					struct_addr, thiscall); | 
 | } | 
 |  | 
 | /* Common parts for gdbarch initialization for Windows and Cygwin on i386.  */ | 
 |  | 
 | static void | 
 | i386_windows_init_abi_common (struct gdbarch_info info, struct gdbarch *gdbarch) | 
 | { | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch); | 
 |  | 
 |   set_gdbarch_skip_trampoline_code (gdbarch, i386_windows_skip_trampoline_code); | 
 |  | 
 |   set_gdbarch_skip_main_prologue (gdbarch, i386_skip_main_prologue); | 
 |  | 
 |   tdep->struct_return = reg_struct_return; | 
 |  | 
 |   tdep->gregset_reg_offset = i386_windows_gregset_reg_offset; | 
 |   tdep->gregset_num_regs = ARRAY_SIZE (i386_windows_gregset_reg_offset); | 
 |   tdep->sizeof_gregset = I386_WINDOWS_SIZEOF_GREGSET; | 
 |  | 
 |   tdep->sizeof_fpregset = 0; | 
 |  | 
 |   /* Core file support.  */ | 
 |   set_gdbarch_core_xfer_shared_libraries | 
 |     (gdbarch, windows_core_xfer_shared_libraries); | 
 |   set_gdbarch_core_pid_to_str (gdbarch, windows_core_pid_to_str); | 
 |  | 
 |   set_gdbarch_auto_wide_charset (gdbarch, i386_windows_auto_wide_charset); | 
 | } | 
 |  | 
 | /* gdbarch initialization for Windows on i386.  */ | 
 |  | 
 | static void | 
 | i386_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) | 
 | { | 
 |   i386_windows_init_abi_common (info, gdbarch); | 
 |   windows_init_abi (info, gdbarch); | 
 |  | 
 |   set_gdbarch_push_dummy_call (gdbarch, i386_windows_push_dummy_call); | 
 | } | 
 |  | 
 | /* gdbarch initialization for Cygwin on i386.  */ | 
 |  | 
 | static void | 
 | i386_cygwin_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) | 
 | { | 
 |   i386_windows_init_abi_common (info, gdbarch); | 
 |   cygwin_init_abi (info, gdbarch); | 
 | } | 
 |  | 
 | static gdb_osabi | 
 | i386_windows_osabi_sniffer (bfd *abfd) | 
 | { | 
 |   const char *target_name = bfd_get_target (abfd); | 
 |  | 
 |   if (!streq (target_name, "pei-i386")) | 
 |     return GDB_OSABI_UNKNOWN; | 
 |  | 
 |   if (is_linked_with_cygwin_dll (abfd)) | 
 |     return GDB_OSABI_CYGWIN; | 
 |  | 
 |   return GDB_OSABI_WINDOWS; | 
 | } | 
 |  | 
 | static enum gdb_osabi | 
 | i386_cygwin_core_osabi_sniffer (bfd *abfd) | 
 | { | 
 |   const char *target_name = bfd_get_target (abfd); | 
 |  | 
 |   /* Cygwin uses elf core dumps.  Do not claim all ELF executables, | 
 |      check whether there is a .reg section of proper size.  */ | 
 |   if (strcmp (target_name, "elf32-i386") == 0) | 
 |     { | 
 |       asection *section = bfd_get_section_by_name (abfd, ".reg"); | 
 |       if (section != nullptr | 
 | 	  && bfd_section_size (section) == I386_WINDOWS_SIZEOF_GREGSET) | 
 | 	return GDB_OSABI_CYGWIN; | 
 |     } | 
 |  | 
 |   return GDB_OSABI_UNKNOWN; | 
 | } | 
 |  | 
 | void _initialize_i386_windows_tdep (); | 
 | void | 
 | _initialize_i386_windows_tdep () | 
 | { | 
 |   gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour, | 
 | 				  i386_windows_osabi_sniffer); | 
 |  | 
 |   /* Cygwin uses elf core dumps.  */ | 
 |   gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour, | 
 | 				  i386_cygwin_core_osabi_sniffer); | 
 |  | 
 |   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_WINDOWS, | 
 | 			  i386_windows_init_abi); | 
 |   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_CYGWIN, | 
 | 			  i386_cygwin_init_abi); | 
 | } |