+2016-02-25  Marcin Kościelnicki  <koriakin@0x04.net>
+
+       PR gdb/13808
+       * Makefile.in: Add i386-*-linux-ipa.o and amd64-*-linux-ipa.o.
+       * configure.srv: Ditto.
+       * linux-aarch64-ipa.c (get_ipa_tdesc): New function.
+       (initialize_low_tracepoint): Remove ipa_tdesc assignment.
+       * linux-amd64-ipa.c: Add "linux-x86-tdesc.h" include.
+       (init_registers_amd64_linux): Remove prototype.
+       (tdesc_amd64_linux): Remove declaration.
+       (get_ipa_tdesc): New function.
+       (initialize_low_tracepoint): Remove ipa_tdesc assignment,
+       initialize remaining tdescs.
+       * linux-i386-ipa.c: Add "linux-x86-tdesc.h" include.
+       (init_registers_i386_linux): Remove prototype.
+       (tdesc_i386_linux): Remove declaration.
+       (get_ipa_tdesc): New function.
+       (initialize_low_tracepoint): Remove ipa_tdesc assignment,
+       initialize remaining tdescs.
+       * linux-low.c (linux_get_ipa_tdesc_idx): New function.
+       (linux_target_ops): wire in linux_get_ipa_tdesc_idx.
+       * linux-low.h (struct linux_target_ops): Add get_ipa_tdesc_idx.
+       * linux-x86-low.c: Move tdesc declarations to linux-x86-tdesc.h.
+       (x86_get_ipa_tdesc_idx): New function.
+       (the_low_target): Wire in x86_get_ipa_tdesc_idx.
+       * linux-x86-tdesc.h: New file.
+       * target.h (struct target_ops): Add get_ipa_tdesc_idx.
+       (target_get_ipa_tdesc_idx): New macro.
+       * tracepoint.c (ipa_tdesc_idx): New macro.
+       (struct ipa_sym_addresses): Add addr_ipa_tdesc_idx.
+       (symbol_list): Add ipa_tdesc_idx.
+       (cmd_qtstart): Write ipa_tdesc_idx in the target.
+       (ipa_tdesc): Remove.
+       (ipa_tdesc_idx): New variable.
+       (get_context_regcache): Use get_ipa_tdesc.
+       (gdb_collect): Ditto.
+       (gdb_probe): Ditto.
+       * tracepoint.h (get_ipa_tdesc): New prototype.
+       (ipa_tdesc): Remove.
+
 2016-02-24  Pedro Alves  <palves@redhat.com>
 
        * linux-low.c (check_stopped_by_breakpoint): Rename to ...
 
 i386-linux-ipa.o: i386-linux.c
        $(IPAGENT_COMPILE) $<
        $(POSTCOMPILE)
+i386-mmx-linux-ipa.o: i386-mmx-linux.c
+       $(IPAGENT_COMPILE) $<
+       $(POSTCOMPILE)
+i386-avx-linux-ipa.o: i386-avx-linux.c
+       $(IPAGENT_COMPILE) $<
+       $(POSTCOMPILE)
+i386-mpx-linux-ipa.o: i386-mpx-linux.c
+       $(IPAGENT_COMPILE) $<
+       $(POSTCOMPILE)
+i386-avx512-linux-ipa.o: i386-avx512-linux.c
+       $(IPAGENT_COMPILE) $<
+       $(POSTCOMPILE)
 linux-i386-ipa.o: linux-i386-ipa.c
        $(IPAGENT_COMPILE) $<
        $(POSTCOMPILE)
 amd64-linux-ipa.o: amd64-linux.c
        $(IPAGENT_COMPILE) $<
        $(POSTCOMPILE)
