+/* Get XSAVE extended state xcr0 from core dump. */
+
+uint64_t
+i386_linux_core_read_xcr0 (bfd *abfd)
+{
+ asection *xstate = bfd_get_section_by_name (abfd, ".reg-xstate");
+ uint64_t xcr0;
+
+ if (xstate)
+ {
+ size_t size = bfd_section_size (abfd, xstate);
+
+ /* Check extended state size. */
+ if (size < I386_XSTATE_AVX_SIZE)
+ xcr0 = I386_XSTATE_SSE_MASK;
+ else
+ {
+ char contents[8];
+
+ if (! bfd_get_section_contents (abfd, xstate, contents,
+ I386_LINUX_XSAVE_XCR0_OFFSET,
+ 8))
+ {
+ warning (_("Couldn't read `xcr0' bytes from "
+ "`.reg-xstate' section in core file."));
+ return 0;
+ }
+
+ xcr0 = bfd_get_64 (abfd, contents);
+ }
+ }
+ else
+ xcr0 = 0;
+
+ return xcr0;
+}
+
+/* Get Linux/x86 target description from core dump. */
+
+static const struct target_desc *
+i386_linux_core_read_description (struct gdbarch *gdbarch,
+ struct target_ops *target,
+ bfd *abfd)
+{
+ /* Linux/i386. */
+ uint64_t xcr0 = i386_linux_core_read_xcr0 (abfd);
+
+ switch ((xcr0 & I386_XSTATE_ALL_MASK))
+ {
+ case I386_XSTATE_MPX_AVX512_MASK:
+ case I386_XSTATE_AVX512_MASK:
+ return tdesc_i386_avx512_linux;
+ case I386_XSTATE_MPX_MASK:
+ return tdesc_i386_mpx_linux;
+ case I386_XSTATE_AVX_MASK:
+ return tdesc_i386_avx_linux;
+ case I386_XSTATE_SSE_MASK:
+ return tdesc_i386_linux;
+ case I386_XSTATE_X87_MASK:
+ return tdesc_i386_mmx_linux;
+ default:
+ break;
+ }
+
+ if (bfd_get_section_by_name (abfd, ".reg-xfp") != NULL)
+ return tdesc_i386_linux;
+ else
+ return tdesc_i386_mmx_linux;
+}
+
+/* Linux kernel shows PC value after the 'int $0x80' instruction even if
+ inferior is still inside the syscall. On next PTRACE_SINGLESTEP it will
+ finish the syscall but PC will not change.
+
+ Some vDSOs contain 'int $0x80; ret' and during stepping out of the syscall
+ i386_displaced_step_fixup would keep PC at the displaced pad location.
+ As PC is pointing to the 'ret' instruction before the step
+ i386_displaced_step_fixup would expect inferior has just executed that 'ret'
+ and PC should not be adjusted. In reality it finished syscall instead and
+ PC should get relocated back to its vDSO address. Hide the 'ret'
+ instruction by 'nop' so that i386_displaced_step_fixup is not confused.
+
+ It is not fully correct as the bytes in struct displaced_step_closure will
+ not match the inferior code. But we would need some new flag in
+ displaced_step_closure otherwise to keep the state that syscall is finishing
+ for the later i386_displaced_step_fixup execution as the syscall execution
+ is already no longer detectable there. The new flag field would mean
+ i386-linux-tdep.c needs to wrap all the displacement methods of i386-tdep.c
+ which does not seem worth it. The same effect is achieved by patching that
+ 'nop' instruction there instead. */
+
+static struct displaced_step_closure *
+i386_linux_displaced_step_copy_insn (struct gdbarch *gdbarch,
+ CORE_ADDR from, CORE_ADDR to,
+ struct regcache *regs)
+{
+ struct displaced_step_closure *closure;
+
+ closure = i386_displaced_step_copy_insn (gdbarch, from, to, regs);
+
+ if (i386_linux_get_syscall_number_from_regcache (regs) != -1)
+ {
+ /* Since we use simple_displaced_step_copy_insn, our closure is a
+ copy of the instruction. */
+ gdb_byte *insn = (gdb_byte *) closure;
+
+ /* Fake nop. */
+ insn[0] = 0x90;
+ }
+
+ return closure;
+}
+