| Index: gdb/gdbserver/linux-x86-low.c
|
| diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c
|
| index 4ea284eebafd16fea56c1ea5165dbe203ece2e30..e8505bf0e83b65aad4f4fab7e6ae6d46646a5477 100644
|
| --- a/gdb/gdbserver/linux-x86-low.c
|
| +++ b/gdb/gdbserver/linux-x86-low.c
|
| @@ -1,6 +1,6 @@
|
| /* GNU/Linux/x86-64 specific low level interface, for the remote server
|
| for GDB.
|
| - Copyright (C) 2002, 2004-2012 Free Software Foundation, Inc.
|
| + Copyright (C) 2002-2013 Free Software Foundation, Inc.
|
|
|
| This file is part of GDB.
|
|
|
| @@ -30,21 +30,54 @@
|
|
|
| #include "gdb_proc_service.h"
|
| #include "agent.h"
|
| +#include "tdesc.h"
|
| +#include "tracepoint.h"
|
| +#include "ax.h"
|
|
|
| -/* Defined in auto-generated file i386-linux.c. */
|
| -void init_registers_i386_linux (void);
|
| +#ifdef __x86_64__
|
| /* Defined in auto-generated file amd64-linux.c. */
|
| void init_registers_amd64_linux (void);
|
| -/* Defined in auto-generated file i386-avx-linux.c. */
|
| -void init_registers_i386_avx_linux (void);
|
| +extern const struct target_desc *tdesc_amd64_linux;
|
| +
|
| /* Defined in auto-generated file amd64-avx-linux.c. */
|
| void init_registers_amd64_avx_linux (void);
|
| -/* Defined in auto-generated file i386-mmx-linux.c. */
|
| -void init_registers_i386_mmx_linux (void);
|
| +extern const struct target_desc *tdesc_amd64_avx_linux;
|
| +
|
| +/* Defined in auto-generated file amd64-mpx-linux.c. */
|
| +void init_registers_amd64_mpx_linux (void);
|
| +extern const struct target_desc *tdesc_amd64_mpx_linux;
|
| +
|
| /* Defined in auto-generated file x32-linux.c. */
|
| void init_registers_x32_linux (void);
|
| +extern const struct target_desc *tdesc_x32_linux;
|
| +
|
| /* Defined in auto-generated file x32-avx-linux.c. */
|
| void init_registers_x32_avx_linux (void);
|
| +extern const struct target_desc *tdesc_x32_avx_linux;
|
| +
|
| +#endif
|
| +
|
| +/* Defined in auto-generated file i386-linux.c. */
|
| +void init_registers_i386_linux (void);
|
| +extern const struct target_desc *tdesc_i386_linux;
|
| +
|
| +/* Defined in auto-generated file i386-mmx-linux.c. */
|
| +void init_registers_i386_mmx_linux (void);
|
| +extern const struct target_desc *tdesc_i386_mmx_linux;
|
| +
|
| +/* Defined in auto-generated file i386-avx-linux.c. */
|
| +void init_registers_i386_avx_linux (void);
|
| +extern const struct target_desc *tdesc_i386_avx_linux;
|
| +
|
| +/* Defined in auto-generated file i386-mpx-linux.c. */
|
| +void init_registers_i386_mpx_linux (void);
|
| +extern const struct target_desc *tdesc_i386_mpx_linux;
|
| +
|
| +#ifdef __x86_64__
|
| +static struct target_desc *tdesc_amd64_linux_no_xml;
|
| +#endif
|
| +static struct target_desc *tdesc_i386_linux_no_xml;
|
| +
|
|
|
| static unsigned char jump_insn[] = { 0xe9, 0, 0, 0, 0 };
|
| static unsigned char small_jump_insn[] = { 0x66, 0xe9, 0, 0 };
|
| @@ -139,8 +172,11 @@ static const int x86_64_regmap[] =
|
| -1, -1, -1, -1, -1, -1, -1, -1,
|
| -1, -1, -1, -1, -1, -1, -1, -1,
|
| -1, -1, -1, -1, -1, -1, -1, -1,
|
| - -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
| - ORIG_RAX * 8
|
| + -1,
|
| + -1, -1, -1, -1, -1, -1, -1, -1,
|
| + ORIG_RAX * 8,
|
| + -1, -1, -1, -1, /* MPX registers BND0 ... BND3. */
|
| + -1, -1 /* MPX registers BNDCFGU, BNDSTATUS. */
|
| };
|
|
|
| #define X86_64_NUM_REGS (sizeof (x86_64_regmap) / sizeof (x86_64_regmap[0]))
|
| @@ -160,6 +196,22 @@ static /*const*/ int i386_regmap[] =
|
| #define I386_NUM_REGS (sizeof (i386_regmap) / sizeof (i386_regmap[0]))
|
|
|
| #endif
|
| +
|
| +#ifdef __x86_64__
|
| +
|
| +/* Returns true if the current inferior belongs to a x86-64 process,
|
| + per the tdesc. */
|
| +
|
| +static int
|
| +is_64bit_tdesc (void)
|
| +{
|
| + struct regcache *regcache = get_thread_regcache (current_inferior, 0);
|
| +
|
| + return register_size (regcache->tdesc, 0) == 8;
|
| +}
|
| +
|
| +#endif
|
| +
|
|
|
| /* Called by libthread_db. */
|
|
|
| @@ -168,7 +220,7 @@ ps_get_thread_area (const struct ps_prochandle *ph,
|
| lwpid_t lwpid, int idx, void **base)
|
| {
|
| #ifdef __x86_64__
|
| - int use_64bit = register_size (0) == 8;
|
| + int use_64bit = is_64bit_tdesc ();
|
|
|
| if (use_64bit)
|
| {
|
| @@ -196,7 +248,8 @@ ps_get_thread_area (const struct ps_prochandle *ph,
|
| (void *) (intptr_t) idx, (unsigned long) &desc) < 0)
|
| return PS_ERR;
|
|
|
| - *(int *)base = desc[1];
|
| + /* Ensure we properly extend the value to 64-bits for x86_64. */
|
| + *base = (void *) (uintptr_t) desc[1];
|
| return PS_OK;
|
| }
|
| }
|
| @@ -210,7 +263,7 @@ static int
|
| x86_get_thread_area (int lwpid, CORE_ADDR *addr)
|
| {
|
| #ifdef __x86_64__
|
| - int use_64bit = register_size (0) == 8;
|
| + int use_64bit = is_64bit_tdesc ();
|
|
|
| if (use_64bit)
|
| {
|
| @@ -250,14 +303,24 @@ x86_get_thread_area (int lwpid, CORE_ADDR *addr)
|
|
|
|
|
| static int
|
| -i386_cannot_store_register (int regno)
|
| +x86_cannot_store_register (int regno)
|
| {
|
| +#ifdef __x86_64__
|
| + if (is_64bit_tdesc ())
|
| + return 0;
|
| +#endif
|
| +
|
| return regno >= I386_NUM_REGS;
|
| }
|
|
|
| static int
|
| -i386_cannot_fetch_register (int regno)
|
| +x86_cannot_fetch_register (int regno)
|
| {
|
| +#ifdef __x86_64__
|
| + if (is_64bit_tdesc ())
|
| + return 0;
|
| +#endif
|
| +
|
| return regno >= I386_NUM_REGS;
|
| }
|
|
|
| @@ -267,7 +330,7 @@ x86_fill_gregset (struct regcache *regcache, void *buf)
|
| int i;
|
|
|
| #ifdef __x86_64__
|
| - if (register_size (0) == 8)
|
| + if (register_size (regcache->tdesc, 0) == 8)
|
| {
|
| for (i = 0; i < X86_64_NUM_REGS; i++)
|
| if (x86_64_regmap[i] != -1)
|
| @@ -289,7 +352,7 @@ x86_store_gregset (struct regcache *regcache, const void *buf)
|
| int i;
|
|
|
| #ifdef __x86_64__
|
| - if (register_size (0) == 8)
|
| + if (register_size (regcache->tdesc, 0) == 8)
|
| {
|
| for (i = 0; i < X86_64_NUM_REGS; i++)
|
| if (x86_64_regmap[i] != -1)
|
| @@ -358,11 +421,9 @@ x86_store_xstateregset (struct regcache *regcache, const void *buf)
|
| This is, presumably, to handle the case where PTRACE_[GS]ETFPXREGS
|
| doesn't work. IWBN to avoid the duplication in the case where it
|
| does work. Maybe the arch_setup routine could check whether it works
|
| - and update target_regsets accordingly, maybe by moving target_regsets
|
| - to linux_target_ops and set the right one there, rather than having to
|
| - modify the target_regsets global. */
|
| + and update the supported regsets accordingly. */
|
|
|
| -struct regset_info target_regsets[] =
|
| +static struct regset_info x86_regsets[] =
|
| {
|
| #ifdef HAVE_PTRACE_GETREGS
|
| { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
|
| @@ -387,7 +448,7 @@ struct regset_info target_regsets[] =
|
| static CORE_ADDR
|
| x86_get_pc (struct regcache *regcache)
|
| {
|
| - int use_64bit = register_size (0) == 8;
|
| + int use_64bit = register_size (regcache->tdesc, 0) == 8;
|
|
|
| if (use_64bit)
|
| {
|
| @@ -406,7 +467,7 @@ x86_get_pc (struct regcache *regcache)
|
| static void
|
| x86_set_pc (struct regcache *regcache, CORE_ADDR pc)
|
| {
|
| - int use_64bit = register_size (0) == 8;
|
| + int use_64bit = register_size (regcache->tdesc, 0) == 8;
|
|
|
| if (use_64bit)
|
| {
|
| @@ -561,7 +622,7 @@ x86_insert_point (char type, CORE_ADDR addr, int len)
|
| struct process_info *proc = current_process ();
|
| switch (type)
|
| {
|
| - case '0':
|
| + case '0': /* software-breakpoint */
|
| {
|
| int ret;
|
|
|
| @@ -572,11 +633,13 @@ x86_insert_point (char type, CORE_ADDR addr, int len)
|
| done_accessing_memory ();
|
| return ret;
|
| }
|
| - case '2':
|
| - case '3':
|
| - case '4':
|
| + case '1': /* hardware-breakpoint */
|
| + case '2': /* write watchpoint */
|
| + case '3': /* read watchpoint */
|
| + case '4': /* access watchpoint */
|
| return i386_low_insert_watchpoint (&proc->private->arch_private->debug_reg_state,
|
| type, addr, len);
|
| +
|
| default:
|
| /* Unsupported. */
|
| return 1;
|
| @@ -589,7 +652,7 @@ x86_remove_point (char type, CORE_ADDR addr, int len)
|
| struct process_info *proc = current_process ();
|
| switch (type)
|
| {
|
| - case '0':
|
| + case '0': /* software-breakpoint */
|
| {
|
| int ret;
|
|
|
| @@ -600,9 +663,10 @@ x86_remove_point (char type, CORE_ADDR addr, int len)
|
| done_accessing_memory ();
|
| return ret;
|
| }
|
| - case '2':
|
| - case '3':
|
| - case '4':
|
| + case '1': /* hardware-breakpoint */
|
| + case '2': /* write watchpoint */
|
| + case '3': /* read watchpoint */
|
| + case '4': /* access watchpoint */
|
| return i386_low_remove_watchpoint (&proc->private->arch_private->debug_reg_state,
|
| type, addr, len);
|
| default:
|
| @@ -1088,8 +1152,6 @@ siginfo_from_compat_x32_siginfo (siginfo_t *to,
|
| }
|
| }
|
|
|
| -/* Is this process 64-bit? */
|
| -static int linux_is_elf64;
|
| #endif /* __x86_64__ */
|
|
|
| /* Convert a native/host siginfo object, into/from the siginfo in the
|
| @@ -1102,8 +1164,12 @@ static int
|
| x86_siginfo_fixup (siginfo_t *native, void *inf, int direction)
|
| {
|
| #ifdef __x86_64__
|
| + unsigned int machine;
|
| + int tid = lwpid_of (get_thread_lwp (current_inferior));
|
| + int is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine);
|
| +
|
| /* Is the inferior 32-bit? If so, then fixup the siginfo object. */
|
| - if (register_size (0) == 4)
|
| + if (!is_64bit_tdesc ())
|
| {
|
| if (sizeof (siginfo_t) != sizeof (compat_siginfo_t))
|
| fatal ("unexpected difference in siginfo");
|
| @@ -1116,7 +1182,7 @@ x86_siginfo_fixup (siginfo_t *native, void *inf, int direction)
|
| return 1;
|
| }
|
| /* No fixup for native x32 GDB. */
|
| - else if (!linux_is_elf64 && sizeof (void *) == 8)
|
| + else if (!is_elf64 && sizeof (void *) == 8)
|
| {
|
| if (sizeof (siginfo_t) != sizeof (compat_x32_siginfo_t))
|
| fatal ("unexpected difference in siginfo");
|
| @@ -1137,138 +1203,240 @@ x86_siginfo_fixup (siginfo_t *native, void *inf, int direction)
|
|
|
| static int use_xml;
|
|
|
| -/* Update gdbserver_xmltarget. */
|
| +/* Format of XSAVE extended state is:
|
| + struct
|
| + {
|
| + fxsave_bytes[0..463]
|
| + sw_usable_bytes[464..511]
|
| + xstate_hdr_bytes[512..575]
|
| + avx_bytes[576..831]
|
| + future_state etc
|
| + };
|
| +
|
| + Same memory layout will be used for the coredump NT_X86_XSTATE
|
| + representing the XSAVE extended state registers.
|
| +
|
| + The first 8 bytes of the sw_usable_bytes[464..467] is the OS enabled
|
| + extended state mask, which is the same as the extended control register
|
| + 0 (the XFEATURE_ENABLED_MASK register), XCR0. We can use this mask
|
| + together with the mask saved in the xstate_hdr_bytes to determine what
|
| + states the processor/OS supports and what state, used or initialized,
|
| + the process/thread is in. */
|
| +#define I386_LINUX_XSAVE_XCR0_OFFSET 464
|
| +
|
| +/* Does the current host support the GETFPXREGS request? The header
|
| + file may or may not define it, and even if it is defined, the
|
| + kernel will return EIO if it's running on a pre-SSE processor. */
|
| +int have_ptrace_getfpxregs =
|
| +#ifdef HAVE_PTRACE_GETFPXREGS
|
| + -1
|
| +#else
|
| + 0
|
| +#endif
|
| +;
|
|
|
| -static void
|
| -x86_linux_update_xmltarget (void)
|
| +/* Does the current host support PTRACE_GETREGSET? */
|
| +static int have_ptrace_getregset = -1;
|
| +
|
| +/* Get Linux/x86 target description from running target. */
|
| +
|
| +static const struct target_desc *
|
| +x86_linux_read_description (void)
|
| {
|
| - int pid;
|
| + unsigned int machine;
|
| + int is_elf64;
|
| + int xcr0_features;
|
| + int tid;
|
| + static uint64_t xcr0;
|
| struct regset_info *regset;
|
| - static unsigned long long xcr0;
|
| - static int have_ptrace_getregset = -1;
|
| -#if !defined(__x86_64__) && defined(HAVE_PTRACE_GETFPXREGS)
|
| - static int have_ptrace_getfpxregs = -1;
|
| -#endif
|
|
|
| - if (!current_inferior)
|
| - return;
|
| + tid = lwpid_of (get_thread_lwp (current_inferior));
|
|
|
| - /* Before changing the register cache internal layout or the target
|
| - regsets, flush the contents of the current valid caches back to
|
| - the threads. */
|
| - regcache_invalidate ();
|
| + is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine);
|
|
|
| - pid = pid_of (get_thread_lwp (current_inferior));
|
| -#ifdef __x86_64__
|
| - if (num_xmm_registers == 8)
|
| - init_registers_i386_linux ();
|
| - else if (linux_is_elf64)
|
| - init_registers_amd64_linux ();
|
| - else
|
| - init_registers_x32_linux ();
|
| -#else
|
| + if (sizeof (void *) == 4)
|
| {
|
| -# ifdef HAVE_PTRACE_GETFPXREGS
|
| - if (have_ptrace_getfpxregs == -1)
|
| - {
|
| - elf_fpxregset_t fpxregs;
|
| + if (is_elf64 > 0)
|
| + error (_("Can't debug 64-bit process with 32-bit GDBserver"));
|
| +#ifndef __x86_64__
|
| + else if (machine == EM_X86_64)
|
| + error (_("Can't debug x86-64 process with 32-bit GDBserver"));
|
| +#endif
|
| + }
|
|
|
| - if (ptrace (PTRACE_GETFPXREGS, pid, 0, (int) &fpxregs) < 0)
|
| - {
|
| - have_ptrace_getfpxregs = 0;
|
| - x86_xcr0 = I386_XSTATE_X87_MASK;
|
| -
|
| - /* Disable PTRACE_GETFPXREGS. */
|
| - for (regset = target_regsets;
|
| - regset->fill_function != NULL; regset++)
|
| - if (regset->get_request == PTRACE_GETFPXREGS)
|
| - {
|
| - regset->size = 0;
|
| - break;
|
| - }
|
| - }
|
| - else
|
| - have_ptrace_getfpxregs = 1;
|
| - }
|
| +#if !defined __x86_64__ && defined HAVE_PTRACE_GETFPXREGS
|
| + if (machine == EM_386 && have_ptrace_getfpxregs == -1)
|
| + {
|
| + elf_fpxregset_t fpxregs;
|
|
|
| - if (!have_ptrace_getfpxregs)
|
| + if (ptrace (PTRACE_GETFPXREGS, tid, 0, (long) &fpxregs) < 0)
|
| {
|
| - init_registers_i386_mmx_linux ();
|
| - return;
|
| + have_ptrace_getfpxregs = 0;
|
| + have_ptrace_getregset = 0;
|
| + return tdesc_i386_mmx_linux;
|
| }
|
| -# endif
|
| - init_registers_i386_linux ();
|
| + else
|
| + have_ptrace_getfpxregs = 1;
|
| }
|
| #endif
|
|
|
| if (!use_xml)
|
| {
|
| + x86_xcr0 = I386_XSTATE_SSE_MASK;
|
| +
|
| /* Don't use XML. */
|
| #ifdef __x86_64__
|
| - if (num_xmm_registers == 8)
|
| - gdbserver_xmltarget = xmltarget_i386_linux_no_xml;
|
| + if (machine == EM_X86_64)
|
| + return tdesc_amd64_linux_no_xml;
|
| else
|
| - gdbserver_xmltarget = xmltarget_amd64_linux_no_xml;
|
| -#else
|
| - gdbserver_xmltarget = xmltarget_i386_linux_no_xml;
|
| #endif
|
| -
|
| - x86_xcr0 = I386_XSTATE_SSE_MASK;
|
| -
|
| - return;
|
| + return tdesc_i386_linux_no_xml;
|
| }
|
|
|
| - /* Check if XSAVE extended state is supported. */
|
| if (have_ptrace_getregset == -1)
|
| {
|
| - unsigned long long xstateregs[I386_XSTATE_SSE_SIZE / sizeof (long long)];
|
| + uint64_t xstateregs[(I386_XSTATE_SSE_SIZE / sizeof (uint64_t))];
|
| struct iovec iov;
|
|
|
| iov.iov_base = xstateregs;
|
| iov.iov_len = sizeof (xstateregs);
|
|
|
| /* Check if PTRACE_GETREGSET works. */
|
| - if (ptrace (PTRACE_GETREGSET, pid, (unsigned int) NT_X86_XSTATE,
|
| - &iov) < 0)
|
| + if (ptrace (PTRACE_GETREGSET, tid,
|
| + (unsigned int) NT_X86_XSTATE, (long) &iov) < 0)
|
| + have_ptrace_getregset = 0;
|
| + else
|
| {
|
| - have_ptrace_getregset = 0;
|
| - return;
|
| + have_ptrace_getregset = 1;
|
| +
|
| + /* Get XCR0 from XSAVE extended state. */
|
| + xcr0 = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET
|
| + / sizeof (uint64_t))];
|
| +
|
| + /* Use PTRACE_GETREGSET if it is available. */
|
| + for (regset = x86_regsets;
|
| + regset->fill_function != NULL; regset++)
|
| + if (regset->get_request == PTRACE_GETREGSET)
|
| + regset->size = I386_XSTATE_SIZE (xcr0);
|
| + else if (regset->type != GENERAL_REGS)
|
| + regset->size = 0;
|
| }
|
| - else
|
| - have_ptrace_getregset = 1;
|
| -
|
| - /* Get XCR0 from XSAVE extended state at byte 464. */
|
| - xcr0 = xstateregs[464 / sizeof (long long)];
|
| -
|
| - /* Use PTRACE_GETREGSET if it is available. */
|
| - for (regset = target_regsets;
|
| - regset->fill_function != NULL; regset++)
|
| - if (regset->get_request == PTRACE_GETREGSET)
|
| - regset->size = I386_XSTATE_SIZE (xcr0);
|
| - else if (regset->type != GENERAL_REGS)
|
| - regset->size = 0;
|
| }
|
|
|
| - if (have_ptrace_getregset)
|
| + /* Check the native XCR0 only if PTRACE_GETREGSET is available. */
|
| + xcr0_features = (have_ptrace_getregset
|
| + && (xcr0 & I386_XSTATE_ALL_MASK));
|
| +
|
| + if (xcr0_features)
|
| + x86_xcr0 = xcr0;
|
| +
|
| + if (machine == EM_X86_64)
|
| {
|
| - /* AVX is the highest feature we support. */
|
| - if ((xcr0 & I386_XSTATE_AVX_MASK) == I386_XSTATE_AVX_MASK)
|
| +#ifdef __x86_64__
|
| + if (is_elf64)
|
| {
|
| - x86_xcr0 = xcr0;
|
| + if (xcr0_features)
|
| + {
|
| + switch (xcr0 & I386_XSTATE_ALL_MASK)
|
| + {
|
| + case I386_XSTATE_MPX_MASK:
|
| + return tdesc_amd64_mpx_linux;
|
|
|
| -#ifdef __x86_64__
|
| - /* I386 has 8 xmm regs. */
|
| - if (num_xmm_registers == 8)
|
| - init_registers_i386_avx_linux ();
|
| - else if (linux_is_elf64)
|
| - init_registers_amd64_avx_linux ();
|
| + case I386_XSTATE_AVX_MASK:
|
| + return tdesc_amd64_avx_linux;
|
| +
|
| + default:
|
| + return tdesc_amd64_linux;
|
| + }
|
| + }
|
| else
|
| - init_registers_x32_avx_linux ();
|
| -#else
|
| - init_registers_i386_avx_linux ();
|
| + return tdesc_amd64_linux;
|
| + }
|
| + else
|
| + {
|
| + if (xcr0_features)
|
| + {
|
| + switch (xcr0 & I386_XSTATE_ALL_MASK)
|
| + {
|
| + case I386_XSTATE_MPX_MASK: /* No MPX on x32. */
|
| + case I386_XSTATE_AVX_MASK:
|
| + return tdesc_x32_avx_linux;
|
| +
|
| + default:
|
| + return tdesc_x32_linux;
|
| + }
|
| + }
|
| + else
|
| + return tdesc_x32_linux;
|
| + }
|
| #endif
|
| + }
|
| + else
|
| + {
|
| + if (xcr0_features)
|
| + {
|
| + switch (xcr0 & I386_XSTATE_ALL_MASK)
|
| + {
|
| + case (I386_XSTATE_MPX_MASK):
|
| + return tdesc_i386_mpx_linux;
|
| +
|
| + case (I386_XSTATE_AVX_MASK):
|
| + return tdesc_i386_avx_linux;
|
| +
|
| + default:
|
| + return tdesc_i386_linux;
|
| + }
|
| }
|
| + else
|
| + return tdesc_i386_linux;
|
| }
|
| +
|
| + gdb_assert_not_reached ("failed to return tdesc");
|
| +}
|
| +
|
| +/* Callback for find_inferior. Stops iteration when a thread with a
|
| + given PID is found. */
|
| +
|
| +static int
|
| +same_process_callback (struct inferior_list_entry *entry, void *data)
|
| +{
|
| + int pid = *(int *) data;
|
| +
|
| + return (ptid_get_pid (entry->id) == pid);
|
| +}
|
| +
|
| +/* Callback for for_each_inferior. Calls the arch_setup routine for
|
| + each process. */
|
| +
|
| +static void
|
| +x86_arch_setup_process_callback (struct inferior_list_entry *entry)
|
| +{
|
| + int pid = ptid_get_pid (entry->id);
|
| +
|
| + /* Look up any thread of this processes. */
|
| + current_inferior
|
| + = (struct thread_info *) find_inferior (&all_threads,
|
| + same_process_callback, &pid);
|
| +
|
| + the_low_target.arch_setup ();
|
| +}
|
| +
|
| +/* Update all the target description of all processes; a new GDB
|
| + connected, and it may or not support xml target descriptions. */
|
| +
|
| +static void
|
| +x86_linux_update_xmltarget (void)
|
| +{
|
| + struct thread_info *save_inferior = current_inferior;
|
| +
|
| + /* Before changing the register cache's internal layout, flush the
|
| + contents of the current valid caches back to the threads, and
|
| + release the current regcache objects. */
|
| + regcache_release ();
|
| +
|
| + for_each_inferior (&all_processes, x86_arch_setup_process_callback);
|
| +
|
| + current_inferior = save_inferior;
|
| }
|
|
|
| /* Process qSupported query, "xmlRegisters=". Update the buffer size for
|
| @@ -1301,62 +1469,54 @@ x86_linux_process_qsupported (const char *query)
|
| x86_linux_update_xmltarget ();
|
| }
|
|
|
| -/* Initialize gdbserver for the architecture of the inferior. */
|
| -
|
| -static void
|
| -x86_arch_setup (void)
|
| -{
|
| - int pid = pid_of (get_thread_lwp (current_inferior));
|
| - unsigned int machine;
|
| - int is_elf64 = linux_pid_exe_is_elf_64_file (pid, &machine);
|
| +/* Common for x86/x86-64. */
|
|
|
| - if (sizeof (void *) == 4)
|
| - {
|
| - if (is_elf64 > 0)
|
| - error (_("Can't debug 64-bit process with 32-bit GDBserver"));
|
| -#ifndef __x86_64__
|
| - else if (machine == EM_X86_64)
|
| - error (_("Can't debug x86-64 process with 32-bit GDBserver"));
|
| -#endif
|
| - }
|
| +static struct regsets_info x86_regsets_info =
|
| + {
|
| + x86_regsets, /* regsets */
|
| + 0, /* num_regsets */
|
| + NULL, /* disabled_regsets */
|
| + };
|
|
|
| #ifdef __x86_64__
|
| - if (is_elf64 < 0)
|
| - {
|
| - /* This can only happen if /proc/<pid>/exe is unreadable,
|
| - but "that can't happen" if we've gotten this far.
|
| - Fall through and assume this is a 32-bit program. */
|
| - }
|
| - else if (machine == EM_X86_64)
|
| - {
|
| - /* Amd64 doesn't have HAVE_LINUX_USRREGS. */
|
| - the_low_target.num_regs = -1;
|
| - the_low_target.regmap = NULL;
|
| - the_low_target.cannot_fetch_register = NULL;
|
| - the_low_target.cannot_store_register = NULL;
|
| -
|
| - /* Amd64 has 16 xmm regs. */
|
| - num_xmm_registers = 16;
|
| -
|
| - linux_is_elf64 = is_elf64;
|
| - x86_linux_update_xmltarget ();
|
| - return;
|
| - }
|
| -
|
| - linux_is_elf64 = 0;
|
| +static struct regs_info amd64_linux_regs_info =
|
| + {
|
| + NULL, /* regset_bitmap */
|
| + NULL, /* usrregs_info */
|
| + &x86_regsets_info
|
| + };
|
| #endif
|
| +static struct usrregs_info i386_linux_usrregs_info =
|
| + {
|
| + I386_NUM_REGS,
|
| + i386_regmap,
|
| + };
|
|
|
| - /* Ok we have a 32-bit inferior. */
|
| +static struct regs_info i386_linux_regs_info =
|
| + {
|
| + NULL, /* regset_bitmap */
|
| + &i386_linux_usrregs_info,
|
| + &x86_regsets_info
|
| + };
|
|
|
| - the_low_target.num_regs = I386_NUM_REGS;
|
| - the_low_target.regmap = i386_regmap;
|
| - the_low_target.cannot_fetch_register = i386_cannot_fetch_register;
|
| - the_low_target.cannot_store_register = i386_cannot_store_register;
|
| +const struct regs_info *
|
| +x86_linux_regs_info (void)
|
| +{
|
| +#ifdef __x86_64__
|
| + if (is_64bit_tdesc ())
|
| + return &amd64_linux_regs_info;
|
| + else
|
| +#endif
|
| + return &i386_linux_regs_info;
|
| +}
|
|
|
| - /* I386 has 8 xmm regs. */
|
| - num_xmm_registers = 8;
|
| +/* Initialize the target description for the architecture of the
|
| + inferior. */
|
|
|
| - x86_linux_update_xmltarget ();
|
| +static void
|
| +x86_arch_setup (void)
|
| +{
|
| + current_process ()->tdesc = x86_linux_read_description ();
|
| }
|
|
|
| static int
|
| @@ -1786,7 +1946,7 @@ x86_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
|
| char *err)
|
| {
|
| #ifdef __x86_64__
|
| - if (register_size (0) == 8)
|
| + if (is_64bit_tdesc ())
|
| return amd64_install_fast_tracepoint_jump_pad (tpoint, tpaddr,
|
| collector, lockaddr,
|
| orig_size, jump_entry,
|
| @@ -1820,7 +1980,7 @@ x86_get_min_fast_tracepoint_insn_len (void)
|
| #ifdef __x86_64__
|
| /* On x86-64, 5-byte jump instructions with a 4-byte offset are always
|
| used for fast tracepoints. */
|
| - if (register_size (0) == 8)
|
| + if (is_64bit_tdesc ())
|
| return 5;
|
| #endif
|
|
|
| @@ -3163,26 +3323,28 @@ static struct emit_ops *
|
| x86_emit_ops (void)
|
| {
|
| #ifdef __x86_64__
|
| - int use_64bit = register_size (0) == 8;
|
| -
|
| - if (use_64bit)
|
| + if (is_64bit_tdesc ())
|
| return &amd64_emit_ops;
|
| else
|
| #endif
|
| return &i386_emit_ops;
|
| }
|
|
|
| +static int
|
| +x86_supports_range_stepping (void)
|
| +{
|
| + return 1;
|
| +}
|
| +
|
| /* This is initialized assuming an amd64 target.
|
| x86_arch_setup will correct it for i386 or amd64 targets. */
|
|
|
| struct linux_target_ops the_low_target =
|
| {
|
| x86_arch_setup,
|
| - -1,
|
| - NULL,
|
| - NULL,
|
| - NULL,
|
| - NULL,
|
| + x86_linux_regs_info,
|
| + x86_cannot_fetch_register,
|
| + x86_cannot_store_register,
|
| NULL, /* fetch_register */
|
| x86_get_pc,
|
| x86_set_pc,
|
| @@ -3211,4 +3373,33 @@ struct linux_target_ops the_low_target =
|
| x86_install_fast_tracepoint_jump_pad,
|
| x86_emit_ops,
|
| x86_get_min_fast_tracepoint_insn_len,
|
| + x86_supports_range_stepping,
|
| };
|
| +
|
| +void
|
| +initialize_low_arch (void)
|
| +{
|
| + /* Initialize the Linux target descriptions. */
|
| +#ifdef __x86_64__
|
| + init_registers_amd64_linux ();
|
| + init_registers_amd64_avx_linux ();
|
| + init_registers_amd64_mpx_linux ();
|
| +
|
| + init_registers_x32_linux ();
|
| + init_registers_x32_avx_linux ();
|
| +
|
| + tdesc_amd64_linux_no_xml = xmalloc (sizeof (struct target_desc));
|
| + copy_target_description (tdesc_amd64_linux_no_xml, tdesc_amd64_linux);
|
| + tdesc_amd64_linux_no_xml->xmltarget = xmltarget_amd64_linux_no_xml;
|
| +#endif
|
| + init_registers_i386_linux ();
|
| + init_registers_i386_mmx_linux ();
|
| + init_registers_i386_avx_linux ();
|
| + init_registers_i386_mpx_linux ();
|
| +
|
| + tdesc_i386_linux_no_xml = xmalloc (sizeof (struct target_desc));
|
| + copy_target_description (tdesc_i386_linux_no_xml, tdesc_i386_linux);
|
| + tdesc_i386_linux_no_xml->xmltarget = xmltarget_i386_linux_no_xml;
|
| +
|
| + initialize_regsets_info (&x86_regsets_info);
|
| +}
|
|
|