+amd64-avx-linux-ipa.o: amd64-avx-linux.c
+       $(IPAGENT_COMPILE) $<
+       $(POSTCOMPILE)
+amd64-mpx-linux-ipa.o: amd64-mpx-linux.c
+       $(IPAGENT_COMPILE) $<
+       $(POSTCOMPILE)
+amd64-avx512-linux-ipa.o: amd64-avx512-linux.c
+       $(IPAGENT_COMPILE) $<
+       $(POSTCOMPILE)
 linux-aarch64-ipa.o: linux-aarch64-ipa.c
        $(IPAGENT_COMPILE) $<
        $(POSTCOMPILE)
 
 srv_amd64_regobj="amd64.o amd64-avx.o amd64-avx512.o amd64-mpx.o x32.o x32-avx.o x32-avx512.o"
 srv_amd64_linux_regobj="amd64-linux.o amd64-avx-linux.o amd64-avx512-linux.o amd64-mpx-linux.o x32-linux.o x32-avx-linux.o x32-avx512-linux.o"
 
-ipa_i386_linux_regobj=i386-linux-ipa.o
-ipa_amd64_linux_regobj=amd64-linux-ipa.o
+ipa_i386_linux_regobj="i386-linux-ipa.o i386-avx-linux-ipa.o i386-avx512-linux-ipa.o i386-mpx-linux-ipa.o i386-mmx-linux-ipa.o"
+ipa_amd64_linux_regobj="amd64-linux-ipa.o amd64-avx-linux-ipa.o amd64-avx512-linux-ipa.o amd64-mpx-linux-ipa.o"
 
 srv_i386_32bit_xmlfiles="i386/32bit-core.xml i386/32bit-sse.xml i386/32bit-avx.xml i386/32bit-avx512.xml i386/32bit-mpx.xml"
 srv_i386_64bit_xmlfiles="i386/64bit-core.xml i386/64bit-sse.xml i386/64bit-avx.xml i386/64bit-avx512.xml i386/x32-core.xml i386/64bit-mpx.xml"
 
                        + aarch64_ft_collect_regmap[regnum] * FT_CR_SIZE);
 }
 
+/* Return target_desc to use for IPA, given the tdesc index passed by
+   gdbserver.  Index is ignored, since we have only one tdesc
+   at the moment.  */
+
+const struct target_desc *
+get_ipa_tdesc (int idx)
+{
+  return tdesc_aarch64;
+}
+
 void
 initialize_low_tracepoint (void)
 {
   init_registers_aarch64 ();
-  ipa_tdesc = tdesc_aarch64;
 }
 
 
 #include "server.h"
 #include "tracepoint.h"
+#include "linux-x86-tdesc.h"
 
 /* Defined in auto-generated file amd64-linux.c.  */
 void init_registers_amd64_linux (void);
 
 #endif /* HAVE_UST */
 
+/* Return target_desc to use for IPA, given the tdesc index passed by
+   gdbserver.  */
+
+const struct target_desc *
+get_ipa_tdesc (int idx)
+{
+  switch (idx)
+    {
+    case X86_TDESC_SSE:
+      return tdesc_amd64_linux;
+    case X86_TDESC_AVX:
+      return tdesc_amd64_avx_linux;
+    case X86_TDESC_MPX:
+      return tdesc_amd64_mpx_linux;
+    case X86_TDESC_AVX512:
+      return tdesc_amd64_avx512_linux;
+    default:
+      internal_error (__FILE__, __LINE__,
+                     "unknown ipa tdesc index: %d", idx);
+      return tdesc_amd64_linux;
+    }
+}
+
 void
 initialize_low_tracepoint (void)
 {
   init_registers_amd64_linux ();
-  ipa_tdesc = tdesc_amd64_linux;
+  init_registers_amd64_avx_linux ();
+  init_registers_amd64_mpx_linux ();
+  init_registers_amd64_avx512_linux ();
 }
 
 #include "server.h"
 #include <sys/mman.h>
 #include "tracepoint.h"
+#include "linux-x86-tdesc.h"
 
 /* GDB register numbers.  */
 
 
 #define i386_num_regs 16
 
-/* Defined in auto-generated file i386-linux.c.  */
-void init_registers_i386_linux (void);
-extern const struct target_desc *tdesc_i386_linux;
-
 #define FT_CR_EAX 15
 #define FT_CR_ECX 14
 #define FT_CR_EDX 13
     }
 }
 
