From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31239 invoked by alias); 16 Apr 2010 15:32:01 -0000 Received: (qmail 31205 invoked by uid 22791); 16 Apr 2010 15:31:56 -0000 X-SWARE-Spam-Status: No, hits=-0.2 required=5.0 tests=BAYES_05,MSGID_MULTIPLE_AT,TW_AV,TW_EG,TW_GP,TW_OC X-Spam-Check-By: sourceware.org Received: from mailhost.u-strasbg.fr (HELO mailhost.u-strasbg.fr) (130.79.200.157) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 16 Apr 2010 15:31:43 +0000 Received: from baal.u-strasbg.fr (baal.u-strasbg.fr [IPv6:2001:660:2402::41]) by mailhost.u-strasbg.fr (8.14.3/jtpda-5.5pre1) with ESMTP id o3GFVcI4081021 for ; Fri, 16 Apr 2010 17:31:38 +0200 (CEST) (envelope-from pierre.muller@ics-cnrs.unistra.fr) Received: from mailserver.u-strasbg.fr (ms3.u-strasbg.fr [IPv6:2001:660:2402:d::12]) by baal.u-strasbg.fr (8.14.0/jtpda-5.5pre1) with ESMTP id o3GFVcQG064743 for ; Fri, 16 Apr 2010 17:31:38 +0200 (CEST) (envelope-from pierre.muller@ics-cnrs.unistra.fr) Received: from d620muller (gw-ics.u-strasbg.fr [130.79.210.225]) (user=mullerp mech=LOGIN) by mailserver.u-strasbg.fr (8.14.3/jtpda-5.5pre1) with ESMTP id o3GFVbqR091181 (version=TLSv1/SSLv3 cipher=RC4-MD5 bits=128 verify=NO) for ; Fri, 16 Apr 2010 17:31:37 +0200 (CEST) (envelope-from pierre.muller@ics-cnrs.unistra.fr) From: "Pierre Muller" To: Subject: [RFC] Mingw Windows 64-bit gdbserver Date: Fri, 16 Apr 2010 15:32:00 -0000 Message-ID: <000d01cadd79$efa9e2b0$cefda810$@muller@ics-cnrs.unistra.fr> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-04/txt/msg00507.txt.bz2 This patch tries to implement support for gdbserver on Windows 64-bit, using the mingw32 cross compiler to windows-64bit. I am unsure if anyone else already tried this, but searching in gdb-patches I didn't find anything... Don't hesitate to tell me otherwise... The resulting gdbserver seem usable to me, I do have a few questions: - About the new file, win64-amd64-low.c should I remove the copyright years and only leave 2010? should I state that it is adapted from win32-i386-low.c? - About gdbserver/configure regeneration: this added several lines: +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 I did use autoconf version 2.64 as required... Is this normal? - About the used communication library: -lwsock32 was not found by the mingw, but main gdb doesn't seem to use it, should we move to ws2_32 for both win32 and win64? I still do have a problem when I connect to win64 gdbserver from a multi target win32 gdb executable, somehow, the library list does not seem to correctly read in the library addresses... Still investigating this. It seems related to the fact that I do not have local copies of my remote DLLs. Final question: Does that patch deserve a documentation or NEWS entry? Pierre Muller Pascal language support maintainer for GDB 2010-04-16 Pierre Muller * configure.tgt (x86_64-*-mingw*): Set BUILD_GDBSERVER to yes. gdbserver ChangeLog entry: 2010-04-16 Pierre Muller * configure.srv (srv_amd64_regobj): Replace "x86_64-avx.o" by "amd64-avx.o". (x86_64-*-mingw*): New configuration for Windows 64bit OS. Set srv_mingw64 variable to `yes'. * configure.ac: Use `ws2_32' library for mingw64 instead of `wsock32'. * configure: Regenerated. * win32-low.c: Use uintptr_t type to store addresses for both 32bit and 64bit binaries. (child_xfer_memory): Use uintptr_t type for local variable `addr'. (get_image_name): Use uintptr_t for local variable `done'. (psapi_get_dll_name): Use uintptr_t type for parameter `BaseAddress'. (toolhelp_get_dll_name): Idem. (handle_load_dll): Use uintptr_t type for local variable `load_addr'. (handle_unload_dll): Use unitptr_t typecast to avoid warning. (handle_exception): Use phex_nz to avoid warning. (win32_wait): Remove unused local variable `process'. * win64-amd64-low.c: New file adapted from win32-i386-low.c. Index: configure.tgt =================================================================== RCS file: /cvs/src/src/gdb/configure.tgt,v retrieving revision 1.230 diff -u -p -r1.230 configure.tgt --- configure.tgt 25 Feb 2010 20:30:58 -0000 1.230 +++ configure.tgt 16 Apr 2010 14:32:54 -0000 @@ -590,6 +590,7 @@ x86_64-*-mingw*) gdb_target_obs="amd64-tdep.o amd64-windows-tdep.o \ i386-tdep.o i386-cygwin-tdep.o i387-tdep.o \ solib-target.o windows-tdep.o" + build_gdbserver=yes ;; x86_64-*-netbsd* | x86_64-*-knetbsd*-gnu) # Target: NetBSD/amd64 Index: gdbserver/configure =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/configure,v retrieving revision 1.46 diff -u -p -r1.46 configure --- gdbserver/configure 23 Feb 2010 19:16:16 -0000 1.46 +++ gdbserver/configure 16 Apr 2010 14:32:55 -0000 @@ -4055,6 +4055,8 @@ esac if test "${srv_mingwce}" = "yes"; then LIBS="$LIBS -lws2" +elif test "${srv_mingw64}" = "yes"; then + LIBS="$LIBS -lws2_32" elif test "${srv_mingw}" = "yes"; then LIBS="$LIBS -lwsock32" elif test "${srv_qnx}" = "yes"; then @@ -4153,6 +4155,8 @@ else /* end confdefs.h. */ #define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 #include int main () @@ -4188,6 +4192,8 @@ else /* end confdefs.h. */ #define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 #include int main () @@ -4223,6 +4229,8 @@ else /* end confdefs.h. */ #define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 #include int main () @@ -4258,6 +4266,8 @@ else /* end confdefs.h. */ #define _SYSCALL32 +/* Needed for new procfs interface on sparc-solaris. */ +#define _STRUCTURED_PROC 1 #include int main () Index: gdbserver/configure.ac =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/configure.ac,v retrieving revision 1.33 diff -u -p -r1.33 configure.ac --- gdbserver/configure.ac 23 Feb 2010 19:16:16 -0000 1.33 +++ gdbserver/configure.ac 16 Apr 2010 14:32:55 -0000 @@ -117,6 +117,8 @@ esac if test "${srv_mingwce}" = "yes"; then LIBS="$LIBS -lws2" +elif test "${srv_mingw64}" = "yes"; then + LIBS="$LIBS -lws2_32" elif test "${srv_mingw}" = "yes"; then LIBS="$LIBS -lwsock32" elif test "${srv_qnx}" = "yes"; then Index: gdbserver/configure.srv =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/configure.srv,v retrieving revision 1.53 diff -u -p -r1.53 configure.srv --- gdbserver/configure.srv 8 Apr 2010 22:32:38 -0000 1.53 +++ gdbserver/configure.srv 16 Apr 2010 14:32:55 -0000 @@ -24,7 +24,7 @@ srv_hostio_err_objs="hostio-errno.o" srv_i386_regobj="i386.o i386-avx.o i386-mmx.o" srv_i386_linux_regobj="i386-linux.o i386-avx-linux.o i386-mmx-linux.o" -srv_amd64_regobj="amd64.o x86-64-avx.o" +srv_amd64_regobj="amd64.o amd64-avx.o" srv_amd64_linux_regobj="amd64-linux.o amd64-avx-linux.o" srv_i386_32bit_xmlfiles="i386/32bit-core.xml i386/32bit-sse.xml i386/32bit-avx.xml" @@ -231,6 +231,13 @@ case "${target}" in srv_linux_regsets=yes srv_linux_thread_db=yes ;; + x86_64-w64-mingw*) srv_regobj="$srv_amd64_regobj" + srv_tgtobj="i386-low.o i387-fp.o win32-low.o win64-amd64-low.o" + srv_xmlfiles="$srv_i386_xmlfiles $srv_amd64_xmlfiles" + srv_mingw64=yes + srv_mingw=yes + ;; + xscale*-*-linux*) srv_regobj=reg-arm.o srv_tgtobj="linux-low.o linux-arm-low.o" srv_linux_usrregs=yes Index: gdbserver/win32-low.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v retrieving revision 1.46 diff -u -p -r1.46 win32-low.c --- gdbserver/win32-low.c 16 Apr 2010 07:49:37 -0000 1.46 +++ gdbserver/win32-low.c 16 Apr 2010 14:32:55 -0000 @@ -280,7 +280,7 @@ child_xfer_memory (CORE_ADDR memaddr, ch int write, struct target_ops *target) { SIZE_T done; - long addr = (long) memaddr; + uintptr_t addr = (uintptr_t) memaddr; if (write) { @@ -941,7 +941,7 @@ get_image_name (HANDLE h, void *address, char *address_ptr; int len = 0; char b[2]; - DWORD done; + uintptr_t done; /* Attempt to read the name of the dll that was detected. This is documented to work only when actively debugging @@ -1019,7 +1019,7 @@ load_psapi (void) } static int -psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret) +psapi_get_dll_name (uintptr_t BaseAddress, char *dll_name_ret) { DWORD len; MODULEINFO mi; @@ -1064,7 +1064,7 @@ psapi_get_dll_name (DWORD BaseAddress, c (int) err, strwinerror (err)); } - if ((DWORD) (mi.lpBaseOfDll) == BaseAddress) + if ((uintptr_t) (mi.lpBaseOfDll) == BaseAddress) { len = (*win32_GetModuleFileNameExA) (current_process_handle, DllHandle[i], @@ -1134,7 +1134,7 @@ load_toolhelp (void) } static int -toolhelp_get_dll_name (DWORD BaseAddress, char *dll_name_ret) +toolhelp_get_dll_name (uintptr_t BaseAddress, char *dll_name_ret) { HANDLE snapshot_module; MODULEENTRY32 modEntry = { sizeof (MODULEENTRY32) }; @@ -1151,7 +1151,7 @@ toolhelp_get_dll_name (DWORD BaseAddress /* Ignore the first module, which is the exe. */ if (win32_Module32First (snapshot_module, &modEntry)) while (win32_Module32Next (snapshot_module, &modEntry)) - if ((DWORD) modEntry.modBaseAddr == BaseAddress) + if ((uintptr_t) modEntry.modBaseAddr == BaseAddress) { #ifdef UNICODE wcstombs (dll_name_ret, modEntry.szExePath, MAX_PATH + 1); @@ -1176,21 +1176,21 @@ handle_load_dll (void) LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; char dll_buf[MAX_PATH + 1]; char *dll_name = NULL; - DWORD load_addr; + uintptr_t load_addr; dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0'; /* Windows does not report the image name of the dlls in the debug event on attaches. We resort to iterating over the list of loaded dlls looking for a match by image base. */ - if (!psapi_get_dll_name ((DWORD) event->lpBaseOfDll, dll_buf)) + if (!psapi_get_dll_name ((uintptr_t) event->lpBaseOfDll, dll_buf)) { if (!server_waiting) /* On some versions of Windows and Windows CE, we can't create toolhelp snapshots while the inferior is stopped in a LOAD_DLL_DEBUG_EVENT due to a dll load, but we can while Windows is reporting the already loaded dlls. */ - toolhelp_get_dll_name ((DWORD) event->lpBaseOfDll, dll_buf); + toolhelp_get_dll_name ((uintptr_t) event->lpBaseOfDll, dll_buf); } dll_name = dll_buf; @@ -1205,7 +1205,7 @@ handle_load_dll (void) the offset from 0 of the first byte in an image - because of the file header and the section alignment. */ - load_addr = (DWORD) event->lpBaseOfDll + 0x1000; + load_addr = (uintptr_t) event->lpBaseOfDll + 0x1000; win32_add_one_solib (dll_name, load_addr); } @@ -1213,7 +1213,7 @@ static void handle_unload_dll (void) { CORE_ADDR load_addr = - (CORE_ADDR) (DWORD) current_event.u.UnloadDll.lpBaseOfDll; + (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll; load_addr += 0x1000; unloaded_dll (NULL, load_addr); } @@ -1314,10 +1314,10 @@ handle_exception (struct target_waitstat ourstatus->kind = TARGET_WAITKIND_SPURIOUS; return; } - OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%08lx", + OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%s", current_event.u.Exception.ExceptionRecord.ExceptionCode, - (DWORD) current_event.u.Exception.ExceptionRecord. - ExceptionAddress)); + phex_nz ((uintptr_t) current_event.u.Exception.ExceptionRecord. + ExceptionAddress, sizeof(uintptr_t)))); ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; break; } @@ -1577,7 +1577,6 @@ get_child_debug_event (struct target_wai static ptid_t win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options) { - struct process_info *process; struct regcache *regcache; while (1) Index: gdbserver/win64-amd64-low.c =================================================================== RCS file: gdbserver/win64-amd64-low.c diff -N gdbserver/win64-amd64-low.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gdbserver/win64-amd64-low.c 16 Apr 2010 14:32:55 -0000 @@ -0,0 +1,343 @@ +/* Copyright (C) 2007, 2008, 2009, 2010 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 . */ + +#include "server.h" +#include "win32-low.h" +#include "i386-low.h" + +#define FCS_REGNUM 27 +#define FOP_REGNUM 31 + +#define FLAG_TRACE_BIT 0x100 + +#ifndef CONTEXT_EXTENDED_REGISTERS +#define CONTEXT_EXTENDED_REGISTERS 0 +#endif + +/* Defined in auto-generated file reg-amd64.c. */ +void init_registers_amd64 (void); + +static struct i386_debug_reg_state debug_reg_state; + +static int debug_registers_changed = 0; +static int debug_registers_used = 0; + +/* Update the inferior's debug register REGNUM from STATE. */ + +void +i386_dr_low_set_addr (const struct i386_debug_reg_state *state, int regnum) +{ + if (! (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR)) + fatal ("Invalid debug register %d", regnum); + + /* debug_reg_state.dr_mirror is already set. + Just notify i386_set_thread_context, i386_thread_added + that the registers need to be updated. */ + debug_registers_changed = 1; + debug_registers_used = 1; +} + +/* Update the inferior's DR7 debug control register from STATE. */ + +void +i386_dr_low_set_control (const struct i386_debug_reg_state *state) +{ + /* debug_reg_state.dr_control_mirror is already set. + Just notify i386_set_thread_context, i386_thread_added + that the registers need to be updated. */ + debug_registers_changed = 1; + debug_registers_used = 1; +} + +/* Get the value of the DR6 debug status register from the inferior + and record it in STATE. */ + +void +i386_dr_low_get_status (struct i386_debug_reg_state *state) +{ + /* We don't need to do anything here, the last call to thread_rec for + current_event.dwThreadId id has already set it. */ +} + +/* Watchpoint support. */ + +static int +amd64_insert_point (char type, CORE_ADDR addr, int len) +{ + switch (type) + { + case '2': + case '3': + case '4': + return i386_low_insert_watchpoint (&debug_reg_state, + type, addr, len); + default: + /* Unsupported. */ + return 1; + } +} + +static int +amd64_remove_point (char type, CORE_ADDR addr, int len) +{ + switch (type) + { + case '2': + case '3': + case '4': + return i386_low_remove_watchpoint (&debug_reg_state, + type, addr, len); + default: + /* Unsupported. */ + return 1; + } +} + +static int +amd64_stopped_by_watchpoint (void) +{ + return i386_low_stopped_by_watchpoint (&debug_reg_state); +} + +static CORE_ADDR +amd64_stopped_data_address (void) +{ + CORE_ADDR addr; + if (i386_low_stopped_data_address (&debug_reg_state, &addr)) + return addr; + return 0; +} + +static void +amd64_initial_stuff (void) +{ + i386_low_init_dregs (&debug_reg_state); + debug_registers_changed = 0; + debug_registers_used = 0; +} + +static void +amd64_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event) +{ + /* Requesting the CONTEXT_EXTENDED_REGISTERS register set fails if + the system doesn't support extended registers. */ + static DWORD extended_registers = CONTEXT_EXTENDED_REGISTERS; + + again: + th->context.ContextFlags = (CONTEXT_FULL + | CONTEXT_FLOATING_POINT + | CONTEXT_DEBUG_REGISTERS + | extended_registers); + + if (!GetThreadContext (th->h, &th->context)) + { + DWORD e = GetLastError (); + + if (extended_registers && e == ERROR_INVALID_PARAMETER) + { + extended_registers = 0; + goto again; + } + + error ("GetThreadContext failure %ld\n", (long) e); + } + + debug_registers_changed = 0; + + if (th->tid == current_event->dwThreadId) + { + /* Copy dr values from the current thread. */ + struct i386_debug_reg_state *dr = &debug_reg_state; + dr->dr_mirror[0] = th->context.Dr0; + dr->dr_mirror[1] = th->context.Dr1; + dr->dr_mirror[2] = th->context.Dr2; + dr->dr_mirror[3] = th->context.Dr3; + dr->dr_status_mirror = th->context.Dr6; + dr->dr_control_mirror = th->context.Dr7; + } +} + +static void +amd64_set_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event) +{ + if (debug_registers_changed) + { + struct i386_debug_reg_state *dr = &debug_reg_state; + th->context.Dr0 = dr->dr_mirror[0]; + th->context.Dr1 = dr->dr_mirror[1]; + th->context.Dr2 = dr->dr_mirror[2]; + th->context.Dr3 = dr->dr_mirror[3]; + /* th->context.Dr6 = dr->dr_status_mirror; + FIXME: should we set dr6 also ?? */ + th->context.Dr7 = dr->dr_control_mirror; + } + + SetThreadContext (th->h, &th->context); +} + +static void +amd64_thread_added (win32_thread_info *th) +{ + /* Set the debug registers for the new thread if they are used. */ + if (debug_registers_used) + { + struct i386_debug_reg_state *dr = &debug_reg_state; + th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS; + GetThreadContext (th->h, &th->context); + + th->context.Dr0 = dr->dr_mirror[0]; + th->context.Dr1 = dr->dr_mirror[1]; + th->context.Dr2 = dr->dr_mirror[2]; + th->context.Dr3 = dr->dr_mirror[3]; + /* th->context.Dr6 = dr->dr_status_mirror; + FIXME: should we set dr6 also ?? */ + th->context.Dr7 = dr->dr_control_mirror; + + SetThreadContext (th->h, &th->context); + th->context.ContextFlags = 0; + } +} + +static void +amd64_single_step (win32_thread_info *th) +{ + th->context.EFlags |= FLAG_TRACE_BIT; +} + +/* An array of offset mappings into a Win64 Context structure. + This is a one-to-one mapping which is indexed by gdb's register + numbers. It retrieves an offset into the context structure where + the register is located. + An offset value of -1 indicates that Win64 does not provide this + register in it's CONTEXT structure. In this case regptr will return + a pointer into a dummy register. */ +#define context_offset(x) (offsetof (CONTEXT, x)) +static const int mappings[] = +{ + context_offset (Rax), + context_offset (Rbx), + context_offset (Rcx), + context_offset (Rdx), + context_offset (Rsi), + context_offset (Rdi), + context_offset (Rbp), + context_offset (Rsp), + context_offset (R8), + context_offset (R9), + context_offset (R10), + context_offset (R11), + context_offset (R12), + context_offset (R13), + context_offset (R14), + context_offset (R15), + context_offset (Rip), + context_offset (EFlags), + context_offset (SegCs), + context_offset (SegSs), + context_offset (SegDs), + context_offset (SegEs), + context_offset (SegFs), + context_offset (SegGs), + context_offset (FloatSave.FloatRegisters[0]), + context_offset (FloatSave.FloatRegisters[1]), + context_offset (FloatSave.FloatRegisters[2]), + context_offset (FloatSave.FloatRegisters[3]), + context_offset (FloatSave.FloatRegisters[4]), + context_offset (FloatSave.FloatRegisters[5]), + context_offset (FloatSave.FloatRegisters[6]), + context_offset (FloatSave.FloatRegisters[7]), + context_offset (FloatSave.ControlWord), + context_offset (FloatSave.StatusWord), + context_offset (FloatSave.TagWord), + context_offset (FloatSave.ErrorSelector), + context_offset (FloatSave.ErrorOffset), + context_offset (FloatSave.DataSelector), + context_offset (FloatSave.DataOffset), + context_offset (FloatSave.ErrorSelector) + /* XMM0-7 */ , + context_offset (Xmm0), + context_offset (Xmm1), + context_offset (Xmm2), + context_offset (Xmm3), + context_offset (Xmm4), + context_offset (Xmm5), + context_offset (Xmm6), + context_offset (Xmm7), + context_offset (Xmm8), + context_offset (Xmm9), + context_offset (Xmm10), + context_offset (Xmm11), + context_offset (Xmm12), + context_offset (Xmm13), + context_offset (Xmm14), + context_offset (Xmm15), + /* MXCSR */ + context_offset (FloatSave.MxCsr) +}; +#undef context_offset + +/* Fetch register from gdbserver regcache data. */ +static void +amd64_fetch_inferior_register (struct regcache *regcache, + win32_thread_info *th, int r) +{ + char *context_offset = (char *) &th->context + mappings[r]; + + long l; + if (r == FCS_REGNUM) + { + l = *((long *) context_offset) & 0xffff; + supply_register (regcache, r, (char *) &l); + } + else if (r == FOP_REGNUM) + { + l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1); + supply_register (regcache, r, (char *) &l); + } + else + supply_register (regcache, r, context_offset); +} + +/* Store a new register value into the thread context of TH. */ +static void +amd64_store_inferior_register (struct regcache *regcache, + win32_thread_info *th, int r) +{ + char *context_offset = (char *) &th->context + mappings[r]; + collect_register (regcache, r, context_offset); +} + +static const unsigned char amd64_win64_breakpoint = 0xcc; +#define amd64_win64_breakpoint_len 1 + +struct win32_target_ops the_low_target = { + init_registers_amd64, + sizeof (mappings) / sizeof (mappings[0]), + amd64_initial_stuff, + amd64_get_thread_context, + amd64_set_thread_context, + amd64_thread_added, + amd64_fetch_inferior_register, + amd64_store_inferior_register, + amd64_single_step, + &amd64_win64_breakpoint, + amd64_win64_breakpoint_len, + amd64_insert_point, + amd64_remove_point, + amd64_stopped_by_watchpoint, + amd64_stopped_data_address +};