+/* Return target_desc to use for IPA, given the tdesc index passed by
+   gdbserver.  */
+
+const struct target_desc *
+get_ipa_tdesc (int idx)
+{
+  switch (idx)
+    {
+    case X86_TDESC_MMX:
+      return tdesc_i386_mmx_linux;
+    case X86_TDESC_SSE:
+      return tdesc_i386_linux;
+    case X86_TDESC_AVX:
+      return tdesc_i386_avx_linux;
+    case X86_TDESC_MPX:
+      return tdesc_i386_mpx_linux;
+    case X86_TDESC_AVX512:
+      return tdesc_i386_avx512_linux;
+    default:
+      internal_error (__FILE__, __LINE__,
+                     "unknown ipa tdesc index: %d", idx);
+      return tdesc_i386_linux;
+    }
+}
+
 void
 initialize_low_tracepoint (void)
 {
+  init_registers_i386_mmx_linux ();
   init_registers_i386_linux ();
-  ipa_tdesc = tdesc_i386_linux;
+  init_registers_i386_avx_linux ();
+  init_registers_i386_mpx_linux ();
+  init_registers_i386_avx512_linux ();
   initialize_fast_tracepoint_trampoline_buffer ();
 }
 
          && linux_supports_tracesysgood ());
 }
 
+static int
+linux_get_ipa_tdesc_idx (void)
+{
+  if (the_low_target.get_ipa_tdesc_idx == NULL)
+    return 0;
+
+  return (*the_low_target.get_ipa_tdesc_idx) ();
+}
+
 static int
 linux_supports_tracepoints (void)
 {
   linux_breakpoint_kind_from_current_state,
   linux_supports_software_single_step,
   linux_supports_catch_syscall,
+  linux_get_ipa_tdesc_idx,
 };
 
 #ifdef HAVE_LINUX_REGSETS
 
      due to SYSCALL_SIGTRAP.  */
   void (*get_syscall_trapinfo) (struct regcache *regcache,
                                int *sysno, int *sysret);
+
+  /* See target.h.  */
+  int (*get_ipa_tdesc_idx) (void);
 };
 
 extern struct linux_target_ops the_low_target;
 
 #include "nat/linux-nat.h"
 #include "nat/x86-linux.h"
 #include "nat/x86-linux-dregs.h"
-
-#ifdef __x86_64__
-/* Defined in auto-generated file amd64-linux.c.  */
-void init_registers_amd64_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);
-extern const struct target_desc *tdesc_amd64_avx_linux;
-
-/* Defined in auto-generated file amd64-avx512-linux.c.  */
-void init_registers_amd64_avx512_linux (void);
-extern const struct target_desc *tdesc_amd64_avx512_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;
-
-/* Defined in auto-generated file x32-avx512-linux.c.  */
-void init_registers_x32_avx512_linux (void);
-extern const struct target_desc *tdesc_x32_avx512_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-avx512-linux.c.  */
-void init_registers_i386_avx512_linux (void);
-extern const struct target_desc *tdesc_i386_avx512_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;
+#include "linux-x86-tdesc.h"
 
 #ifdef __x86_64__
 static struct target_desc *tdesc_amd64_linux_no_xml;
   return 1;
 }
 
+static int
+x86_get_ipa_tdesc_idx (void)
+{
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+  const struct target_desc *tdesc = regcache->tdesc;
+
+#ifdef __x86_64__
+  if (tdesc == tdesc_amd64_linux || tdesc == tdesc_amd64_linux_no_xml
+      || tdesc == tdesc_x32_linux)
+    return X86_TDESC_SSE;
+  if (tdesc == tdesc_amd64_avx_linux || tdesc == tdesc_x32_avx_linux)
+    return X86_TDESC_AVX;
+  if (tdesc == tdesc_amd64_mpx_linux)
+    return X86_TDESC_MPX;
+  if (tdesc == tdesc_amd64_avx512_linux || tdesc == tdesc_x32_avx512_linux)
+    return X86_TDESC_AVX512;
+#endif
+
+  if (tdesc == tdesc_i386_mmx_linux)
+    return X86_TDESC_MMX;
+  if (tdesc == tdesc_i386_linux || tdesc == tdesc_i386_linux_no_xml)
+    return X86_TDESC_SSE;
+  if (tdesc == tdesc_i386_avx_linux)
+    return X86_TDESC_AVX;
+  if (tdesc == tdesc_i386_mpx_linux)
+    return X86_TDESC_MPX;
+  if (tdesc == tdesc_i386_avx512_linux)
+    return X86_TDESC_AVX512;
+
+  return 0;
+}
+
 /* This is initialized assuming an amd64 target.
    x86_arch_setup will correct it for i386 or amd64 targets.  */
 
   NULL, /* breakpoint_kind_from_current_state */
   x86_supports_hardware_single_step,
   x86_get_syscall_trapinfo,
+  x86_get_ipa_tdesc_idx,
 };
 
 void
 
--- /dev/null
+/* Low level support for x86 (i386 and x86-64), shared between gdbserver
+   and IPA.
+
+   Copyright (C) 2016 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/>.  */
+
+/* Note: since IPA obviously knows what ABI it's running on (i386 vs x86_64
+   vs x32), it's sufficient to pass only the register set here.  This,
+   together with the ABI known at IPA compile time, maps to a tdesc.  */
+
+enum x86_linux_tdesc {
+  X86_TDESC_MMX = 0,
+  X86_TDESC_SSE = 1,
+  X86_TDESC_AVX = 2,
+  X86_TDESC_MPX = 3,
+  X86_TDESC_AVX512 = 4,
+};
+
+#ifdef __x86_64__
+
+#if defined __LP64__  || !defined IN_PROCESS_AGENT
+/* Defined in auto-generated file amd64-linux.c.  */
+void init_registers_amd64_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);
+extern const struct target_desc *tdesc_amd64_avx_linux;
+
+/* Defined in auto-generated file amd64-avx512-linux.c.  */
+void init_registers_amd64_avx512_linux (void);
+extern const struct target_desc *tdesc_amd64_avx512_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;
+#endif
+
+#if defined __ILP32__ || !defined IN_PROCESS_AGENT
+/* 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;
+
+/* Defined in auto-generated file x32-avx512-linux.c.  */
+void init_registers_x32_avx512_linux (void);
+extern const struct target_desc *tdesc_x32_avx512_linux;
+#endif
+
+#endif
+
+#if defined __i386__ || !defined IN_PROCESS_AGENT
+/* 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-avx512-linux.c.  */
+void init_registers_i386_avx512_linux (void);
+extern const struct target_desc *tdesc_i386_avx512_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;
+#endif
 
   /* Return 1 if the target supports catch syscall, 0 (or leave the
      callback NULL) otherwise.  */
   int (*supports_catch_syscall) (void);
+
+  /* Return tdesc index for IPA.  */
+  int (*get_ipa_tdesc_idx) (void);
 };
 
 extern struct target_ops *the_target;
   (the_target->supports_catch_syscall ?                        \
    (*the_target->supports_catch_syscall) () : 0)
 
+#define target_get_ipa_tdesc_idx()                     \
+  (the_target->get_ipa_tdesc_idx                       \
+   ? (*the_target->get_ipa_tdesc_idx) () : 0)
+
 #define target_supports_tracepoints()                  \
   (the_target->supports_tracepoints                    \
    ? (*the_target->supports_tracepoints) () : 0)
 
 # define ust_loaded IPA_SYM_EXPORTED_NAME (ust_loaded)
 # define helper_thread_id IPA_SYM_EXPORTED_NAME (helper_thread_id)
 # define cmd_buf IPA_SYM_EXPORTED_NAME (cmd_buf)
+# define ipa_tdesc_idx IPA_SYM_EXPORTED_NAME (ipa_tdesc_idx)
 #endif
 
 #ifndef IN_PROCESS_AGENT
   CORE_ADDR addr_get_trace_state_variable_value;
   CORE_ADDR addr_set_trace_state_variable_value;
   CORE_ADDR addr_ust_loaded;
+  CORE_ADDR addr_ipa_tdesc_idx;
 };
 
 static struct
   IPA_SYM(get_trace_state_variable_value),
   IPA_SYM(set_trace_state_variable_value),
   IPA_SYM(ust_loaded),
+  IPA_SYM(ipa_tdesc_idx),
 };
 
 static struct ipa_sym_addresses ipa_sym_addrs;
 
   *packet = '\0';
 
+  /* Tell IPA about the correct tdesc.  */
+  if (write_inferior_integer (ipa_sym_addrs.addr_ipa_tdesc_idx,
+                             target_get_ipa_tdesc_idx ()))
+    error ("Error setting ipa_tdesc_idx variable in lib");
+
   /* Start out empty.  */
   if (agent_loaded_p ())
     write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, 0);
 #endif
 
 #ifdef IN_PROCESS_AGENT
-/* The target description used by the IPA.  Given that the IPA library
-   is built for a specific architecture that is loaded into the
-   inferior, there only needs to be one such description per
-   build.  */
-const struct target_desc *ipa_tdesc;
+/* The target description index for IPA.  Passed from gdbserver, used
+   to select ipa_tdesc.  */
+EXTERN_C_PUSH
+IP_AGENT_EXPORT_VAR int ipa_tdesc_idx;
+EXTERN_C_POP
 #endif
 
 static struct regcache *
 get_context_regcache (struct tracepoint_hit_ctx *ctx)
 {
   struct regcache *regcache = NULL;
-
 #ifdef IN_PROCESS_AGENT
+  const struct target_desc *ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx);
+
   if (ctx->type == fast_tracepoint)
     {
       struct fast_tracepoint_ctx *fctx = (struct fast_tracepoint_ctx *) ctx;
 gdb_collect (struct tracepoint *tpoint, unsigned char *regs)
 {
   struct fast_tracepoint_ctx ctx;
+  const struct target_desc *ipa_tdesc;
 
   /* Don't do anything until the trace run is completely set up.  */
   if (!tracing)
     return;
 
+  ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx);
   ctx.base.type = fast_tracepoint;
   ctx.regs = regs;
   ctx.regcache_initted = 0;
 {
   struct tracepoint *tpoint;
   struct static_tracepoint_ctx ctx;
+  const struct target_desc *ipa_tdesc;
 
   /* Don't do anything until the trace run is completely set up.  */
   if (!tracing)
       return;
     }
 
+  ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx);
   ctx.base.type = static_tracepoint;
   ctx.regcache_initted = 0;
   ctx.regs = regs;
 
 
 #ifdef IN_PROCESS_AGENT
 void initialize_low_tracepoint (void);
+const struct target_desc *get_ipa_tdesc (int idx);
 void supply_fast_tracepoint_registers (struct regcache *regcache,
                                       const unsigned char *regs);
 void supply_static_tracepoint_registers (struct regcache *regcache,
                                         CORE_ADDR pc);
 void set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end,
                                  char *errmsg);
-
-extern const struct target_desc *ipa_tdesc;
-
 #else
 void stop_tracing (void);
 
 
+2016-02-25  Marcin Kościelnicki  <koriakin@0x04.net>
+
+       PR gdb/13808
+       * gdb.trace/ftrace.exp (test_fast_tracepoints): Remove kfail.
+
 2016-02-25  Marcin Kościelnicki  <koriakin@0x04.net>
 
        * gdb.trace/ftrace.exp: Remove unnecessary target check.
 
     gdb_test "tfind pc *set_point" "Found trace frame .*" \
         "tfind set_point frame, first time"
 
-    setup_kfail "gdb/13808" "x86_64-*-linux*"
     gdb_test "print globvar" " = 1"
 
     gdb_test "tfind pc *set_point" "Found trace frame .*" \