aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorTristan Gingold <gingold@adacore.com>2009-06-05 09:19:44 +0000
committerTristan Gingold <gingold@adacore.com>2009-06-05 09:19:44 +0000
commit154a1ee56c0283227aa6268ddbefe372c34e642a (patch)
tree9eb1700456cddad6d9c5bd48edec34aab6cf9278 /bfd
parent07070927ceb9126f8a5cb344597870bf2ebf2f54 (diff)
downloadfsf-binutils-gdb-154a1ee56c0283227aa6268ddbefe372c34e642a.zip
fsf-binutils-gdb-154a1ee56c0283227aa6268ddbefe372c34e642a.tar.gz
fsf-binutils-gdb-154a1ee56c0283227aa6268ddbefe372c34e642a.tar.bz2
2009-06-05 Tristan Gingold <gingold@adacore.com>
* mach-o.h: Update copyright year. (bfd_mach_o_mach_header_magic): New enum. (bfd_mach_o_cpu_subtype): Now an enum. (BFD_MACH_O_HEADER_SIZE, BFD_MACH_O_HEADER_64_SIZE): New macros. (BFD_MACH_O_SECTION_SIZE, BFD_MACH_O_SECTION_64_SIZE): Ditto. (BFD_MACH_O_LC_SEGMENT_SIZE, BFD_MACH_O_LC_SEGMENT_64_SIZE): Ditto. (bfd_mach_o_load_command): Field type_required is now a boolean. Reindent prototypes. (bfd_mach_o_object_p, bfd_mach_o_core_p): Remove. (bfd_mach_o_bfd_copy_private_symbol_data): Add a prototype. (bfd_mach_o_bfd_copy_private_section_data): Ditto. (bfd_mach_o_bfd_copy_private_bfd_data): Ditto. (bfd_mach_o_get_symtab_upper_bound): Ditto. (bfd_mach_o_canonicalize_symtab): Ditto. (bfd_mach_o_get_symbol_info): Ditto. (bfd_mach_o_print_symbol): Ditto. (bfd_mach_o_bfd_print_private_bfd_data): Ditto. (bfd_mach_o_make_empty_symbol): Ditto. (bfd_mach_o_write_contents): Ditto. * mach-o.c (bfd_mach_o_object_p, bfd_mach_o_core_p, bfd_mach_o_mkobject): Defines. (bfd_mach_o_valid): Returns FALSE/TRUE instead of 0/1. Do not check with target vector but with flavour. (struct mach_o_section_name_xlat): New declaration. (dwarf_section_names_xlat): Ditto. (text_section_names_xlat): Ditto. (data_section_names_xlat): Ditto. (struct mach_o_segment_name_xlat): Ditto. (segsec_names_xlat): Ditto. (bfd_mach_o_convert_section_name_to_bfd): New function. (bfd_mach_o_convert_section_name_to_mach_o): Ditto. (bfd_mach_o_bfd_copy_private_symbol_data): Make it public. (bfd_mach_o_bfd_copy_private_section_data): Ditto. (bfd_mach_o_bfd_copy_private_bfd_data): Ditto. Accept any input and output flavour. Do not share private data anymore. (bfd_mach_o_count_symbols): Add a comment. (bfd_mach_o_get_symtab_upper_bound): Make it public. (bfd_mach_o_canonicalize_symtab): Ditto. (bfd_mach_o_get_symbol_info): Ditto. (bfd_mach_o_print_symbol): Ditto. (bfd_mach_o_write_header): Now returns a boolean instead of an int. Use constants instead of hard-coded values. (bfd_mach_o_scan_write_section_32): Use constants instead of hard-coded values. (bfd_mach_o_scan_write_section_64): Ditto. (bfd_mach_o_scan_write_segment): Ditto. Do not copy sections anymore. (bfd_mach_o_write_contents): Make it public. Remove dead code. Rewrite typeflag assignment. (bfd_mach_o_build_commands): New function. (bfd_mach_o_set_section_contents): Ditto. (bfd_mach_o_make_empty_symbol): Make it public. (bfd_mach_o_read_header): Make it static. Convert to bfd_boolean. Use constants instead of hard-coded values. (bfd_mach_o_make_bfd_section): Call bfd_mach_o_convert_section_name_to_bfd to create name. (bfd_mach_o_scan_read_section_32): Use constants instead of hard-coded values. (bfd_mach_o_scan_read_section_64): Ditto. (bfd_mach_o_scan_read_segment): Do not create a bfd section for a segment anymore. Use constants instead of hard-coded values. (bfd_mach_o_scan_read_command): Fix style. (bfd_mach_o_scan): Use constants instead of hard-coded values. Get rid of BFD_IO_FUNCS. (bfd_mach_o_mkobject_init): Renamed from bfd_mach_o_mkobject. (bfd_mach_o_header_p): Created from bfd_mach_o_object_p. (bfd_mach_o_gen_object_p): New function, replaces bfd_mach_o_object_p. (bfd_mach_o_object_p): Removed. (bfd_mach_o_gen_core_p): New function, replaces ... (bfd_mach_o_core_p): ... deleted. (bfd_mach_o_bfd_print_private_bfd_data): Make it public. * mach-o-i386.c: New file. * config.bfd: Use mach_o_i386_vec as targ_defvec for ix86-darwin. * configure.in (TDEFINES): Add mach_o_i386_vec. * configure: Regenerated. * targets.c: Add mach_o_i386_vec. * mach-o.c: Update copyright years. (BFD_IO_FUNCS): Remove (was not used). (bfd_mach_o_mkarchive, bfd_mach_o_read_ar_hdr, bfd_mach_o_slurp_armap bfd_mach_o_slurp_extended_name_table, bfd_mach_o_construct_extended_name_table, bfd_mach_o_truncate_arname, bfd_mach_o_write_armap, bfd_mach_o_get_elt_at_index, bfd_mach_o_generic_stat_arch_elt, bfd_mach_o_update_armap_timestamp, bfd_mach_o_close_and_cleanup, bfd_mach_o_bfd_free_cached_info, bfd_mach_o_new_section_hook, bfd_mach_o_get_section_contents_in_window, bfd_mach_o_bfd_is_local_label_name, bfd_mach_o_bfd_is_target_special_symbol, bfd_mach_o_bfd_is_local_label_name, bfd_mach_o_get_lineno, bfd_mach_o_find_nearest_line, bfd_mach_o_find_inliner_info, bfd_mach_o_bfd_make_debug_symbol, bfd_mach_o_read_minisymbols, bfd_mach_o_minisymbol_to_symbol, bfd_mach_o_bfd_get_relocated_section_contents, bfd_mach_o_bfd_relax_section, bfd_mach_o_bfd_link_hash_table_create, bfd_mach_o_bfd_link_hash_table_free, bfd_mach_o_bfd_link_add_symbols, bfd_mach_o_bfd_link_just_syms, bfd_mach_o_bfd_final_link, bfd_mach_o_bfd_link_split_section, bfd_mach_o_set_arch_mach, bfd_mach_o_bfd_merge_private_bfd_data, bfd_mach_o_bfd_set_private_flags, bfd_mach_o_get_section_contents, bfd_mach_o_bfd_gc_sections, bfd_mach_o_bfd_merge_sections, bfd_mach_o_bfd_is_group_section, bfd_mach_o_bfd_discard_group, bfd_mach_o_section_already_linked, bfd_mach_o_bfd_define_common_symbol, bfd_mach_o_bfd_copy_private_header_data, bfd_mach_o_core_file_matches_executable_p): Move these defines ... * mach-o-target.c: ... here. Update copyright years.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog120
-rw-r--r--bfd/config.bfd4
-rwxr-xr-xbfd/configure1
-rw-r--r--bfd/configure.in1
-rw-r--r--bfd/mach-o-i386.c69
-rw-r--r--bfd/mach-o-target.c54
-rw-r--r--bfd/mach-o.c656
-rw-r--r--bfd/mach-o.h84
-rw-r--r--bfd/targets.c2
9 files changed, 710 insertions, 281 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 6f8f3ea..34bb1f8 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,117 @@
+2009-06-05 Tristan Gingold <gingold@adacore.com>
+
+ * mach-o.h: Update copyright year.
+ (bfd_mach_o_mach_header_magic): New enum.
+ (bfd_mach_o_cpu_subtype): Now an enum.
+ (BFD_MACH_O_HEADER_SIZE, BFD_MACH_O_HEADER_64_SIZE): New macros.
+ (BFD_MACH_O_SECTION_SIZE, BFD_MACH_O_SECTION_64_SIZE): Ditto.
+ (BFD_MACH_O_LC_SEGMENT_SIZE, BFD_MACH_O_LC_SEGMENT_64_SIZE): Ditto.
+ (bfd_mach_o_load_command): Field type_required is now a boolean.
+ Reindent prototypes.
+ (bfd_mach_o_object_p, bfd_mach_o_core_p): Remove.
+ (bfd_mach_o_bfd_copy_private_symbol_data): Add a prototype.
+ (bfd_mach_o_bfd_copy_private_section_data): Ditto.
+ (bfd_mach_o_bfd_copy_private_bfd_data): Ditto.
+ (bfd_mach_o_get_symtab_upper_bound): Ditto.
+ (bfd_mach_o_canonicalize_symtab): Ditto.
+ (bfd_mach_o_get_symbol_info): Ditto.
+ (bfd_mach_o_print_symbol): Ditto.
+ (bfd_mach_o_bfd_print_private_bfd_data): Ditto.
+ (bfd_mach_o_make_empty_symbol): Ditto.
+ (bfd_mach_o_write_contents): Ditto.
+
+ * mach-o.c (bfd_mach_o_object_p, bfd_mach_o_core_p,
+ bfd_mach_o_mkobject): Defines.
+ (bfd_mach_o_valid): Returns FALSE/TRUE instead of 0/1.
+ Do not check with target vector but with flavour.
+ (struct mach_o_section_name_xlat): New declaration.
+ (dwarf_section_names_xlat): Ditto.
+ (text_section_names_xlat): Ditto.
+ (data_section_names_xlat): Ditto.
+ (struct mach_o_segment_name_xlat): Ditto.
+ (segsec_names_xlat): Ditto.
+ (bfd_mach_o_convert_section_name_to_bfd): New function.
+ (bfd_mach_o_convert_section_name_to_mach_o): Ditto.
+ (bfd_mach_o_bfd_copy_private_symbol_data): Make it public.
+ (bfd_mach_o_bfd_copy_private_section_data): Ditto.
+ (bfd_mach_o_bfd_copy_private_bfd_data): Ditto.
+ Accept any input and output flavour. Do not share private data
+ anymore.
+ (bfd_mach_o_count_symbols): Add a comment.
+ (bfd_mach_o_get_symtab_upper_bound): Make it public.
+ (bfd_mach_o_canonicalize_symtab): Ditto.
+ (bfd_mach_o_get_symbol_info): Ditto.
+ (bfd_mach_o_print_symbol): Ditto.
+ (bfd_mach_o_write_header): Now returns a boolean instead of an int.
+ Use constants instead of hard-coded values.
+ (bfd_mach_o_scan_write_section_32): Use constants instead of hard-coded
+ values.
+ (bfd_mach_o_scan_write_section_64): Ditto.
+ (bfd_mach_o_scan_write_segment): Ditto.
+ Do not copy sections anymore.
+ (bfd_mach_o_write_contents): Make it public.
+ Remove dead code. Rewrite typeflag assignment.
+ (bfd_mach_o_build_commands): New function.
+ (bfd_mach_o_set_section_contents): Ditto.
+ (bfd_mach_o_make_empty_symbol): Make it public.
+ (bfd_mach_o_read_header): Make it static.
+ Convert to bfd_boolean.
+ Use constants instead of hard-coded values.
+ (bfd_mach_o_make_bfd_section): Call
+ bfd_mach_o_convert_section_name_to_bfd to create name.
+ (bfd_mach_o_scan_read_section_32): Use constants instead of hard-coded
+ values.
+ (bfd_mach_o_scan_read_section_64): Ditto.
+ (bfd_mach_o_scan_read_segment): Do not create a bfd section for
+ a segment anymore. Use constants instead of hard-coded values.
+ (bfd_mach_o_scan_read_command): Fix style.
+ (bfd_mach_o_scan): Use constants instead of hard-coded values.
+ Get rid of BFD_IO_FUNCS.
+ (bfd_mach_o_mkobject_init): Renamed from bfd_mach_o_mkobject.
+ (bfd_mach_o_header_p): Created from bfd_mach_o_object_p.
+ (bfd_mach_o_gen_object_p): New function, replaces bfd_mach_o_object_p.
+ (bfd_mach_o_object_p): Removed.
+ (bfd_mach_o_gen_core_p): New function, replaces ...
+ (bfd_mach_o_core_p): ... deleted.
+ (bfd_mach_o_bfd_print_private_bfd_data): Make it public.
+
+ * mach-o-i386.c: New file.
+ * config.bfd: Use mach_o_i386_vec as targ_defvec for ix86-darwin.
+ * configure.in (TDEFINES): Add mach_o_i386_vec.
+ * configure: Regenerated.
+ * targets.c: Add mach_o_i386_vec.
+
+ * mach-o.c: Update copyright years.
+ (BFD_IO_FUNCS): Remove (was not used).
+ (bfd_mach_o_mkarchive, bfd_mach_o_read_ar_hdr, bfd_mach_o_slurp_armap
+ bfd_mach_o_slurp_extended_name_table,
+ bfd_mach_o_construct_extended_name_table,
+ bfd_mach_o_truncate_arname, bfd_mach_o_write_armap,
+ bfd_mach_o_get_elt_at_index, bfd_mach_o_generic_stat_arch_elt,
+ bfd_mach_o_update_armap_timestamp, bfd_mach_o_close_and_cleanup,
+ bfd_mach_o_bfd_free_cached_info, bfd_mach_o_new_section_hook,
+ bfd_mach_o_get_section_contents_in_window,
+ bfd_mach_o_bfd_is_local_label_name,
+ bfd_mach_o_bfd_is_target_special_symbol,
+ bfd_mach_o_bfd_is_local_label_name, bfd_mach_o_get_lineno,
+ bfd_mach_o_find_nearest_line, bfd_mach_o_find_inliner_info,
+ bfd_mach_o_bfd_make_debug_symbol, bfd_mach_o_read_minisymbols,
+ bfd_mach_o_minisymbol_to_symbol,
+ bfd_mach_o_bfd_get_relocated_section_contents,
+ bfd_mach_o_bfd_relax_section, bfd_mach_o_bfd_link_hash_table_create,
+ bfd_mach_o_bfd_link_hash_table_free, bfd_mach_o_bfd_link_add_symbols,
+ bfd_mach_o_bfd_link_just_syms, bfd_mach_o_bfd_final_link,
+ bfd_mach_o_bfd_link_split_section, bfd_mach_o_set_arch_mach,
+ bfd_mach_o_bfd_merge_private_bfd_data,
+ bfd_mach_o_bfd_set_private_flags, bfd_mach_o_get_section_contents,
+ bfd_mach_o_bfd_gc_sections, bfd_mach_o_bfd_merge_sections,
+ bfd_mach_o_bfd_is_group_section, bfd_mach_o_bfd_discard_group,
+ bfd_mach_o_section_already_linked, bfd_mach_o_bfd_define_common_symbol,
+ bfd_mach_o_bfd_copy_private_header_data,
+ bfd_mach_o_core_file_matches_executable_p): Move these defines ...
+ * mach-o-target.c: ... here.
+ Update copyright years.
+
2009-06-04 Alan Modra <amodra@bigpond.net.au>
* dep-in.sed: Don't use \n in replacement part of s command.
@@ -564,7 +678,7 @@
2009-04-21 H.J. Lu <hongjiu.lu@intel.com>
* coff-ia64.c (COFF_PAGE_SIZE): Changed to 8K.
-
+
* coffcode.h (coff_compute_section_file_positions): Clear
D_PAGED if PE section alignment is smaller than COFF_PAGE_SIZE.
@@ -817,7 +931,7 @@
2009-04-02 Sterling Augustine <sterling@jaw.hq.tensilica.com>
- * elf32-xtensa.c (relax_property_section): Always set r_offset
+ * elf32-xtensa.c (relax_property_section): Always set r_offset
to zero.
2009-04-02 Christophe Lyon <christophe.lyon@st.com>
@@ -833,7 +947,7 @@
* elf32-vax.c (elf_vax_check_relocs): Do not put relocations against
hidden symbols into the GOT or PLT.GOT.
- (elf_vax_relocate_section): Do not emit a PCREL reloc
+ (elf_vax_relocate_section): Do not emit a PCREL reloc
into a shared object if it is against a hidden symbol.
2009-04-01 Richard Sandiford <r.sandiford@uk.ibm.com>
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 545d848..0d042d7 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -541,8 +541,8 @@ case "${targ}" in
targ_selvecs="i386coff_vec i386aout_vec"
;;
i[3-7]86-*-darwin* | i[3-7]86-*-macos10* | i[3-7]86-*-rhapsody*)
- targ_defvec=mach_o_le_vec
- targ_selvecs="mach_o_le_vec mach_o_be_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec"
+ targ_defvec=mach_o_i386_vec
+ targ_selvecs="mach_o_i386_vec mach_o_le_vec mach_o_be_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec"
targ_archs="bfd_i386_arch bfd_powerpc_arch bfd_rs6000_arch"
;;
i[3-7]86-sequent-bsd*)
diff --git a/bfd/configure b/bfd/configure
index 32f7713..0e3a02a 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -21171,6 +21171,7 @@ do
mach_o_be_vec) tb="$tb mach-o.lo" ;;
mach_o_le_vec) tb="$tb mach-o.lo" ;;
mach_o_fat_vec) tb="$tb mach-o.lo" ;;
+ mach_o_i386_vec) tb="$tb mach-o-i386.lo" ;;
mcore_pe_big_vec) tb="$tb pe-mcore.lo peigen.lo cofflink.lo" ;;
mcore_pe_little_vec) tb="$tb pe-mcore.lo peigen.lo cofflink.lo" ;;
mcore_pei_big_vec) tb="$tb pei-mcore.lo peigen.lo cofflink.lo" ;;
diff --git a/bfd/configure.in b/bfd/configure.in
index 00c339a..0b446e2 100644
--- a/bfd/configure.in
+++ b/bfd/configure.in
@@ -868,6 +868,7 @@ do
mach_o_be_vec) tb="$tb mach-o.lo" ;;
mach_o_le_vec) tb="$tb mach-o.lo" ;;
mach_o_fat_vec) tb="$tb mach-o.lo" ;;
+ mach_o_i386_vec) tb="$tb mach-o-i386.lo" ;;
mcore_pe_big_vec) tb="$tb pe-mcore.lo peigen.lo cofflink.lo" ;;
mcore_pe_little_vec) tb="$tb pe-mcore.lo peigen.lo cofflink.lo" ;;
mcore_pei_big_vec) tb="$tb pei-mcore.lo peigen.lo cofflink.lo" ;;
diff --git a/bfd/mach-o-i386.c b/bfd/mach-o-i386.c
new file mode 100644
index 0000000..60a6a6f
--- /dev/null
+++ b/bfd/mach-o-i386.c
@@ -0,0 +1,69 @@
+/* Intel i386 Mach-O support for BFD.
+ Copyright 2009
+ Free Software Foundation, Inc.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "sysdep.h"
+#include "mach-o.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "libiberty.h"
+
+#define bfd_mach_o_object_p bfd_mach_o_i386_object_p
+#define bfd_mach_o_core_p bfd_mach_o_i386_core_p
+#define bfd_mach_o_mkobject bfd_mach_o_i386_mkobject
+
+static const bfd_target *
+bfd_mach_o_i386_object_p (bfd *abfd)
+{
+ return bfd_mach_o_header_p (abfd, 0, BFD_MACH_O_CPU_TYPE_I386);
+}
+
+static const bfd_target *
+bfd_mach_o_i386_core_p (bfd *abfd)
+{
+ return bfd_mach_o_header_p (abfd,
+ BFD_MACH_O_MH_CORE, BFD_MACH_O_CPU_TYPE_I386);
+}
+
+static bfd_boolean
+bfd_mach_o_i386_mkobject (bfd *abfd)
+{
+ bfd_mach_o_data_struct *mdata;
+
+ if (!bfd_mach_o_mkobject_init (abfd))
+ return FALSE;
+
+ mdata = abfd->tdata.mach_o_data;
+ mdata->header.magic = BFD_MACH_O_MH_MAGIC;
+ mdata->header.cputype = BFD_MACH_O_CPU_TYPE_I386;
+ mdata->header.cpusubtype = BFD_MACH_O_CPU_SUBTYPE_X86_ALL;
+ mdata->header.filetype = BFD_MACH_O_MH_OBJECT;
+ mdata->header.byteorder = BFD_ENDIAN_LITTLE;
+ mdata->header.version = 1;
+
+ return TRUE;
+}
+
+#define TARGET_NAME mach_o_i386_vec
+#define TARGET_STRING "mach-o-i386"
+#define TARGET_BIG_ENDIAN 0
+#define TARGET_ARCHIVE 0
+
+#include "mach-o-target.c"
diff --git a/bfd/mach-o-target.c b/bfd/mach-o-target.c
index a435e6e..bf68f93 100644
--- a/bfd/mach-o-target.c
+++ b/bfd/mach-o-target.c
@@ -1,5 +1,5 @@
/* Mach-O support for BFD.
- Copyright 1999, 2000, 2001, 2002, 2007
+ Copyright 1999, 2000, 2001, 2002, 2007, 2009
Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
@@ -19,6 +19,58 @@
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
+/* Define generic entry points here so that we don't need to duplicate the
+ defines in every target. But define once as this file may be included
+ several times. */
+#ifndef MACH_O_TARGET_COMMON_DEFINED
+#define MACH_O_TARGET_COMMON_DEFINED
+
+#define bfd_mach_o_mkarchive _bfd_noarchive_mkarchive
+#define bfd_mach_o_read_ar_hdr _bfd_noarchive_read_ar_hdr
+#define bfd_mach_o_slurp_armap _bfd_noarchive_slurp_armap
+#define bfd_mach_o_slurp_extended_name_table _bfd_noarchive_slurp_extended_name_table
+#define bfd_mach_o_construct_extended_name_table _bfd_noarchive_construct_extended_name_table
+#define bfd_mach_o_truncate_arname _bfd_noarchive_truncate_arname
+#define bfd_mach_o_write_armap _bfd_noarchive_write_armap
+#define bfd_mach_o_get_elt_at_index _bfd_noarchive_get_elt_at_index
+#define bfd_mach_o_generic_stat_arch_elt _bfd_noarchive_generic_stat_arch_elt
+#define bfd_mach_o_update_armap_timestamp _bfd_noarchive_update_armap_timestamp
+#define bfd_mach_o_close_and_cleanup _bfd_generic_close_and_cleanup
+#define bfd_mach_o_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
+#define bfd_mach_o_new_section_hook _bfd_generic_new_section_hook
+#define bfd_mach_o_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
+#define bfd_mach_o_bfd_is_local_label_name _bfd_nosymbols_bfd_is_local_label_name
+#define bfd_mach_o_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
+#define bfd_mach_o_bfd_is_local_label_name _bfd_nosymbols_bfd_is_local_label_name
+#define bfd_mach_o_get_lineno _bfd_nosymbols_get_lineno
+#define bfd_mach_o_find_nearest_line _bfd_nosymbols_find_nearest_line
+#define bfd_mach_o_find_inliner_info _bfd_nosymbols_find_inliner_info
+#define bfd_mach_o_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
+#define bfd_mach_o_read_minisymbols _bfd_generic_read_minisymbols
+#define bfd_mach_o_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
+#define bfd_mach_o_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
+#define bfd_mach_o_bfd_relax_section bfd_generic_relax_section
+#define bfd_mach_o_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
+#define bfd_mach_o_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
+#define bfd_mach_o_bfd_link_add_symbols _bfd_generic_link_add_symbols
+#define bfd_mach_o_bfd_link_just_syms _bfd_generic_link_just_syms
+#define bfd_mach_o_bfd_final_link _bfd_generic_final_link
+#define bfd_mach_o_bfd_link_split_section _bfd_generic_link_split_section
+#define bfd_mach_o_set_arch_mach bfd_default_set_arch_mach
+#define bfd_mach_o_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
+#define bfd_mach_o_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
+#define bfd_mach_o_get_section_contents _bfd_generic_get_section_contents
+#define bfd_mach_o_bfd_gc_sections bfd_generic_gc_sections
+#define bfd_mach_o_bfd_merge_sections bfd_generic_merge_sections
+#define bfd_mach_o_bfd_is_group_section bfd_generic_is_group_section
+#define bfd_mach_o_bfd_discard_group bfd_generic_discard_group
+#define bfd_mach_o_section_already_linked _bfd_generic_section_already_linked
+#define bfd_mach_o_bfd_define_common_symbol bfd_generic_define_common_symbol
+#define bfd_mach_o_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data
+#define bfd_mach_o_core_file_matches_executable_p generic_core_file_matches_executable_p
+
+#endif /* MACH_O_TARGET_COMMON_DEFINED */
+
#ifndef TARGET_NAME
#error TARGET_NAME must be defined
#endif /* TARGET_NAME */
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index df15312..86f3dd1 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -1,5 +1,5 @@
/* Mach-O support for BFD.
- Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
@@ -27,54 +27,9 @@
#include "aout/stab_gnu.h"
#include <ctype.h>
-#ifndef BFD_IO_FUNCS
-#define BFD_IO_FUNCS 0
-#endif
-
-#define bfd_mach_o_mkarchive _bfd_noarchive_mkarchive
-#define bfd_mach_o_read_ar_hdr _bfd_noarchive_read_ar_hdr
-#define bfd_mach_o_slurp_armap _bfd_noarchive_slurp_armap
-#define bfd_mach_o_slurp_extended_name_table _bfd_noarchive_slurp_extended_name_table
-#define bfd_mach_o_construct_extended_name_table _bfd_noarchive_construct_extended_name_table
-#define bfd_mach_o_truncate_arname _bfd_noarchive_truncate_arname
-#define bfd_mach_o_write_armap _bfd_noarchive_write_armap
-#define bfd_mach_o_get_elt_at_index _bfd_noarchive_get_elt_at_index
-#define bfd_mach_o_generic_stat_arch_elt _bfd_noarchive_generic_stat_arch_elt
-#define bfd_mach_o_update_armap_timestamp _bfd_noarchive_update_armap_timestamp
-#define bfd_mach_o_close_and_cleanup _bfd_generic_close_and_cleanup
-#define bfd_mach_o_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
-#define bfd_mach_o_new_section_hook _bfd_generic_new_section_hook
-#define bfd_mach_o_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
-#define bfd_mach_o_bfd_is_local_label_name _bfd_nosymbols_bfd_is_local_label_name
-#define bfd_mach_o_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
-#define bfd_mach_o_bfd_is_local_label_name _bfd_nosymbols_bfd_is_local_label_name
-#define bfd_mach_o_get_lineno _bfd_nosymbols_get_lineno
-#define bfd_mach_o_find_nearest_line _bfd_nosymbols_find_nearest_line
-#define bfd_mach_o_find_inliner_info _bfd_nosymbols_find_inliner_info
-#define bfd_mach_o_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
-#define bfd_mach_o_read_minisymbols _bfd_generic_read_minisymbols
-#define bfd_mach_o_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
-#define bfd_mach_o_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
-#define bfd_mach_o_bfd_relax_section bfd_generic_relax_section
-#define bfd_mach_o_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
-#define bfd_mach_o_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
-#define bfd_mach_o_bfd_link_add_symbols _bfd_generic_link_add_symbols
-#define bfd_mach_o_bfd_link_just_syms _bfd_generic_link_just_syms
-#define bfd_mach_o_bfd_final_link _bfd_generic_final_link
-#define bfd_mach_o_bfd_link_split_section _bfd_generic_link_split_section
-#define bfd_mach_o_set_arch_mach bfd_default_set_arch_mach
-#define bfd_mach_o_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
-#define bfd_mach_o_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
-#define bfd_mach_o_get_section_contents _bfd_generic_get_section_contents
-#define bfd_mach_o_set_section_contents _bfd_generic_set_section_contents
-#define bfd_mach_o_bfd_gc_sections bfd_generic_gc_sections
-#define bfd_mach_o_bfd_merge_sections bfd_generic_merge_sections
-#define bfd_mach_o_bfd_is_group_section bfd_generic_is_group_section
-#define bfd_mach_o_bfd_discard_group bfd_generic_discard_group
-#define bfd_mach_o_section_already_linked _bfd_generic_section_already_linked
-#define bfd_mach_o_bfd_define_common_symbol bfd_generic_define_common_symbol
-#define bfd_mach_o_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data
-#define bfd_mach_o_core_file_matches_executable_p generic_core_file_matches_executable_p
+#define bfd_mach_o_object_p bfd_mach_o_gen_object_p
+#define bfd_mach_o_core_p bfd_mach_o_gen_core_p
+#define bfd_mach_o_mkobject bfd_false
static unsigned int
bfd_mach_o_version (bfd *abfd)
@@ -91,22 +46,180 @@ bfd_boolean
bfd_mach_o_valid (bfd *abfd)
{
if (abfd == NULL || abfd->xvec == NULL)
- return 0;
+ return FALSE;
- if (! ((abfd->xvec == &mach_o_be_vec)
- || (abfd->xvec == &mach_o_le_vec)
- || (abfd->xvec == &mach_o_fat_vec)))
- return 0;
+ if (abfd->xvec->flavour != bfd_target_mach_o_flavour)
+ return FALSE;
if (abfd->tdata.mach_o_data == NULL)
- return 0;
- return 1;
+ return FALSE;
+ return TRUE;
+}
+
+/* Tables to translate well known Mach-O segment/section names to bfd
+ names. Use of canonical names (such as .text or .debug_frame) is required
+ by gdb. */
+
+struct mach_o_section_name_xlat
+{
+ const char *bfd_name;
+ const char *mach_o_name;
+};
+
+static const struct mach_o_section_name_xlat dwarf_section_names_xlat[] =
+ {
+ { ".debug_frame", "__debug_frame" },
+ { ".debug_info", "__debug_info" },
+ { ".debug_abbrev", "__debug_abbrev" },
+ { ".debug_aranges", "__debug_aranges" },
+ { ".debug_macinfo", "__debug_macinfo" },
+ { ".debug_line", "__debug_line" },
+ { ".debug_loc", "__debug_loc" },
+ { ".debug_pubnames", "__debug_pubnames" },
+ { ".debug_pubtypes", "__debug_pubtypes" },
+ { ".debug_str", "__debug_str" },
+ { ".debug_ranges", "__debug_ranges" },
+ { NULL, NULL}
+ };
+
+static const struct mach_o_section_name_xlat text_section_names_xlat[] =
+ {
+ { ".text", "__text" },
+ { ".cstring", "__cstring" },
+ { ".eh_frame", "__eh_frame" },
+ { NULL, NULL}
+ };
+
+static const struct mach_o_section_name_xlat data_section_names_xlat[] =
+ {
+ { ".data", "__data" },
+ { ".bss", "__bss" },
+ { NULL, NULL}
+ };
+
+struct mach_o_segment_name_xlat
+{
+ const char *segname;
+ const struct mach_o_section_name_xlat *sections;
+};
+
+static const struct mach_o_segment_name_xlat segsec_names_xlat[] =
+ {
+ { "__DWARF", dwarf_section_names_xlat },
+ { "__TEXT", text_section_names_xlat },
+ { "__DATA", data_section_names_xlat },
+ { NULL, NULL }
+ };
+
+
+/* Mach-O to bfd names. */
+
+static char *
+bfd_mach_o_convert_section_name_to_bfd (bfd *abfd, bfd_mach_o_section *section)
+{
+ const struct mach_o_segment_name_xlat *seg;
+ char *res;
+ unsigned int len;
+
+ for (seg = segsec_names_xlat; seg->segname; seg++)
+ {
+ if (strcmp (seg->segname, section->segname) == 0)
+ {
+ const struct mach_o_section_name_xlat *sec;
+
+ for (sec = seg->sections; sec->mach_o_name; sec++)
+ {
+ if (strcmp (sec->mach_o_name, section->sectname) == 0)
+ {
+ len = strlen (sec->bfd_name);
+ res = bfd_alloc (abfd, len + 1);
+
+ if (res == NULL)
+ return NULL;
+ strcpy (res, sec->bfd_name);
+ return res;
+ }
+ }
+ }
+ }
+
+ len = sizeof ("LC_SEGMENT") - 1 + 1
+ + strlen (section->segname) + 1
+ + strlen (section->sectname) + 1;
+
+ res = bfd_alloc (abfd, len);
+ if (res == NULL)
+ return NULL;
+ snprintf (res, len, "LC_SEGMENT.%s.%s", section->segname, section->sectname);
+ return res;
+}
+
+/* Convert a bfd sectio name to a Mach-O segment + section name. */
+
+static void
+bfd_mach_o_convert_section_name_to_mach_o (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sect,
+ bfd_mach_o_section *section)
+{
+ const struct mach_o_segment_name_xlat *seg;
+ const char *name = bfd_get_section_name (abfd, sect);
+ const char *dot;
+ unsigned int len;
+ unsigned int seglen;
+ unsigned int seclen;
+
+ /* List of well known names. */
+ for (seg = segsec_names_xlat; seg->segname; seg++)
+ {
+ const struct mach_o_section_name_xlat *sec;
+
+ for (sec = seg->sections; sec->mach_o_name; sec++)
+ {
+ if (strcmp (sec->bfd_name, name) == 0)
+ {
+ strcpy (section->segname, seg->segname);
+ strcpy (section->sectname, sec->mach_o_name);
+ return;
+ }
+ }
+ }
+
+ /* Strip LC_SEGMENT. prefix. */
+ if (strncmp (name, "LC_SEGMENT.", 11) == 0)
+ name += 11;
+
+ /* Find a dot. */
+ dot = strchr (name, '.');
+ len = strlen (name);
+
+ /* Try to split name into segment and section names. */
+ if (dot && dot != name)
+ {
+ seglen = dot - name;
+ seclen = len - (dot + 1 - name);
+
+ if (seglen < 16 && seclen < 16)
+ {
+ memcpy (section->segname, name, seglen);
+ section->segname[seglen] = 0;
+ memcpy (section->sectname, dot + 1, seclen);
+ section->sectname[seclen] = 0;
+ return;
+ }
+ }
+
+ if (len > 16)
+ len = 16;
+ memcpy (section->segname, name, len);
+ section->segname[len] = 0;
+ memcpy (section->sectname, name, len);
+ section->sectname[len] = 0;
}
/* Copy any private info we understand from the input symbol
to the output symbol. */
-static bfd_boolean
+bfd_boolean
bfd_mach_o_bfd_copy_private_symbol_data (bfd *ibfd ATTRIBUTE_UNUSED,
asymbol *isymbol ATTRIBUTE_UNUSED,
bfd *obfd ATTRIBUTE_UNUSED,
@@ -118,7 +231,7 @@ bfd_mach_o_bfd_copy_private_symbol_data (bfd *ibfd ATTRIBUTE_UNUSED,
/* Copy any private info we understand from the input section
to the output section. */
-static bfd_boolean
+bfd_boolean
bfd_mach_o_bfd_copy_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
asection *isection ATTRIBUTE_UNUSED,
bfd *obfd ATTRIBUTE_UNUSED,
@@ -130,17 +243,23 @@ bfd_mach_o_bfd_copy_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
/* Copy any private info we understand from the input bfd
to the output bfd. */
-static bfd_boolean
+bfd_boolean
bfd_mach_o_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
{
+ if (bfd_get_flavour (ibfd) != bfd_target_mach_o_flavour
+ || bfd_get_flavour (obfd) != bfd_target_mach_o_flavour)
+ return TRUE;
+
BFD_ASSERT (bfd_mach_o_valid (ibfd));
BFD_ASSERT (bfd_mach_o_valid (obfd));
- obfd->tdata.mach_o_data = ibfd->tdata.mach_o_data;
- obfd->tdata.mach_o_data->ibfd = ibfd;
+ /* FIXME: copy commands. */
+
return TRUE;
}
+/* Count the total number of symbols. Traverse all sections. */
+
static long
bfd_mach_o_count_symbols (bfd *abfd)
{
@@ -161,7 +280,7 @@ bfd_mach_o_count_symbols (bfd *abfd)
return nsyms;
}
-static long
+long
bfd_mach_o_get_symtab_upper_bound (bfd *abfd)
{
long nsyms = bfd_mach_o_count_symbols (abfd);
@@ -172,7 +291,7 @@ bfd_mach_o_get_symtab_upper_bound (bfd *abfd)
return ((nsyms + 1) * sizeof (asymbol *));
}
-static long
+long
bfd_mach_o_canonicalize_symtab (bfd *abfd, asymbol **alocation)
{
bfd_mach_o_data_struct *mdata = abfd->tdata.mach_o_data;
@@ -210,7 +329,7 @@ bfd_mach_o_canonicalize_symtab (bfd *abfd, asymbol **alocation)
return nsyms;
}
-static void
+void
bfd_mach_o_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
asymbol *symbol,
symbol_info *ret)
@@ -218,7 +337,7 @@ bfd_mach_o_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
bfd_symbol_info (symbol, ret);
}
-static void
+void
bfd_mach_o_print_symbol (bfd *abfd,
PTR afile,
asymbol *symbol,
@@ -319,13 +438,14 @@ bfd_mach_o_convert_architecture (bfd_mach_o_cpu_type mtype,
}
}
-static int
+static bfd_boolean
bfd_mach_o_write_header (bfd *abfd, bfd_mach_o_header *header)
{
unsigned char buf[32];
unsigned int size;
- size = (header->version == 2) ? 32 : 28;
+ size = (header->version == 2) ?
+ BFD_MACH_O_HEADER_64_SIZE : BFD_MACH_O_HEADER_SIZE;
bfd_h_put_32 (abfd, header->magic, buf + 0);
bfd_h_put_32 (abfd, header->cputype, buf + 4);
@@ -340,9 +460,9 @@ bfd_mach_o_write_header (bfd *abfd, bfd_mach_o_header *header)
bfd_seek (abfd, 0, SEEK_SET);
if (bfd_bwrite ((PTR) buf, size, abfd) != size)
- return -1;
+ return FALSE;
- return 0;
+ return TRUE;
}
static int
@@ -382,7 +502,7 @@ bfd_mach_o_scan_write_section_32 (bfd *abfd,
bfd_mach_o_section *section,
bfd_vma offset)
{
- unsigned char buf[68];
+ unsigned char buf[BFD_MACH_O_SECTION_SIZE];
memcpy (buf, section->sectname, 16);
memcpy (buf + 16, section->segname, 16);
@@ -397,7 +517,8 @@ bfd_mach_o_scan_write_section_32 (bfd *abfd,
bfd_h_put_32 (abfd, section->reserved2, buf + 64);
bfd_seek (abfd, offset, SEEK_SET);
- if (bfd_bwrite ((PTR) buf, 68, abfd) != 68)
+ if (bfd_bwrite ((PTR) buf, BFD_MACH_O_SECTION_SIZE, abfd)
+ != BFD_MACH_O_SECTION_SIZE)
return -1;
return 0;
@@ -408,7 +529,7 @@ bfd_mach_o_scan_write_section_64 (bfd *abfd,
bfd_mach_o_section *section,
bfd_vma offset)
{
- unsigned char buf[80];
+ unsigned char buf[BFD_MACH_O_SECTION_64_SIZE];
memcpy (buf, section->sectname, 16);
memcpy (buf + 16, section->segname, 16);
@@ -424,7 +545,8 @@ bfd_mach_o_scan_write_section_64 (bfd *abfd,
bfd_h_put_32 (abfd, section->reserved3, buf + 76);
bfd_seek (abfd, offset, SEEK_SET);
- if (bfd_bwrite ((PTR) buf, 80, abfd) != 80)
+ if (bfd_bwrite ((PTR) buf, BFD_MACH_O_SECTION_64_SIZE, abfd)
+ != BFD_MACH_O_SECTION_64_SIZE)
return -1;
return 0;
@@ -490,38 +612,15 @@ bfd_mach_o_scan_write_segment (bfd *abfd,
return -1;
}
- {
- char buf[1024];
- bfd_vma nbytes = seg->filesize;
- bfd_vma curoff = seg->fileoff;
-
- while (nbytes > 0)
- {
- bfd_vma thiswrite = nbytes;
-
- if (thiswrite > 1024)
- thiswrite = 1024;
-
- bfd_seek (abfd, curoff, SEEK_SET);
- if (bfd_bread ((PTR) buf, thiswrite, abfd) != thiswrite)
- return -1;
-
- bfd_seek (abfd, curoff, SEEK_SET);
- if (bfd_bwrite ((PTR) buf, thiswrite, abfd) != thiswrite)
- return -1;
-
- nbytes -= thiswrite;
- curoff += thiswrite;
- }
- }
-
for (i = 0; i < seg->nsects; i++)
{
bfd_vma segoff;
if (wide)
- segoff = command->offset + 64 + 8 + (i * 80);
+ segoff = command->offset + BFD_MACH_O_LC_SEGMENT_64_SIZE
+ + (i * BFD_MACH_O_SECTION_64_SIZE);
else
- segoff = command->offset + 48 + 8 + (i * 68);
+ segoff = command->offset + BFD_MACH_O_LC_SEGMENT_SIZE
+ + (i * BFD_MACH_O_SECTION_SIZE);
if (bfd_mach_o_scan_write_section
(abfd, &seg->sections[i], segoff, wide) != 0)
@@ -606,22 +705,14 @@ bfd_mach_o_scan_write_symtab (bfd *abfd, bfd_mach_o_load_command *command)
return 0;
}
-static bfd_boolean
+bfd_boolean
bfd_mach_o_write_contents (bfd *abfd)
{
unsigned int i;
- asection *s;
-
bfd_mach_o_data_struct *mdata = abfd->tdata.mach_o_data;
- /* Write data sections first in case they overlap header data to be
- written later. */
-
- for (s = abfd->sections; s != (asection *) NULL; s = s->next)
- ;
-
/* Now write header information. */
- if (bfd_mach_o_write_header (abfd, &mdata->header) != 0)
+ if (!bfd_mach_o_write_header (abfd, &mdata->header))
return FALSE;
for (i = 0; i < mdata->header.ncmds; i++)
@@ -630,7 +721,7 @@ bfd_mach_o_write_contents (bfd *abfd)
bfd_mach_o_load_command *cur = &mdata->commands[i];
unsigned long typeflag;
- typeflag = cur->type_required ? cur->type & BFD_MACH_O_LC_REQ_DYLD : cur->type;
+ typeflag = cur->type | (cur->type_required ? BFD_MACH_O_LC_REQ_DYLD : 0);
bfd_h_put_32 (abfd, typeflag, buf);
bfd_h_put_32 (abfd, cur->len, buf + 4);
@@ -686,7 +777,121 @@ bfd_mach_o_write_contents (bfd *abfd)
return TRUE;
}
-static int
+/* Build Mach-O load commands from the sections. */
+
+bfd_boolean
+bfd_mach_o_build_commands (bfd *abfd)
+{
+ bfd_mach_o_data_struct *mdata = bfd_get_mach_o_data (abfd);
+ unsigned int wide = (mdata->header.version == 2);
+ bfd_mach_o_segment_command *seg;
+ bfd_mach_o_section *sections;
+ asection *sec;
+ file_ptr filepos;
+
+ /* Return now if commands are already built. */
+ if (mdata->header.ncmds)
+ return FALSE;
+
+ /* Very simple version: 1 command (segment) containing all sections. */
+ mdata->header.ncmds = 1;
+ mdata->commands = bfd_alloc (abfd, mdata->header.ncmds
+ * sizeof (bfd_mach_o_load_command));
+ if (mdata->commands == NULL)
+ return FALSE;
+ seg = &mdata->commands[0].command.segment;
+ seg->nsects = bfd_count_sections (abfd);
+ sections = bfd_alloc (abfd, seg->nsects * sizeof (bfd_mach_o_section));
+ if (sections == NULL)
+ return FALSE;
+ seg->sections = sections;
+
+ /* Set segment command. */
+ if (wide)
+ {
+ mdata->commands[0].type = BFD_MACH_O_LC_SEGMENT_64;
+ mdata->commands[0].offset = BFD_MACH_O_HEADER_64_SIZE;
+ mdata->commands[0].len = BFD_MACH_O_LC_SEGMENT_64_SIZE
+ + BFD_MACH_O_SECTION_64_SIZE * seg->nsects;
+ }
+ else
+ {
+ mdata->commands[0].type = BFD_MACH_O_LC_SEGMENT;
+ mdata->commands[0].offset = BFD_MACH_O_HEADER_SIZE;
+ mdata->commands[0].len = BFD_MACH_O_LC_SEGMENT_SIZE
+ + BFD_MACH_O_SECTION_SIZE * seg->nsects;
+ }
+ mdata->commands[0].type_required = FALSE;
+ mdata->header.sizeofcmds = mdata->commands[0].len;
+
+ filepos = mdata->commands[0].offset + mdata->commands[0].len;
+
+ memset (seg->segname, 0, sizeof (seg->segname));
+ seg->vmaddr = 0;
+ seg->fileoff = filepos;
+ seg->filesize = 0;
+ seg->maxprot = BFD_MACH_O_PROT_READ | BFD_MACH_O_PROT_WRITE
+ | BFD_MACH_O_PROT_EXECUTE;
+ seg->initprot = seg->maxprot;
+ seg->flags = 0;
+
+ /* Create Mach-O sections. */
+ for (sec = abfd->sections; sec; sec = sec->next)
+ {
+ sections->bfdsection = sec;
+ bfd_mach_o_convert_section_name_to_mach_o (abfd, sec, sections);
+ sections->addr = bfd_get_section_vma (abfd, sec);
+ sections->size = bfd_get_section_size (sec);
+ sections->align = bfd_get_section_alignment (abfd, sec);
+
+ filepos = (filepos + ((file_ptr) 1 << sections->align) - 1)
+ & ((file_ptr) -1 << sections->align);
+ sections->offset = filepos;
+ sections->reloff = 0;
+ sections->nreloc = 0;
+ sections->reserved1 = 0;
+ sections->reserved2 = 0;
+ sections->reserved3 = 0;
+
+ sec->filepos = filepos;
+
+ filepos += sections->size;
+ sections++;
+ }
+ seg->filesize = filepos - seg->fileoff;
+ seg->vmsize = seg->filesize;
+
+ return TRUE;
+}
+
+/* Set the contents of a section. */
+
+bfd_boolean
+bfd_mach_o_set_section_contents (bfd *abfd,
+ asection *section,
+ const void * location,
+ file_ptr offset,
+ bfd_size_type count)
+{
+ file_ptr pos;
+
+ /* This must be done first, because bfd_set_section_contents is
+ going to set output_has_begun to TRUE. */
+ if (! abfd->output_has_begun && ! bfd_mach_o_build_commands (abfd))
+ return FALSE;
+
+ if (count == 0)
+ return TRUE;
+
+ pos = section->filepos + offset;
+ if (bfd_seek (abfd, pos, SEEK_SET) != 0
+ || bfd_bwrite (location, count, abfd) != count)
+ return FALSE;
+
+ return TRUE;
+}
+
+int
bfd_mach_o_sizeof_headers (bfd *a ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
@@ -696,7 +901,7 @@ bfd_mach_o_sizeof_headers (bfd *a ATTRIBUTE_UNUSED,
/* Make an empty symbol. This is required only because
bfd_make_section_anyway wants to create a symbol for the section. */
-static asymbol *
+asymbol *
bfd_mach_o_make_empty_symbol (bfd *abfd)
{
asymbol *new;
@@ -708,59 +913,59 @@ bfd_mach_o_make_empty_symbol (bfd *abfd)
return new;
}
-static int
+static bfd_boolean
bfd_mach_o_read_header (bfd *abfd, bfd_mach_o_header *header)
{
unsigned char buf[32];
unsigned int size;
bfd_vma (*get32) (const void *) = NULL;
- bfd_seek (abfd, 0, SEEK_SET);
-
/* Just read the magic number. */
+ bfd_seek (abfd, 0, SEEK_SET);
if (bfd_bread ((PTR) buf, 4, abfd) != 4)
- return -1;
+ return FALSE;
- if (bfd_getb32 (buf) == 0xfeedface)
+ if (bfd_getb32 (buf) == BFD_MACH_O_MH_MAGIC)
{
header->byteorder = BFD_ENDIAN_BIG;
- header->magic = 0xfeedface;
+ header->magic = BFD_MACH_O_MH_MAGIC;
header->version = 1;
get32 = bfd_getb32;
}
- else if (bfd_getl32 (buf) == 0xfeedface)
+ else if (bfd_getl32 (buf) == BFD_MACH_O_MH_MAGIC)
{
header->byteorder = BFD_ENDIAN_LITTLE;
- header->magic = 0xfeedface;
+ header->magic = BFD_MACH_O_MH_MAGIC;
header->version = 1;
get32 = bfd_getl32;
}
- else if (bfd_getb32 (buf) == 0xfeedfacf)
+ else if (bfd_getb32 (buf) == BFD_MACH_O_MH_MAGIC_64)
{
header->byteorder = BFD_ENDIAN_BIG;
- header->magic = 0xfeedfacf;
+ header->magic = BFD_MACH_O_MH_MAGIC_64;
header->version = 2;
get32 = bfd_getb32;
}
- else if (bfd_getl32 (buf) == 0xfeedfacf)
+ else if (bfd_getl32 (buf) == BFD_MACH_O_MH_MAGIC_64)
{
header->byteorder = BFD_ENDIAN_LITTLE;
- header->magic = 0xfeedfacf;
+ header->magic = BFD_MACH_O_MH_MAGIC_64;
header->version = 2;
get32 = bfd_getl32;
}
else
{
header->byteorder = BFD_ENDIAN_UNKNOWN;
- return -1;
+ return FALSE;
}
/* Once the size of the header is known, read the full header. */
- size = (header->version == 2) ? 32 : 28;
+ size = (header->version == 2) ?
+ BFD_MACH_O_HEADER_64_SIZE : BFD_MACH_O_HEADER_SIZE;
bfd_seek (abfd, 0, SEEK_SET);
if (bfd_bread ((PTR) buf, size, abfd) != size)
- return -1;
+ return FALSE;
header->cputype = (*get32) (buf + 4);
header->cpusubtype = (*get32) (buf + 8);
@@ -772,7 +977,7 @@ bfd_mach_o_read_header (bfd *abfd, bfd_mach_o_header *header)
if (header->version == 2)
header->reserved = (*get32) (buf + 28);
- return 0;
+ return TRUE;
}
static asection *
@@ -781,41 +986,12 @@ bfd_mach_o_make_bfd_section (bfd *abfd, bfd_mach_o_section *section,
{
asection *bfdsec;
char *sname;
- const char *prefix = "LC_SEGMENT";
- unsigned int snamelen;
flagword flags;
- snamelen = strlen (prefix) + 1
- + strlen (section->segname) + 1
- + strlen (section->sectname) + 1;
-
- sname = bfd_alloc (abfd, snamelen);
+ sname = bfd_mach_o_convert_section_name_to_bfd (abfd, section);
if (sname == NULL)
return NULL;
- /* Use canonical dwarf section names for dwarf sections. */
- if (strcmp (section->segname, "__DWARF") == 0
- && strncmp (section->sectname, "__", 2) == 0)
- sprintf (sname, ".%s", section->sectname + 2);
- else if (strcmp (section->segname, "__TEXT") == 0)
- {
- if (strcmp (section->sectname, "__eh_frame") == 0)
- strcpy (sname, ".eh_frame");
- else if (section->sectname[0])
- sprintf (sname, "%s.%s", section->segname, section->sectname);
- else
- strcpy (sname, section->segname);
- }
- else if (strcmp (section->segname, "__DATA") == 0)
- {
- if (section->sectname[0])
- sprintf (sname, "%s.%s", section->segname, section->sectname);
- else
- strcpy (sname, section->segname);
- }
- else
- sprintf (sname, "%s.%s.%s", prefix, section->segname, section->sectname);
-
if (section->flags & BFD_MACH_O_S_ATTR_DEBUG)
flags = SEC_HAS_CONTENTS | SEC_DEBUGGING;
else
@@ -853,10 +1029,11 @@ bfd_mach_o_scan_read_section_32 (bfd *abfd,
bfd_vma offset,
unsigned long prot)
{
- unsigned char buf[68];
+ unsigned char buf[BFD_MACH_O_SECTION_SIZE];
bfd_seek (abfd, offset, SEEK_SET);
- if (bfd_bread ((PTR) buf, 68, abfd) != 68)
+ if (bfd_bread ((PTR) buf, BFD_MACH_O_SECTION_SIZE, abfd)
+ != BFD_MACH_O_SECTION_SIZE)
return -1;
memcpy (section->sectname, buf, 16);
@@ -887,10 +1064,11 @@ bfd_mach_o_scan_read_section_64 (bfd *abfd,
bfd_vma offset,
unsigned long prot)
{
- unsigned char buf[80];
+ unsigned char buf[BFD_MACH_O_SECTION_64_SIZE];
bfd_seek (abfd, offset, SEEK_SET);
- if (bfd_bread ((PTR) buf, 80, abfd) != 80)
+ if (bfd_bread ((PTR) buf, BFD_MACH_O_SECTION_64_SIZE, abfd)
+ != BFD_MACH_O_SECTION_64_SIZE)
return -1;
memcpy (section->sectname, buf, 16);
@@ -1551,10 +1729,6 @@ bfd_mach_o_scan_read_segment (bfd *abfd,
unsigned char buf[64];
bfd_mach_o_segment_command *seg = &command->command.segment;
unsigned long i;
- asection *bfdsec;
- char *sname;
- const char *prefix = "LC_SEGMENT";
- unsigned int snamelen;
if (wide)
{
@@ -1597,45 +1771,22 @@ bfd_mach_o_scan_read_segment (bfd *abfd,
seg->flags = bfd_h_get_32 (abfd, buf + 44);
}
- snamelen = strlen (prefix) + 1 + strlen (seg->segname) + 1;
- sname = bfd_alloc (abfd, snamelen);
- if (sname == NULL)
- return -1;
- if (strcmp (seg->segname, "__TEXT") == 0
- || strcmp (seg->segname, "__DATA") == 0
- || strcmp (seg->segname, "__IMPORT") == 0
- || strcmp (seg->segname, "__LINKEDIT") == 0)
- strcpy (sname, seg->segname);
- else
- sprintf (sname, "%s.%s", prefix, seg->segname);
-
- bfdsec = bfd_make_section_anyway (abfd, sname);
- if (bfdsec == NULL)
- return -1;
-
- bfdsec->vma = seg->vmaddr;
- bfdsec->lma = seg->vmaddr;
- bfdsec->size = seg->filesize;
- bfdsec->filepos = seg->fileoff;
- bfdsec->alignment_power = 0x0;
- bfdsec->flags = SEC_HAS_CONTENTS;
- bfdsec->segment_mark = 1;
-
- seg->segment = bfdsec;
-
if (seg->nsects != 0)
{
- seg->sections = bfd_alloc (abfd, seg->nsects * sizeof (bfd_mach_o_section));
+ seg->sections = bfd_alloc (abfd, seg->nsects
+ * sizeof (bfd_mach_o_section));
if (seg->sections == NULL)
return -1;
for (i = 0; i < seg->nsects; i++)
{
bfd_vma segoff;
- if (wide)
- segoff = command->offset + 64 + 8 + (i * 80);
- else
- segoff = command->offset + 48 + 8 + (i * 68);
+ if (wide)
+ segoff = command->offset + BFD_MACH_O_LC_SEGMENT_64_SIZE
+ + (i * BFD_MACH_O_SECTION_64_SIZE);
+ else
+ segoff = command->offset + BFD_MACH_O_LC_SEGMENT_SIZE
+ + (i * BFD_MACH_O_SECTION_SIZE);
if (bfd_mach_o_scan_read_section
(abfd, &seg->sections[i], segoff, seg->initprot, wide) != 0)
@@ -1667,9 +1818,9 @@ bfd_mach_o_scan_read_command (bfd *abfd, bfd_mach_o_load_command *command)
if (bfd_bread ((PTR) buf, 8, abfd) != 8)
return -1;
- command->type = (bfd_h_get_32 (abfd, buf) & ~BFD_MACH_O_LC_REQ_DYLD);
+ command->type = bfd_h_get_32 (abfd, buf) & ~BFD_MACH_O_LC_REQ_DYLD;
command->type_required = (bfd_h_get_32 (abfd, buf) & BFD_MACH_O_LC_REQ_DYLD
- ? 1 : 0);
+ ? TRUE : FALSE);
command->len = bfd_h_get_32 (abfd, buf + 4);
switch (command->type)
@@ -1876,12 +2027,13 @@ bfd_mach_o_scan (bfd *abfd,
unsigned long cpusubtype;
unsigned int hdrsize;
- hdrsize = (header->version == 2) ? 32 : 28;
+ hdrsize = (header->version == 2) ?
+ BFD_MACH_O_HEADER_64_SIZE : BFD_MACH_O_HEADER_SIZE;
mdata->header = *header;
mdata->symbols = NULL;
- abfd->flags = abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS);
+ abfd->flags = abfd->flags & BFD_IN_MEMORY;
switch (header->filetype)
{
case BFD_MACH_O_MH_OBJECT:
@@ -1940,7 +2092,7 @@ bfd_mach_o_scan (bfd *abfd,
}
bfd_boolean
-bfd_mach_o_mkobject (bfd *abfd)
+bfd_mach_o_mkobject_init (bfd *abfd)
{
bfd_mach_o_data_struct *mdata = NULL;
@@ -1968,13 +2120,15 @@ bfd_mach_o_mkobject (bfd *abfd)
}
const bfd_target *
-bfd_mach_o_object_p (bfd *abfd)
+bfd_mach_o_header_p (bfd *abfd,
+ bfd_mach_o_filetype filetype,
+ bfd_mach_o_cpu_type cputype)
{
struct bfd_preserve preserve;
bfd_mach_o_header header;
preserve.marker = NULL;
- if (bfd_mach_o_read_header (abfd, &header) != 0)
+ if (!bfd_mach_o_read_header (abfd, &header))
goto wrong;
if (! (header.byteorder == BFD_ENDIAN_BIG
@@ -1993,6 +2147,42 @@ bfd_mach_o_object_p (bfd *abfd)
&& abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE)))
goto wrong;
+ /* Check cputype and filetype.
+ In case of wildcard, do not accept magics that are handled by existing
+ targets. */
+ if (cputype)
+ {
+ if (header.cputype != cputype)
+ goto wrong;
+ }
+ else
+ {
+ switch (header.cputype)
+ {
+ case BFD_MACH_O_CPU_TYPE_I386:
+ /* Handled by mach-o-i386 */
+ goto wrong;
+ default:
+ break;
+ }
+ }
+ if (filetype)
+ {
+ if (header.filetype != filetype)
+ goto wrong;
+ }
+ else
+ {
+ switch (header.filetype)
+ {
+ case BFD_MACH_O_MH_CORE:
+ /* Handled by core_p */
+ goto wrong;
+ default:
+ break;
+ }
+ }
+
preserve.marker = bfd_zalloc (abfd, sizeof (bfd_mach_o_data_struct));
if (preserve.marker == NULL
|| !bfd_preserve_save (abfd, &preserve))
@@ -2014,54 +2204,16 @@ bfd_mach_o_object_p (bfd *abfd)
return NULL;
}
-const bfd_target *
-bfd_mach_o_core_p (bfd *abfd)
+static const bfd_target *
+bfd_mach_o_gen_object_p (bfd *abfd)
{
- struct bfd_preserve preserve;
- bfd_mach_o_header header;
-
- preserve.marker = NULL;
- if (bfd_mach_o_read_header (abfd, &header) != 0)
- goto wrong;
-
- if (! (header.byteorder == BFD_ENDIAN_BIG
- || header.byteorder == BFD_ENDIAN_LITTLE))
- {
- fprintf (stderr, "unknown header byte-order value 0x%lx\n",
- (unsigned long) header.byteorder);
- abort ();
- }
-
- if (! ((header.byteorder == BFD_ENDIAN_BIG
- && abfd->xvec->byteorder == BFD_ENDIAN_BIG
- && abfd->xvec->header_byteorder == BFD_ENDIAN_BIG)
- || (header.byteorder == BFD_ENDIAN_LITTLE
- && abfd->xvec->byteorder == BFD_ENDIAN_LITTLE
- && abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE)))
- goto wrong;
-
- if (header.filetype != BFD_MACH_O_MH_CORE)
- goto wrong;
-
- preserve.marker = bfd_zalloc (abfd, sizeof (bfd_mach_o_data_struct));
- if (preserve.marker == NULL
- || !bfd_preserve_save (abfd, &preserve))
- goto fail;
-
- if (bfd_mach_o_scan (abfd, &header,
- (bfd_mach_o_data_struct *) preserve.marker) != 0)
- goto wrong;
-
- bfd_preserve_finish (abfd, &preserve);
- return abfd->xvec;
-
- wrong:
- bfd_set_error (bfd_error_wrong_format);
+ return bfd_mach_o_header_p (abfd, 0, 0);
+}
- fail:
- if (preserve.marker != NULL)
- bfd_preserve_restore (abfd, &preserve);
- return NULL;
+static const bfd_target *
+bfd_mach_o_gen_core_p (bfd *abfd)
+{
+ return bfd_mach_o_header_p (abfd, BFD_MACH_O_MH_CORE, 0);
}
typedef struct mach_o_fat_archentry
@@ -2370,7 +2522,7 @@ bfd_mach_o_stack_addr (enum bfd_mach_o_cpu_type type)
}
}
-static bfd_boolean
+bfd_boolean
bfd_mach_o_bfd_print_private_bfd_data (bfd *abfd, PTR ptr)
{
bfd_mach_o_data_struct *mdata = abfd->tdata.mach_o_data;
diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index 615a4b3..756fda5 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -1,5 +1,5 @@
/* Mach-O support for BFD.
- Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2007, 2008
+ Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
@@ -40,6 +40,15 @@
#define BFD_MACH_O_SYM_NSECT(SYM) (((SYM)->udata.i >> 16) & 0xff)
#define BFD_MACH_O_SYM_NDESC(SYM) ((SYM)->udata.i & 0xffff)
+typedef enum bfd_mach_o_mach_header_magic
+{
+ BFD_MACH_O_MH_MAGIC = 0xfeedface,
+ BFD_MACH_O_MH_CIGAM = 0xcefaedfe,
+ BFD_MACH_O_MH_MAGIC_64 = 0xfeedfacf,
+ BFD_MACH_O_MH_CIGAM_64 = 0xcffaedfe
+}
+bfd_mach_o_mach_header_magic;
+
typedef enum bfd_mach_o_ppc_thread_flavour
{
BFD_MACH_O_PPC_THREAD_STATE = 1,
@@ -134,6 +143,12 @@ typedef enum bfd_mach_o_cpu_type
}
bfd_mach_o_cpu_type;
+typedef enum bfd_mach_o_cpu_subtype
+{
+ BFD_MACH_O_CPU_SUBTYPE_X86_ALL = 3
+}
+bfd_mach_o_cpu_subtype;
+
typedef enum bfd_mach_o_filetype
{
BFD_MACH_O_MH_OBJECT = 1,
@@ -225,8 +240,6 @@ bfd_mach_o_section_type;
/* Section contains only true machine instructions. */
#define BFD_MACH_O_S_ATTR_PURE_INSTRUCTIONS 0x80000000
-typedef unsigned long bfd_mach_o_cpu_subtype;
-
typedef struct bfd_mach_o_header
{
unsigned long magic;
@@ -243,6 +256,9 @@ typedef struct bfd_mach_o_header
}
bfd_mach_o_header;
+#define BFD_MACH_O_HEADER_SIZE 28
+#define BFD_MACH_O_HEADER_64_SIZE 32
+
typedef struct bfd_mach_o_section
{
asection *bfdsection;
@@ -260,6 +276,8 @@ typedef struct bfd_mach_o_section
unsigned long reserved3;
}
bfd_mach_o_section;
+#define BFD_MACH_O_SECTION_SIZE 68
+#define BFD_MACH_O_SECTION_64_SIZE 80
typedef struct bfd_mach_o_segment_command
{
@@ -276,6 +294,8 @@ typedef struct bfd_mach_o_segment_command
asection *segment;
}
bfd_mach_o_segment_command;
+#define BFD_MACH_O_LC_SEGMENT_SIZE 56
+#define BFD_MACH_O_LC_SEGMENT_64_SIZE 72
/* Protection flags. */
#define BFD_MACH_O_PROT_READ 0x01
@@ -506,7 +526,7 @@ bfd_mach_o_uuid_command;
typedef struct bfd_mach_o_load_command
{
bfd_mach_o_load_command_type type;
- unsigned int type_required;
+ bfd_boolean type_required;
bfd_vma offset;
bfd_vma len;
union
@@ -540,26 +560,44 @@ mach_o_data_struct;
typedef struct mach_o_data_struct bfd_mach_o_data_struct;
-bfd_boolean bfd_mach_o_valid (bfd *);
-int bfd_mach_o_scan_read_symtab_symbol (bfd *, bfd_mach_o_symtab_command *, asymbol *, unsigned long);
-int bfd_mach_o_scan_read_symtab_strtab (bfd *, bfd_mach_o_symtab_command *);
-int bfd_mach_o_scan_read_symtab_symbols (bfd *, bfd_mach_o_symtab_command *);
-int bfd_mach_o_scan_read_dysymtab_symbol (bfd *, bfd_mach_o_dysymtab_command *, bfd_mach_o_symtab_command *, asymbol *, unsigned long);
-int bfd_mach_o_scan_start_address (bfd *);
-int bfd_mach_o_scan (bfd *, bfd_mach_o_header *, bfd_mach_o_data_struct *);
-bfd_boolean bfd_mach_o_mkobject (bfd *);
-const bfd_target * bfd_mach_o_object_p (bfd *);
-const bfd_target * bfd_mach_o_core_p (bfd *);
-const bfd_target * bfd_mach_o_archive_p (bfd *);
-bfd * bfd_mach_o_openr_next_archived_file (bfd *, bfd *);
-int bfd_mach_o_lookup_section (bfd *, asection *, bfd_mach_o_load_command **, bfd_mach_o_section **);
-int bfd_mach_o_lookup_command (bfd *, bfd_mach_o_load_command_type, bfd_mach_o_load_command **);
-unsigned long bfd_mach_o_stack_addr (enum bfd_mach_o_cpu_type);
-int bfd_mach_o_core_fetch_environment (bfd *, unsigned char **, unsigned int *);
-char * bfd_mach_o_core_file_failing_command (bfd *);
-int bfd_mach_o_core_file_failing_signal (bfd *);
-bfd_boolean bfd_mach_o_core_file_matches_executable_p (bfd *, bfd *);
+bfd_boolean bfd_mach_o_valid (bfd *);
+int bfd_mach_o_scan_read_symtab_symbol (bfd *, bfd_mach_o_symtab_command *, asymbol *, unsigned long);
+int bfd_mach_o_scan_read_symtab_strtab (bfd *, bfd_mach_o_symtab_command *);
+int bfd_mach_o_scan_read_symtab_symbols (bfd *, bfd_mach_o_symtab_command *);
+int bfd_mach_o_scan_read_dysymtab_symbol (bfd *, bfd_mach_o_dysymtab_command *, bfd_mach_o_symtab_command *, asymbol *, unsigned long);
+int bfd_mach_o_scan_start_address (bfd *);
+int bfd_mach_o_scan (bfd *, bfd_mach_o_header *, bfd_mach_o_data_struct *);
+bfd_boolean bfd_mach_o_mkobject_init (bfd *);
+const bfd_target *bfd_mach_o_object_p (bfd *);
+const bfd_target *bfd_mach_o_core_p (bfd *);
+const bfd_target *bfd_mach_o_archive_p (bfd *);
+bfd *bfd_mach_o_openr_next_archived_file (bfd *, bfd *);
+int bfd_mach_o_lookup_section (bfd *, asection *, bfd_mach_o_load_command **, bfd_mach_o_section **);
+int bfd_mach_o_lookup_command (bfd *, bfd_mach_o_load_command_type, bfd_mach_o_load_command **);
+bfd_boolean bfd_mach_o_write_contents (bfd *);
+bfd_boolean bfd_mach_o_bfd_copy_private_symbol_data (bfd *, asymbol *,
+ bfd *, asymbol *);
+bfd_boolean bfd_mach_o_bfd_copy_private_section_data (bfd *, asection *,
+ bfd *, asection *);
+bfd_boolean bfd_mach_o_bfd_copy_private_bfd_data (bfd *, bfd *);
+long bfd_mach_o_get_symtab_upper_bound (bfd *);
+long bfd_mach_o_canonicalize_symtab (bfd *, asymbol **);
+asymbol *bfd_mach_o_make_empty_symbol (bfd *);
+void bfd_mach_o_get_symbol_info (bfd *, asymbol *, symbol_info *);
+void bfd_mach_o_print_symbol (bfd *, PTR, asymbol *, bfd_print_symbol_type);
+bfd_boolean bfd_mach_o_bfd_print_private_bfd_data (bfd *, PTR);
+int bfd_mach_o_sizeof_headers (bfd *, struct bfd_link_info *);
+unsigned long bfd_mach_o_stack_addr (enum bfd_mach_o_cpu_type);
+int bfd_mach_o_core_fetch_environment (bfd *, unsigned char **, unsigned int *);
+char *bfd_mach_o_core_file_failing_command (bfd *);
+int bfd_mach_o_core_file_failing_signal (bfd *);
+bfd_boolean bfd_mach_o_core_file_matches_executable_p (bfd *, bfd *);
bfd *bfd_mach_o_fat_extract (bfd *, bfd_format , const bfd_arch_info_type *);
+const bfd_target *bfd_mach_o_header_p (bfd *, bfd_mach_o_filetype,
+ bfd_mach_o_cpu_type);
+bfd_boolean bfd_mach_o_build_commands (bfd *abfd);
+bfd_boolean bfd_mach_o_set_section_contents (bfd *, asection *, const void *,
+ file_ptr, bfd_size_type);
extern const bfd_target mach_o_be_vec;
extern const bfd_target mach_o_le_vec;
diff --git a/bfd/targets.c b/bfd/targets.c
index 49aa5f1..ba56a44 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -747,6 +747,7 @@ extern const bfd_target m88kopenbsd_vec;
extern const bfd_target mach_o_be_vec;
extern const bfd_target mach_o_le_vec;
extern const bfd_target mach_o_fat_vec;
+extern const bfd_target mach_o_i386_vec;
extern const bfd_target maxqcoff_vec;
extern const bfd_target mcore_pe_big_vec;
extern const bfd_target mcore_pe_little_vec;
@@ -1115,6 +1116,7 @@ static const bfd_target * const _bfd_target_vector[] =
&mach_o_be_vec,
&mach_o_le_vec,
&mach_o_fat_vec,
+ &mach_o_i386_vec,
&maxqcoff_vec,
&mcore_pe_big_vec,
&mcore_pe_little_vec,
'n2885' href='#n2885'>2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074
/* Intel 386 target-dependent stuff.

   Copyright (C) 1988-2017 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 "opcode/i386.h"
#include "arch-utils.h"
#include "command.h"
#include "dummy-frame.h"
#include "dwarf2-frame.h"
#include "frame.h"
#include "frame-base.h"
#include "frame-unwind.h"
#include "inferior.h"
#include "infrun.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdbtypes.h"
#include "objfiles.h"
#include "osabi.h"
#include "regcache.h"
#include "reggroups.h"
#include "regset.h"
#include "symfile.h"
#include "symtab.h"
#include "target.h"
#include "target-float.h"
#include "value.h"
#include "dis-asm.h"
#include "disasm.h"
#include "remote.h"
#include "i386-tdep.h"
#include "i387-tdep.h"
#include "x86-xstate.h"

#include "record.h"
#include "record-full.h"
#include "target-descriptions.h"
#include "arch/i386.h"

#include "ax.h"
#include "ax-gdb.h"

#include "stap-probe.h"
#include "user-regs.h"
#include "cli/cli-utils.h"
#include "expression.h"
#include "parser-defs.h"
#include <ctype.h>
#include <algorithm>

/* Register names.  */

static const char *i386_register_names[] =
{
  "eax",   "ecx",    "edx",   "ebx",
  "esp",   "ebp",    "esi",   "edi",
  "eip",   "eflags", "cs",    "ss",
  "ds",    "es",     "fs",    "gs",
  "st0",   "st1",    "st2",   "st3",
  "st4",   "st5",    "st6",   "st7",
  "fctrl", "fstat",  "ftag",  "fiseg",
  "fioff", "foseg",  "fooff", "fop",
  "xmm0",  "xmm1",   "xmm2",  "xmm3",
  "xmm4",  "xmm5",   "xmm6",  "xmm7",
  "mxcsr"
};

static const char *i386_zmm_names[] =
{
  "zmm0",  "zmm1",   "zmm2",  "zmm3",
  "zmm4",  "zmm5",   "zmm6",  "zmm7"
};

static const char *i386_zmmh_names[] =
{
  "zmm0h",  "zmm1h",   "zmm2h",  "zmm3h",
  "zmm4h",  "zmm5h",   "zmm6h",  "zmm7h"
};

static const char *i386_k_names[] =
{
  "k0",  "k1",   "k2",  "k3",
  "k4",  "k5",   "k6",  "k7"
};

static const char *i386_ymm_names[] =
{
  "ymm0",  "ymm1",   "ymm2",  "ymm3",
  "ymm4",  "ymm5",   "ymm6",  "ymm7",
};

static const char *i386_ymmh_names[] =
{
  "ymm0h",  "ymm1h",   "ymm2h",  "ymm3h",
  "ymm4h",  "ymm5h",   "ymm6h",  "ymm7h",
};

static const char *i386_mpx_names[] =
{
  "bnd0raw", "bnd1raw", "bnd2raw", "bnd3raw", "bndcfgu", "bndstatus"
};

static const char* i386_pkeys_names[] =
{
  "pkru"
};

/* Register names for MPX pseudo-registers.  */

static const char *i386_bnd_names[] =
{
  "bnd0", "bnd1", "bnd2", "bnd3"
};

/* Register names for MMX pseudo-registers.  */

static const char *i386_mmx_names[] =
{
  "mm0", "mm1", "mm2", "mm3",
  "mm4", "mm5", "mm6", "mm7"
};

/* Register names for byte pseudo-registers.  */

static const char *i386_byte_names[] =
{
  "al", "cl", "dl", "bl", 
  "ah", "ch", "dh", "bh"
};

/* Register names for word pseudo-registers.  */

static const char *i386_word_names[] =
{
  "ax", "cx", "dx", "bx",
  "", "bp", "si", "di"
};

/* Constant used for reading/writing pseudo registers.  In 64-bit mode, we have
   16 lower ZMM regs that extend corresponding xmm/ymm registers.  In addition,
   we have 16 upper ZMM regs that have to be handled differently.  */

const int num_lower_zmm_regs = 16;

/* MMX register?  */

static int
i386_mmx_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int mm0_regnum = tdep->mm0_regnum;

  if (mm0_regnum < 0)
    return 0;

  regnum -= mm0_regnum;
  return regnum >= 0 && regnum < tdep->num_mmx_regs;
}

/* Byte register?  */

int
i386_byte_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  regnum -= tdep->al_regnum;
  return regnum >= 0 && regnum < tdep->num_byte_regs;
}

/* Word register?  */

int
i386_word_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  regnum -= tdep->ax_regnum;
  return regnum >= 0 && regnum < tdep->num_word_regs;
}

/* Dword register?  */

int
i386_dword_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int eax_regnum = tdep->eax_regnum;

  if (eax_regnum < 0)
    return 0;

  regnum -= eax_regnum;
  return regnum >= 0 && regnum < tdep->num_dword_regs;
}

/* AVX512 register?  */

int
i386_zmmh_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int zmm0h_regnum = tdep->zmm0h_regnum;

  if (zmm0h_regnum < 0)
    return 0;

  regnum -= zmm0h_regnum;
  return regnum >= 0 && regnum < tdep->num_zmm_regs;
}

int
i386_zmm_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int zmm0_regnum = tdep->zmm0_regnum;

  if (zmm0_regnum < 0)
    return 0;

  regnum -= zmm0_regnum;
  return regnum >= 0 && regnum < tdep->num_zmm_regs;
}

int
i386_k_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int k0_regnum = tdep->k0_regnum;

  if (k0_regnum < 0)
    return 0;

  regnum -= k0_regnum;
  return regnum >= 0 && regnum < I387_NUM_K_REGS;
}

static int
i386_ymmh_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int ymm0h_regnum = tdep->ymm0h_regnum;

  if (ymm0h_regnum < 0)
    return 0;

  regnum -= ymm0h_regnum;
  return regnum >= 0 && regnum < tdep->num_ymm_regs;
}

/* AVX register?  */

int
i386_ymm_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int ymm0_regnum = tdep->ymm0_regnum;

  if (ymm0_regnum < 0)
    return 0;

  regnum -= ymm0_regnum;
  return regnum >= 0 && regnum < tdep->num_ymm_regs;
}

static int
i386_ymmh_avx512_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int ymm16h_regnum = tdep->ymm16h_regnum;

  if (ymm16h_regnum < 0)
    return 0;

  regnum -= ymm16h_regnum;
  return regnum >= 0 && regnum < tdep->num_ymm_avx512_regs;
}

int
i386_ymm_avx512_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int ymm16_regnum = tdep->ymm16_regnum;

  if (ymm16_regnum < 0)
    return 0;

  regnum -= ymm16_regnum;
  return regnum >= 0 && regnum < tdep->num_ymm_avx512_regs;
}

/* BND register?  */

int
i386_bnd_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int bnd0_regnum = tdep->bnd0_regnum;

  if (bnd0_regnum < 0)
    return 0;

  regnum -= bnd0_regnum;
  return regnum >= 0 && regnum < I387_NUM_BND_REGS;
}

/* SSE register?  */

int
i386_xmm_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int num_xmm_regs = I387_NUM_XMM_REGS (tdep);

  if (num_xmm_regs == 0)
    return 0;

  regnum -= I387_XMM0_REGNUM (tdep);
  return regnum >= 0 && regnum < num_xmm_regs;
}

/* XMM_512 register?  */

int
i386_xmm_avx512_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int num_xmm_avx512_regs = I387_NUM_XMM_AVX512_REGS (tdep);

  if (num_xmm_avx512_regs == 0)
    return 0;

  regnum -= I387_XMM16_REGNUM (tdep);
  return regnum >= 0 && regnum < num_xmm_avx512_regs;
}

static int
i386_mxcsr_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  if (I387_NUM_XMM_REGS (tdep) == 0)
    return 0;

  return (regnum == I387_MXCSR_REGNUM (tdep));
}

/* FP register?  */

int
i386_fp_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  if (I387_ST0_REGNUM (tdep) < 0)
    return 0;

  return (I387_ST0_REGNUM (tdep) <= regnum
	  && regnum < I387_FCTRL_REGNUM (tdep));
}

int
i386_fpc_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  if (I387_ST0_REGNUM (tdep) < 0)
    return 0;

  return (I387_FCTRL_REGNUM (tdep) <= regnum 
	  && regnum < I387_XMM0_REGNUM (tdep));
}

/* BNDr (raw) register?  */

static int
i386_bndr_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

   if (I387_BND0R_REGNUM (tdep) < 0)
     return 0;

  regnum -= tdep->bnd0r_regnum;
  return regnum >= 0 && regnum < I387_NUM_BND_REGS;
}

/* BND control register?  */

static int
i386_mpx_ctrl_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

   if (I387_BNDCFGU_REGNUM (tdep) < 0)
     return 0;

  regnum -= I387_BNDCFGU_REGNUM (tdep);
  return regnum >= 0 && regnum < I387_NUM_MPX_CTRL_REGS;
}

/* PKRU register?  */

bool
i386_pkru_regnum_p (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int pkru_regnum = tdep->pkru_regnum;

  if (pkru_regnum < 0)
    return false;

  regnum -= pkru_regnum;
  return regnum >= 0 && regnum < I387_NUM_PKEYS_REGS;
}

/* Return the name of register REGNUM, or the empty string if it is
   an anonymous register.  */

static const char *
i386_register_name (struct gdbarch *gdbarch, int regnum)
{
  /* Hide the upper YMM registers.  */
  if (i386_ymmh_regnum_p (gdbarch, regnum))
    return "";

  /* Hide the upper YMM16-31 registers.  */
  if (i386_ymmh_avx512_regnum_p (gdbarch, regnum))
    return "";

  /* Hide the upper ZMM registers.  */
  if (i386_zmmh_regnum_p (gdbarch, regnum))
    return "";

  return tdesc_register_name (gdbarch, regnum);
}

/* Return the name of register REGNUM.  */

const char *
i386_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  if (i386_bnd_regnum_p (gdbarch, regnum))
    return i386_bnd_names[regnum - tdep->bnd0_regnum];
  if (i386_mmx_regnum_p (gdbarch, regnum))
    return i386_mmx_names[regnum - I387_MM0_REGNUM (tdep)];
  else if (i386_ymm_regnum_p (gdbarch, regnum))
    return i386_ymm_names[regnum - tdep->ymm0_regnum];
  else if (i386_zmm_regnum_p (gdbarch, regnum))
    return i386_zmm_names[regnum - tdep->zmm0_regnum];
  else if (i386_byte_regnum_p (gdbarch, regnum))
    return i386_byte_names[regnum - tdep->al_regnum];
  else if (i386_word_regnum_p (gdbarch, regnum))
    return i386_word_names[regnum - tdep->ax_regnum];

  internal_error (__FILE__, __LINE__, _("invalid regnum"));
}

/* Convert a dbx register number REG to the appropriate register
   number used by GDB.  */

static int
i386_dbx_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  /* This implements what GCC calls the "default" register map
     (dbx_register_map[]).  */

  if (reg >= 0 && reg <= 7)
    {
      /* General-purpose registers.  The debug info calls %ebp
         register 4, and %esp register 5.  */
      if (reg == 4)
        return 5;
      else if (reg == 5)
        return 4;
      else return reg;
    }
  else if (reg >= 12 && reg <= 19)
    {
      /* Floating-point registers.  */
      return reg - 12 + I387_ST0_REGNUM (tdep);
    }
  else if (reg >= 21 && reg <= 28)
    {
      /* SSE registers.  */
      int ymm0_regnum = tdep->ymm0_regnum;

      if (ymm0_regnum >= 0
	  && i386_xmm_regnum_p (gdbarch, reg))
	return reg - 21 + ymm0_regnum;
      else
	return reg - 21 + I387_XMM0_REGNUM (tdep);
    }
  else if (reg >= 29 && reg <= 36)
    {
      /* MMX registers.  */
      return reg - 29 + I387_MM0_REGNUM (tdep);
    }

  /* This will hopefully provoke a warning.  */
  return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
}

/* Convert SVR4 DWARF register number REG to the appropriate register number
   used by GDB.  */

static int
i386_svr4_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  /* This implements the GCC register map that tries to be compatible
     with the SVR4 C compiler for DWARF (svr4_dbx_register_map[]).  */

  /* The SVR4 register numbering includes %eip and %eflags, and
     numbers the floating point registers differently.  */
  if (reg >= 0 && reg <= 9)
    {
      /* General-purpose registers.  */
      return reg;
    }
  else if (reg >= 11 && reg <= 18)
    {
      /* Floating-point registers.  */
      return reg - 11 + I387_ST0_REGNUM (tdep);
    }
  else if (reg >= 21 && reg <= 36)
    {
      /* The SSE and MMX registers have the same numbers as with dbx.  */
      return i386_dbx_reg_to_regnum (gdbarch, reg);
    }

  switch (reg)
    {
    case 37: return I387_FCTRL_REGNUM (tdep);
    case 38: return I387_FSTAT_REGNUM (tdep);
    case 39: return I387_MXCSR_REGNUM (tdep);
    case 40: return I386_ES_REGNUM;
    case 41: return I386_CS_REGNUM;
    case 42: return I386_SS_REGNUM;
    case 43: return I386_DS_REGNUM;
    case 44: return I386_FS_REGNUM;
    case 45: return I386_GS_REGNUM;
    }

  return -1;
}

/* Wrapper on i386_svr4_dwarf_reg_to_regnum to return
   num_regs + num_pseudo_regs for other debug formats.  */

int
i386_svr4_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
  int regnum = i386_svr4_dwarf_reg_to_regnum (gdbarch, reg);

  if (regnum == -1)
    return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
  return regnum;
}



/* This is the variable that is set with "set disassembly-flavor", and
   its legitimate values.  */
static const char att_flavor[] = "att";
static const char intel_flavor[] = "intel";
static const char *const valid_flavors[] =
{
  att_flavor,
  intel_flavor,
  NULL
};
static const char *disassembly_flavor = att_flavor;


/* Use the program counter to determine the contents and size of a
   breakpoint instruction.  Return a pointer to a string of bytes that
   encode a breakpoint instruction, store the length of the string in
   *LEN and optionally adjust *PC to point to the correct memory
   location for inserting the breakpoint.

   On the i386 we have a single breakpoint that fits in a single byte
   and can be inserted anywhere.

   This function is 64-bit safe.  */

constexpr gdb_byte i386_break_insn[] = { 0xcc }; /* int 3 */

typedef BP_MANIPULATION (i386_break_insn) i386_breakpoint;


/* Displaced instruction handling.  */

/* Skip the legacy instruction prefixes in INSN.
   Not all prefixes are valid for any particular insn
   but we needn't care, the insn will fault if it's invalid.
   The result is a pointer to the first opcode byte,
   or NULL if we run off the end of the buffer.  */

static gdb_byte *
i386_skip_prefixes (gdb_byte *insn, size_t max_len)
{
  gdb_byte *end = insn + max_len;

  while (insn < end)
    {
      switch (*insn)
	{
	case DATA_PREFIX_OPCODE:
	case ADDR_PREFIX_OPCODE:
	case CS_PREFIX_OPCODE:
	case DS_PREFIX_OPCODE:
	case ES_PREFIX_OPCODE:
	case FS_PREFIX_OPCODE:
	case GS_PREFIX_OPCODE:
	case SS_PREFIX_OPCODE:
	case LOCK_PREFIX_OPCODE:
	case REPE_PREFIX_OPCODE:
	case REPNE_PREFIX_OPCODE:
	  ++insn;
	  continue;
	default:
	  return insn;
	}
    }

  return NULL;
}

static int
i386_absolute_jmp_p (const gdb_byte *insn)
{
  /* jmp far (absolute address in operand).  */
  if (insn[0] == 0xea)
    return 1;

  if (insn[0] == 0xff)
    {
      /* jump near, absolute indirect (/4).  */
      if ((insn[1] & 0x38) == 0x20)
        return 1;

      /* jump far, absolute indirect (/5).  */
      if ((insn[1] & 0x38) == 0x28)
        return 1;
    }

  return 0;
}

/* Return non-zero if INSN is a jump, zero otherwise.  */

static int
i386_jmp_p (const gdb_byte *insn)
{
  /* jump short, relative.  */
  if (insn[0] == 0xeb)
    return 1;

  /* jump near, relative.  */
  if (insn[0] == 0xe9)
    return 1;

  return i386_absolute_jmp_p (insn);
}

static int
i386_absolute_call_p (const gdb_byte *insn)
{
  /* call far, absolute.  */
  if (insn[0] == 0x9a)
    return 1;

  if (insn[0] == 0xff)
    {
      /* Call near, absolute indirect (/2).  */
      if ((insn[1] & 0x38) == 0x10)
        return 1;

      /* Call far, absolute indirect (/3).  */
      if ((insn[1] & 0x38) == 0x18)
        return 1;
    }

  return 0;
}

static int
i386_ret_p (const gdb_byte *insn)
{
  switch (insn[0])
    {
    case 0xc2: /* ret near, pop N bytes.  */
    case 0xc3: /* ret near */
    case 0xca: /* ret far, pop N bytes.  */
    case 0xcb: /* ret far */
    case 0xcf: /* iret */
      return 1;

    default:
      return 0;
    }
}

static int
i386_call_p (const gdb_byte *insn)
{
  if (i386_absolute_call_p (insn))
    return 1;

  /* call near, relative.  */
  if (insn[0] == 0xe8)
    return 1;

  return 0;
}

/* Return non-zero if INSN is a system call, and set *LENGTHP to its
   length in bytes.  Otherwise, return zero.  */

static int
i386_syscall_p (const gdb_byte *insn, int *lengthp)
{
  /* Is it 'int $0x80'?  */
  if ((insn[0] == 0xcd && insn[1] == 0x80)
      /* Or is it 'sysenter'?  */
      || (insn[0] == 0x0f && insn[1] == 0x34)
      /* Or is it 'syscall'?  */
      || (insn[0] == 0x0f && insn[1] == 0x05))
    {
      *lengthp = 2;
      return 1;
    }

  return 0;
}

/* The gdbarch insn_is_call method.  */

static int
i386_insn_is_call (struct gdbarch *gdbarch, CORE_ADDR addr)
{
  gdb_byte buf[I386_MAX_INSN_LEN], *insn;

  read_code (addr, buf, I386_MAX_INSN_LEN);
  insn = i386_skip_prefixes (buf, I386_MAX_INSN_LEN);

  return i386_call_p (insn);
}

/* The gdbarch insn_is_ret method.  */

static int
i386_insn_is_ret (struct gdbarch *gdbarch, CORE_ADDR addr)
{
  gdb_byte buf[I386_MAX_INSN_LEN], *insn;

  read_code (addr, buf, I386_MAX_INSN_LEN);
  insn = i386_skip_prefixes (buf, I386_MAX_INSN_LEN);

  return i386_ret_p (insn);
}

/* The gdbarch insn_is_jump method.  */

static int
i386_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr)
{
  gdb_byte buf[I386_MAX_INSN_LEN], *insn;

  read_code (addr, buf, I386_MAX_INSN_LEN);
  insn = i386_skip_prefixes (buf, I386_MAX_INSN_LEN);

  return i386_jmp_p (insn);
}

/* Some kernels may run one past a syscall insn, so we have to cope.  */

struct displaced_step_closure *
i386_displaced_step_copy_insn (struct gdbarch *gdbarch,
			       CORE_ADDR from, CORE_ADDR to,
			       struct regcache *regs)
{
  size_t len = gdbarch_max_insn_length (gdbarch);
  i386_displaced_step_closure *closure = new i386_displaced_step_closure (len);
  gdb_byte *buf = closure->buf.data ();

  read_memory (from, buf, len);

  /* GDB may get control back after the insn after the syscall.
     Presumably this is a kernel bug.
     If this is a syscall, make sure there's a nop afterwards.  */
  {
    int syscall_length;
    gdb_byte *insn;

    insn = i386_skip_prefixes (buf, len);
    if (insn != NULL && i386_syscall_p (insn, &syscall_length))
      insn[syscall_length] = NOP_OPCODE;
  }

  write_memory (to, buf, len);

  if (debug_displaced)
    {
      fprintf_unfiltered (gdb_stdlog, "displaced: copy %s->%s: ",
                          paddress (gdbarch, from), paddress (gdbarch, to));
      displaced_step_dump_bytes (gdb_stdlog, buf, len);
    }

  return closure;
}

/* Fix up the state of registers and memory after having single-stepped
   a displaced instruction.  */

void
i386_displaced_step_fixup (struct gdbarch *gdbarch,
                           struct displaced_step_closure *closure_,
                           CORE_ADDR from, CORE_ADDR to,
                           struct regcache *regs)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);

  /* The offset we applied to the instruction's address.
     This could well be negative (when viewed as a signed 32-bit
     value), but ULONGEST won't reflect that, so take care when
     applying it.  */
  ULONGEST insn_offset = to - from;

  i386_displaced_step_closure *closure
    = (i386_displaced_step_closure *) closure_;
  gdb_byte *insn = closure->buf.data ();
  /* The start of the insn, needed in case we see some prefixes.  */
  gdb_byte *insn_start = insn;

  if (debug_displaced)
    fprintf_unfiltered (gdb_stdlog,
                        "displaced: fixup (%s, %s), "
                        "insn = 0x%02x 0x%02x ...\n",
                        paddress (gdbarch, from), paddress (gdbarch, to),
			insn[0], insn[1]);

  /* The list of issues to contend with here is taken from
     resume_execution in arch/i386/kernel/kprobes.c, Linux 2.6.20.
     Yay for Free Software!  */

  /* Relocate the %eip, if necessary.  */

  /* The instruction recognizers we use assume any leading prefixes
     have been skipped.  */
  {
    /* This is the size of the buffer in closure.  */
    size_t max_insn_len = gdbarch_max_insn_length (gdbarch);
    gdb_byte *opcode = i386_skip_prefixes (insn, max_insn_len);
    /* If there are too many prefixes, just ignore the insn.
       It will fault when run.  */
    if (opcode != NULL)
      insn = opcode;
  }

  /* Except in the case of absolute or indirect jump or call
     instructions, or a return instruction, the new eip is relative to
     the displaced instruction; make it relative.  Well, signal
     handler returns don't need relocation either, but we use the
     value of %eip to recognize those; see below.  */
  if (! i386_absolute_jmp_p (insn)
      && ! i386_absolute_call_p (insn)
      && ! i386_ret_p (insn))
    {
      ULONGEST orig_eip;
      int insn_len;

      regcache_cooked_read_unsigned (regs, I386_EIP_REGNUM, &orig_eip);

      /* A signal trampoline system call changes the %eip, resuming
         execution of the main program after the signal handler has
         returned.  That makes them like 'return' instructions; we
         shouldn't relocate %eip.

         But most system calls don't, and we do need to relocate %eip.

         Our heuristic for distinguishing these cases: if stepping
         over the system call instruction left control directly after
         the instruction, the we relocate --- control almost certainly
         doesn't belong in the displaced copy.  Otherwise, we assume
         the instruction has put control where it belongs, and leave
         it unrelocated.  Goodness help us if there are PC-relative
         system calls.  */
      if (i386_syscall_p (insn, &insn_len)
          && orig_eip != to + (insn - insn_start) + insn_len
	  /* GDB can get control back after the insn after the syscall.
	     Presumably this is a kernel bug.
	     i386_displaced_step_copy_insn ensures its a nop,
	     we add one to the length for it.  */
          && orig_eip != to + (insn - insn_start) + insn_len + 1)
        {
          if (debug_displaced)
            fprintf_unfiltered (gdb_stdlog,
                                "displaced: syscall changed %%eip; "
                                "not relocating\n");
        }
      else
        {
          ULONGEST eip = (orig_eip - insn_offset) & 0xffffffffUL;

	  /* If we just stepped over a breakpoint insn, we don't backup
	     the pc on purpose; this is to match behaviour without
	     stepping.  */

          regcache_cooked_write_unsigned (regs, I386_EIP_REGNUM, eip);

          if (debug_displaced)
            fprintf_unfiltered (gdb_stdlog,
                                "displaced: "
                                "relocated %%eip from %s to %s\n",
                                paddress (gdbarch, orig_eip),
				paddress (gdbarch, eip));
        }
    }

  /* If the instruction was PUSHFL, then the TF bit will be set in the
     pushed value, and should be cleared.  We'll leave this for later,
     since GDB already messes up the TF flag when stepping over a
     pushfl.  */

  /* If the instruction was a call, the return address now atop the
     stack is the address following the copied instruction.  We need
     to make it the address following the original instruction.  */
  if (i386_call_p (insn))
    {
      ULONGEST esp;
      ULONGEST retaddr;
      const ULONGEST retaddr_len = 4;

      regcache_cooked_read_unsigned (regs, I386_ESP_REGNUM, &esp);
      retaddr = read_memory_unsigned_integer (esp, retaddr_len, byte_order);
      retaddr = (retaddr - insn_offset) & 0xffffffffUL;
      write_memory_unsigned_integer (esp, retaddr_len, byte_order, retaddr);

      if (debug_displaced)
        fprintf_unfiltered (gdb_stdlog,
                            "displaced: relocated return addr at %s to %s\n",
                            paddress (gdbarch, esp),
                            paddress (gdbarch, retaddr));
    }
}

static void
append_insns (CORE_ADDR *to, ULONGEST len, const gdb_byte *buf)
{
  target_write_memory (*to, buf, len);
  *to += len;
}

static void
i386_relocate_instruction (struct gdbarch *gdbarch,
			   CORE_ADDR *to, CORE_ADDR oldloc)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  gdb_byte buf[I386_MAX_INSN_LEN];
  int offset = 0, rel32, newrel;
  int insn_length;
  gdb_byte *insn = buf;

  read_memory (oldloc, buf, I386_MAX_INSN_LEN);

  insn_length = gdb_buffered_insn_length (gdbarch, insn,
					  I386_MAX_INSN_LEN, oldloc);

  /* Get past the prefixes.  */
  insn = i386_skip_prefixes (insn, I386_MAX_INSN_LEN);

  /* Adjust calls with 32-bit relative addresses as push/jump, with
     the address pushed being the location where the original call in
     the user program would return to.  */
  if (insn[0] == 0xe8)
    {
      gdb_byte push_buf[16];
      unsigned int ret_addr;

      /* Where "ret" in the original code will return to.  */
      ret_addr = oldloc + insn_length;
      push_buf[0] = 0x68; /* pushq $...  */
      store_unsigned_integer (&push_buf[1], 4, byte_order, ret_addr);
      /* Push the push.  */
      append_insns (to, 5, push_buf);

      /* Convert the relative call to a relative jump.  */
      insn[0] = 0xe9;

      /* Adjust the destination offset.  */
      rel32 = extract_signed_integer (insn + 1, 4, byte_order);
      newrel = (oldloc - *to) + rel32;
      store_signed_integer (insn + 1, 4, byte_order, newrel);

      if (debug_displaced)
	fprintf_unfiltered (gdb_stdlog,
			    "Adjusted insn rel32=%s at %s to"
			    " rel32=%s at %s\n",
			    hex_string (rel32), paddress (gdbarch, oldloc),
			    hex_string (newrel), paddress (gdbarch, *to));

      /* Write the adjusted jump into its displaced location.  */
      append_insns (to, 5, insn);
      return;
    }

  /* Adjust jumps with 32-bit relative addresses.  Calls are already
     handled above.  */
  if (insn[0] == 0xe9)
    offset = 1;
  /* Adjust conditional jumps.  */
  else if (insn[0] == 0x0f && (insn[1] & 0xf0) == 0x80)
    offset = 2;

  if (offset)
    {
      rel32 = extract_signed_integer (insn + offset, 4, byte_order);
      newrel = (oldloc - *to) + rel32;
      store_signed_integer (insn + offset, 4, byte_order, newrel);
      if (debug_displaced)
	fprintf_unfiltered (gdb_stdlog,
			    "Adjusted insn rel32=%s at %s to"
			    " rel32=%s at %s\n",
			    hex_string (rel32), paddress (gdbarch, oldloc),
			    hex_string (newrel), paddress (gdbarch, *to));
    }

  /* Write the adjusted instructions into their displaced
     location.  */
  append_insns (to, insn_length, buf);
}


#ifdef I386_REGNO_TO_SYMMETRY
#error "The Sequent Symmetry is no longer supported."
#endif

/* According to the System V ABI, the registers %ebp, %ebx, %edi, %esi
   and %esp "belong" to the calling function.  Therefore these
   registers should be saved if they're going to be modified.  */

/* The maximum number of saved registers.  This should include all
   registers mentioned above, and %eip.  */
#define I386_NUM_SAVED_REGS	I386_NUM_GREGS

struct i386_frame_cache
{
  /* Base address.  */
  CORE_ADDR base;
  int base_p;
  LONGEST sp_offset;
  CORE_ADDR pc;

  /* Saved registers.  */
  CORE_ADDR saved_regs[I386_NUM_SAVED_REGS];
  CORE_ADDR saved_sp;
  int saved_sp_reg;
  int pc_in_eax;

  /* Stack space reserved for local variables.  */
  long locals;
};

/* Allocate and initialize a frame cache.  */

static struct i386_frame_cache *
i386_alloc_frame_cache (void)
{
  struct i386_frame_cache *cache;
  int i;

  cache = FRAME_OBSTACK_ZALLOC (struct i386_frame_cache);

  /* Base address.  */
  cache->base_p = 0;
  cache->base = 0;
  cache->sp_offset = -4;
  cache->pc = 0;

  /* Saved registers.  We initialize these to -1 since zero is a valid
     offset (that's where %ebp is supposed to be stored).  */
  for (i = 0; i < I386_NUM_SAVED_REGS; i++)
    cache->saved_regs[i] = -1;
  cache->saved_sp = 0;
  cache->saved_sp_reg = -1;
  cache->pc_in_eax = 0;

  /* Frameless until proven otherwise.  */
  cache->locals = -1;

  return cache;
}

/* If the instruction at PC is a jump, return the address of its
   target.  Otherwise, return PC.  */

static CORE_ADDR
i386_follow_jump (struct gdbarch *gdbarch, CORE_ADDR pc)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  gdb_byte op;
  long delta = 0;
  int data16 = 0;

  if (target_read_code (pc, &op, 1))
    return pc;

  if (op == 0x66)
    {
      data16 = 1;

      op = read_code_unsigned_integer (pc + 1, 1, byte_order);
    }

  switch (op)
    {
    case 0xe9:
      /* Relative jump: if data16 == 0, disp32, else disp16.  */
      if (data16)
	{
	  delta = read_memory_integer (pc + 2, 2, byte_order);

	  /* Include the size of the jmp instruction (including the
             0x66 prefix).  */
	  delta += 4;
	}
      else
	{
	  delta = read_memory_integer (pc + 1, 4, byte_order);

	  /* Include the size of the jmp instruction.  */
	  delta += 5;
	}
      break;
    case 0xeb:
      /* Relative jump, disp8 (ignore data16).  */
      delta = read_memory_integer (pc + data16 + 1, 1, byte_order);

      delta += data16 + 2;
      break;
    }

  return pc + delta;
}

/* Check whether PC points at a prologue for a function returning a
   structure or union.  If so, it updates CACHE and returns the
   address of the first instruction after the code sequence that
   removes the "hidden" argument from the stack or CURRENT_PC,
   whichever is smaller.  Otherwise, return PC.  */

static CORE_ADDR
i386_analyze_struct_return (CORE_ADDR pc, CORE_ADDR current_pc,
			    struct i386_frame_cache *cache)
{
  /* Functions that return a structure or union start with:

        popl %eax             0x58
        xchgl %eax, (%esp)    0x87 0x04 0x24
     or xchgl %eax, 0(%esp)   0x87 0x44 0x24 0x00

     (the System V compiler puts out the second `xchg' instruction,
     and the assembler doesn't try to optimize it, so the 'sib' form
     gets generated).  This sequence is used to get the address of the
     return buffer for a function that returns a structure.  */
  static gdb_byte proto1[3] = { 0x87, 0x04, 0x24 };
  static gdb_byte proto2[4] = { 0x87, 0x44, 0x24, 0x00 };
  gdb_byte buf[4];
  gdb_byte op;

  if (current_pc <= pc)
    return pc;

  if (target_read_code (pc, &op, 1))
    return pc;

  if (op != 0x58)		/* popl %eax */
    return pc;

  if (target_read_code (pc + 1, buf, 4))
    return pc;

  if (memcmp (buf, proto1, 3) != 0 && memcmp (buf, proto2, 4) != 0)
    return pc;

  if (current_pc == pc)
    {
      cache->sp_offset += 4;
      return current_pc;
    }

  if (current_pc == pc + 1)
    {
      cache->pc_in_eax = 1;
      return current_pc;
    }
  
  if (buf[1] == proto1[1])
    return pc + 4;
  else
    return pc + 5;
}

static CORE_ADDR
i386_skip_probe (CORE_ADDR pc)
{
  /* A function may start with

        pushl constant
        call _probe
	addl $4, %esp
	   
     followed by

        pushl %ebp

     etc.  */
  gdb_byte buf[8];
  gdb_byte op;

  if (target_read_code (pc, &op, 1))
    return pc;

  if (op == 0x68 || op == 0x6a)
    {
      int delta;

      /* Skip past the `pushl' instruction; it has either a one-byte or a
	 four-byte operand, depending on the opcode.  */
      if (op == 0x68)
	delta = 5;
      else
	delta = 2;

      /* Read the following 8 bytes, which should be `call _probe' (6
	 bytes) followed by `addl $4,%esp' (2 bytes).  */
      read_memory (pc + delta, buf, sizeof (buf));
      if (buf[0] == 0xe8 && buf[6] == 0xc4 && buf[7] == 0x4)
	pc += delta + sizeof (buf);
    }

  return pc;
}

/* GCC 4.1 and later, can put code in the prologue to realign the
   stack pointer.  Check whether PC points to such code, and update
   CACHE accordingly.  Return the first instruction after the code
   sequence or CURRENT_PC, whichever is smaller.  If we don't
   recognize the code, return PC.  */

static CORE_ADDR
i386_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc,
			  struct i386_frame_cache *cache)
{
  /* There are 2 code sequences to re-align stack before the frame
     gets set up:

	1. Use a caller-saved saved register:

		leal  4(%esp), %reg
		andl  $-XXX, %esp
		pushl -4(%reg)

	2. Use a callee-saved saved register:

		pushl %reg
		leal  8(%esp), %reg
		andl  $-XXX, %esp
		pushl -4(%reg)

     "andl $-XXX, %esp" can be either 3 bytes or 6 bytes:
     
     	0x83 0xe4 0xf0			andl $-16, %esp
     	0x81 0xe4 0x00 0xff 0xff 0xff	andl $-256, %esp
   */

  gdb_byte buf[14];
  int reg;
  int offset, offset_and;
  static int regnums[8] = {
    I386_EAX_REGNUM,		/* %eax */
    I386_ECX_REGNUM,		/* %ecx */
    I386_EDX_REGNUM,		/* %edx */
    I386_EBX_REGNUM,		/* %ebx */
    I386_ESP_REGNUM,		/* %esp */
    I386_EBP_REGNUM,		/* %ebp */
    I386_ESI_REGNUM,		/* %esi */
    I386_EDI_REGNUM		/* %edi */
  };

  if (target_read_code (pc, buf, sizeof buf))
    return pc;

  /* Check caller-saved saved register.  The first instruction has
     to be "leal 4(%esp), %reg".  */
  if (buf[0] == 0x8d && buf[2] == 0x24 && buf[3] == 0x4)
    {
      /* MOD must be binary 10 and R/M must be binary 100.  */
      if ((buf[1] & 0xc7) != 0x44)
	return pc;

      /* REG has register number.  */
      reg = (buf[1] >> 3) & 7;
      offset = 4;
    }
  else
    {
      /* Check callee-saved saved register.  The first instruction
	 has to be "pushl %reg".  */
      if ((buf[0] & 0xf8) != 0x50)
	return pc;

      /* Get register.  */
      reg = buf[0] & 0x7;

      /* The next instruction has to be "leal 8(%esp), %reg".  */
      if (buf[1] != 0x8d || buf[3] != 0x24 || buf[4] != 0x8)
	return pc;

      /* MOD must be binary 10 and R/M must be binary 100.  */
      if ((buf[2] & 0xc7) != 0x44)
	return pc;
      
      /* REG has register number.  Registers in pushl and leal have to
	 be the same.  */
      if (reg != ((buf[2] >> 3) & 7))
	return pc;

      offset = 5;
    }

  /* Rigister can't be %esp nor %ebp.  */
  if (reg == 4 || reg == 5)
    return pc;

  /* The next instruction has to be "andl $-XXX, %esp".  */
  if (buf[offset + 1] != 0xe4
      || (buf[offset] != 0x81 && buf[offset] != 0x83))
    return pc;

  offset_and = offset;
  offset += buf[offset] == 0x81 ? 6 : 3;

  /* The next instruction has to be "pushl -4(%reg)".  8bit -4 is
     0xfc.  REG must be binary 110 and MOD must be binary 01.  */
  if (buf[offset] != 0xff
      || buf[offset + 2] != 0xfc
      || (buf[offset + 1] & 0xf8) != 0x70)
    return pc;

  /* R/M has register.  Registers in leal and pushl have to be the
     same.  */
  if (reg != (buf[offset + 1] & 7))
    return pc;

  if (current_pc > pc + offset_and)
    cache->saved_sp_reg = regnums[reg];

  return std::min (pc + offset + 3, current_pc);
}

/* Maximum instruction length we need to handle.  */
#define I386_MAX_MATCHED_INSN_LEN	6

/* Instruction description.  */
struct i386_insn
{
  size_t len;
  gdb_byte insn[I386_MAX_MATCHED_INSN_LEN];
  gdb_byte mask[I386_MAX_MATCHED_INSN_LEN];
};

/* Return whether instruction at PC matches PATTERN.  */

static int
i386_match_pattern (CORE_ADDR pc, struct i386_insn pattern)
{
  gdb_byte op;

  if (target_read_code (pc, &op, 1))
    return 0;

  if ((op & pattern.mask[0]) == pattern.insn[0])
    {
      gdb_byte buf[I386_MAX_MATCHED_INSN_LEN - 1];
      int insn_matched = 1;
      size_t i;

      gdb_assert (pattern.len > 1);
      gdb_assert (pattern.len <= I386_MAX_MATCHED_INSN_LEN);

      if (target_read_code (pc + 1, buf, pattern.len - 1))
	return 0;

      for (i = 1; i < pattern.len; i++)
	{
	  if ((buf[i - 1] & pattern.mask[i]) != pattern.insn[i])
	    insn_matched = 0;
	}
      return insn_matched;
    }
  return 0;
}

/* Search for the instruction at PC in the list INSN_PATTERNS.  Return
   the first instruction description that matches.  Otherwise, return
   NULL.  */

static struct i386_insn *
i386_match_insn (CORE_ADDR pc, struct i386_insn *insn_patterns)
{
  struct i386_insn *pattern;

  for (pattern = insn_patterns; pattern->len > 0; pattern++)
    {
      if (i386_match_pattern (pc, *pattern))
	return pattern;
    }

  return NULL;
}

/* Return whether PC points inside a sequence of instructions that
   matches INSN_PATTERNS.  */

static int
i386_match_insn_block (CORE_ADDR pc, struct i386_insn *insn_patterns)
{
  CORE_ADDR current_pc;
  int ix, i;
  struct i386_insn *insn;

  insn = i386_match_insn (pc, insn_patterns);
  if (insn == NULL)
    return 0;

  current_pc = pc;
  ix = insn - insn_patterns;
  for (i = ix - 1; i >= 0; i--)
    {
      current_pc -= insn_patterns[i].len;

      if (!i386_match_pattern (current_pc, insn_patterns[i]))
	return 0;
    }

  current_pc = pc + insn->len;
  for (insn = insn_patterns + ix + 1; insn->len > 0; insn++)
    {
      if (!i386_match_pattern (current_pc, *insn))
	return 0;

      current_pc += insn->len;
    }

  return 1;
}

/* Some special instructions that might be migrated by GCC into the
   part of the prologue that sets up the new stack frame.  Because the
   stack frame hasn't been setup yet, no registers have been saved
   yet, and only the scratch registers %eax, %ecx and %edx can be
   touched.  */

struct i386_insn i386_frame_setup_skip_insns[] =
{
  /* Check for `movb imm8, r' and `movl imm32, r'.
    
     ??? Should we handle 16-bit operand-sizes here?  */

  /* `movb imm8, %al' and `movb imm8, %ah' */
  /* `movb imm8, %cl' and `movb imm8, %ch' */
  { 2, { 0xb0, 0x00 }, { 0xfa, 0x00 } },
  /* `movb imm8, %dl' and `movb imm8, %dh' */
  { 2, { 0xb2, 0x00 }, { 0xfb, 0x00 } },
  /* `movl imm32, %eax' and `movl imm32, %ecx' */
  { 5, { 0xb8 }, { 0xfe } },
  /* `movl imm32, %edx' */
  { 5, { 0xba }, { 0xff } },

  /* Check for `mov imm32, r32'.  Note that there is an alternative
     encoding for `mov m32, %eax'.

     ??? Should we handle SIB adressing here?
     ??? Should we handle 16-bit operand-sizes here?  */

  /* `movl m32, %eax' */
  { 5, { 0xa1 }, { 0xff } },
  /* `movl m32, %eax' and `mov; m32, %ecx' */
  { 6, { 0x89, 0x05 }, {0xff, 0xf7 } },
  /* `movl m32, %edx' */
  { 6, { 0x89, 0x15 }, {0xff, 0xff } },

  /* Check for `xorl r32, r32' and the equivalent `subl r32, r32'.
     Because of the symmetry, there are actually two ways to encode
     these instructions; opcode bytes 0x29 and 0x2b for `subl' and
     opcode bytes 0x31 and 0x33 for `xorl'.  */

  /* `subl %eax, %eax' */
  { 2, { 0x29, 0xc0 }, { 0xfd, 0xff } },
  /* `subl %ecx, %ecx' */
  { 2, { 0x29, 0xc9 }, { 0xfd, 0xff } },
  /* `subl %edx, %edx' */
  { 2, { 0x29, 0xd2 }, { 0xfd, 0xff } },
  /* `xorl %eax, %eax' */
  { 2, { 0x31, 0xc0 }, { 0xfd, 0xff } },
  /* `xorl %ecx, %ecx' */
  { 2, { 0x31, 0xc9 }, { 0xfd, 0xff } },
  /* `xorl %edx, %edx' */
  { 2, { 0x31, 0xd2 }, { 0xfd, 0xff } },
  { 0 }
};


/* Check whether PC points to a no-op instruction.  */
static CORE_ADDR
i386_skip_noop (CORE_ADDR pc)
{
  gdb_byte op;
  int check = 1;

  if (target_read_code (pc, &op, 1))
    return pc;

  while (check) 
    {
      check = 0;
      /* Ignore `nop' instruction.  */
      if (op == 0x90) 
	{
	  pc += 1;
	  if (target_read_code (pc, &op, 1))
	    return pc;
	  check = 1;
	}
      /* Ignore no-op instruction `mov %edi, %edi'.
	 Microsoft system dlls often start with
	 a `mov %edi,%edi' instruction.
	 The 5 bytes before the function start are
	 filled with `nop' instructions.
	 This pattern can be used for hot-patching:
	 The `mov %edi, %edi' instruction can be replaced by a
	 near jump to the location of the 5 `nop' instructions
	 which can be replaced by a 32-bit jump to anywhere
	 in the 32-bit address space.  */

      else if (op == 0x8b)
	{
	  if (target_read_code (pc + 1, &op, 1))
	    return pc;

	  if (op == 0xff)
	    {
	      pc += 2;
	      if (target_read_code (pc, &op, 1))
		return pc;

	      check = 1;
	    }
	}
    }
  return pc; 
}

/* Check whether PC points at a code that sets up a new stack frame.
   If so, it updates CACHE and returns the address of the first
   instruction after the sequence that sets up the frame or LIMIT,
   whichever is smaller.  If we don't recognize the code, return PC.  */

static CORE_ADDR
i386_analyze_frame_setup (struct gdbarch *gdbarch,
			  CORE_ADDR pc, CORE_ADDR limit,
			  struct i386_frame_cache *cache)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  struct i386_insn *insn;
  gdb_byte op;
  int skip = 0;

  if (limit <= pc)
    return limit;

  if (target_read_code (pc, &op, 1))
    return pc;

  if (op == 0x55)		/* pushl %ebp */
    {
      /* Take into account that we've executed the `pushl %ebp' that
	 starts this instruction sequence.  */
      cache->saved_regs[I386_EBP_REGNUM] = 0;
      cache->sp_offset += 4;
      pc++;

      /* If that's all, return now.  */
      if (limit <= pc)
	return limit;

      /* Check for some special instructions that might be migrated by
	 GCC into the prologue and skip them.  At this point in the
	 prologue, code should only touch the scratch registers %eax,
	 %ecx and %edx, so while the number of posibilities is sheer,
	 it is limited.

	 Make sure we only skip these instructions if we later see the
	 `movl %esp, %ebp' that actually sets up the frame.  */
      while (pc + skip < limit)
	{
	  insn = i386_match_insn (pc + skip, i386_frame_setup_skip_insns);
	  if (insn == NULL)
	    break;

	  skip += insn->len;
	}

      /* If that's all, return now.  */
      if (limit <= pc + skip)
	return limit;

      if (target_read_code (pc + skip, &op, 1))
	return pc + skip;

      /* The i386 prologue looks like

	 push   %ebp
	 mov    %esp,%ebp
	 sub    $0x10,%esp

	 and a different prologue can be generated for atom.

	 push   %ebp
	 lea    (%esp),%ebp
	 lea    -0x10(%esp),%esp

	 We handle both of them here.  */

      switch (op)
	{
	  /* Check for `movl %esp, %ebp' -- can be written in two ways.  */
	case 0x8b:
	  if (read_code_unsigned_integer (pc + skip + 1, 1, byte_order)
	      != 0xec)
	    return pc;
	  pc += (skip + 2);
	  break;
	case 0x89:
	  if (read_code_unsigned_integer (pc + skip + 1, 1, byte_order)
	      != 0xe5)
	    return pc;
	  pc += (skip + 2);
	  break;
	case 0x8d: /* Check for 'lea (%ebp), %ebp'.  */
	  if (read_code_unsigned_integer (pc + skip + 1, 2, byte_order)
	      != 0x242c)
	    return pc;
	  pc += (skip + 3);
	  break;
	default:
	  return pc;
	}

      /* OK, we actually have a frame.  We just don't know how large
	 it is yet.  Set its size to zero.  We'll adjust it if
	 necessary.  We also now commit to skipping the special
	 instructions mentioned before.  */
      cache->locals = 0;

      /* If that's all, return now.  */
      if (limit <= pc)
	return limit;

      /* Check for stack adjustment 

	    subl $XXX, %esp
	 or
	    lea -XXX(%esp),%esp

	 NOTE: You can't subtract a 16-bit immediate from a 32-bit
	 reg, so we don't have to worry about a data16 prefix.  */
      if (target_read_code (pc, &op, 1))
	return pc;
      if (op == 0x83)
	{
	  /* `subl' with 8-bit immediate.  */
	  if (read_code_unsigned_integer (pc + 1, 1, byte_order) != 0xec)
	    /* Some instruction starting with 0x83 other than `subl'.  */
	    return pc;

	  /* `subl' with signed 8-bit immediate (though it wouldn't
	     make sense to be negative).  */
	  cache->locals = read_code_integer (pc + 2, 1, byte_order);
	  return pc + 3;
	}
      else if (op == 0x81)
	{
	  /* Maybe it is `subl' with a 32-bit immediate.  */
	  if (read_code_unsigned_integer (pc + 1, 1, byte_order) != 0xec)
	    /* Some instruction starting with 0x81 other than `subl'.  */
	    return pc;

	  /* It is `subl' with a 32-bit immediate.  */
	  cache->locals = read_code_integer (pc + 2, 4, byte_order);
	  return pc + 6;
	}
      else if (op == 0x8d)
	{
	  /* The ModR/M byte is 0x64.  */
	  if (read_code_unsigned_integer (pc + 1, 1, byte_order) != 0x64)
	    return pc;
	  /* 'lea' with 8-bit displacement.  */
	  cache->locals = -1 * read_code_integer (pc + 3, 1, byte_order);
	  return pc + 4;
	}
      else
	{
	  /* Some instruction other than `subl' nor 'lea'.  */
	  return pc;
	}
    }
  else if (op == 0xc8)		/* enter */
    {
      cache->locals = read_code_unsigned_integer (pc + 1, 2, byte_order);
      return pc + 4;
    }

  return pc;
}

/* Check whether PC points at code that saves registers on the stack.
   If so, it updates CACHE and returns the address of the first
   instruction after the register saves or CURRENT_PC, whichever is
   smaller.  Otherwise, return PC.  */

static CORE_ADDR
i386_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc,
			     struct i386_frame_cache *cache)
{
  CORE_ADDR offset = 0;
  gdb_byte op;
  int i;

  if (cache->locals > 0)
    offset -= cache->locals;
  for (i = 0; i < 8 && pc < current_pc; i++)
    {
      if (target_read_code (pc, &op, 1))
	return pc;
      if (op < 0x50 || op > 0x57)
	break;

      offset -= 4;
      cache->saved_regs[op - 0x50] = offset;
      cache->sp_offset += 4;
      pc++;
    }

  return pc;
}

/* Do a full analysis of the prologue at PC and update CACHE
   accordingly.  Bail out early if CURRENT_PC is reached.  Return the
   address where the analysis stopped.

   We handle these cases:

   The startup sequence can be at the start of the function, or the
   function can start with a branch to startup code at the end.

   %ebp can be set up with either the 'enter' instruction, or "pushl
   %ebp, movl %esp, %ebp" (`enter' is too slow to be useful, but was
   once used in the System V compiler).

   Local space is allocated just below the saved %ebp by either the
   'enter' instruction, or by "subl $<size>, %esp".  'enter' has a
   16-bit unsigned argument for space to allocate, and the 'addl'
   instruction could have either a signed byte, or 32-bit immediate.

   Next, the registers used by this function are pushed.  With the
   System V compiler they will always be in the order: %edi, %esi,
   %ebx (and sometimes a harmless bug causes it to also save but not
   restore %eax); however, the code below is willing to see the pushes
   in any order, and will handle up to 8 of them.
 
   If the setup sequence is at the end of the function, then the next
   instruction will be a branch back to the start.  */

static CORE_ADDR
i386_analyze_prologue (struct gdbarch *gdbarch,
		       CORE_ADDR pc, CORE_ADDR current_pc,
		       struct i386_frame_cache *cache)
{
  pc = i386_skip_noop (pc);
  pc = i386_follow_jump (gdbarch, pc);
  pc = i386_analyze_struct_return (pc, current_pc, cache);
  pc = i386_skip_probe (pc);
  pc = i386_analyze_stack_align (pc, current_pc, cache);
  pc = i386_analyze_frame_setup (gdbarch, pc, current_pc, cache);
  return i386_analyze_register_saves (pc, current_pc, cache);
}

/* Return PC of first real instruction.  */

static CORE_ADDR
i386_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);

  static gdb_byte pic_pat[6] =
  {
    0xe8, 0, 0, 0, 0,		/* call 0x0 */
    0x5b,			/* popl %ebx */
  };
  struct i386_frame_cache cache;
  CORE_ADDR pc;
  gdb_byte op;
  int i;
  CORE_ADDR func_addr;

  if (find_pc_partial_function (start_pc, NULL, &func_addr, NULL))
    {
      CORE_ADDR post_prologue_pc
	= skip_prologue_using_sal (gdbarch, func_addr);
      struct compunit_symtab *cust = find_pc_compunit_symtab (func_addr);

      /* Clang always emits a line note before the prologue and another
	 one after.  We trust clang to emit usable line notes.  */
      if (post_prologue_pc
	  && (cust != NULL
	      && COMPUNIT_PRODUCER (cust) != NULL
	      && startswith (COMPUNIT_PRODUCER (cust), "clang ")))
        return std::max (start_pc, post_prologue_pc);
    }
 
  cache.locals = -1;
  pc = i386_analyze_prologue (gdbarch, start_pc, 0xffffffff, &cache);
  if (cache.locals < 0)
    return start_pc;

  /* Found valid frame setup.  */

  /* The native cc on SVR4 in -K PIC mode inserts the following code
     to get the address of the global offset table (GOT) into register
     %ebx:

        call	0x0
	popl    %ebx
        movl    %ebx,x(%ebp)    (optional)
        addl    y,%ebx

     This code is with the rest of the prologue (at the end of the
     function), so we have to skip it to get to the first real
     instruction at the start of the function.  */

  for (i = 0; i < 6; i++)
    {
      if (target_read_code (pc + i, &op, 1))
	return pc;

      if (pic_pat[i] != op)
	break;
    }
  if (i == 6)
    {
      int delta = 6;

      if (target_read_code (pc + delta, &op, 1))
	return pc;

      if (op == 0x89)		/* movl %ebx, x(%ebp) */
	{
	  op = read_code_unsigned_integer (pc + delta + 1, 1, byte_order);

	  if (op == 0x5d)	/* One byte offset from %ebp.  */
	    delta += 3;
	  else if (op == 0x9d)	/* Four byte offset from %ebp.  */
	    delta += 6;
	  else			/* Unexpected instruction.  */
	    delta = 0;

          if (target_read_code (pc + delta, &op, 1))
	    return pc;
	}

      /* addl y,%ebx */
      if (delta > 0 && op == 0x81
	  && read_code_unsigned_integer (pc + delta + 1, 1, byte_order)
	     == 0xc3)
	{
	  pc += delta + 6;
	}
    }

  /* If the function starts with a branch (to startup code at the end)
     the last instruction should bring us back to the first
     instruction of the real code.  */
  if (i386_follow_jump (gdbarch, start_pc) != start_pc)
    pc = i386_follow_jump (gdbarch, pc);

  return pc;
}

/* Check that the code pointed to by PC corresponds to a call to
   __main, skip it if so.  Return PC otherwise.  */

CORE_ADDR
i386_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  gdb_byte op;

  if (target_read_code (pc, &op, 1))
    return pc;
  if (op == 0xe8)
    {
      gdb_byte buf[4];

      if (target_read_code (pc + 1, buf, sizeof buf) == 0)
 	{
	  /* Make sure address is computed correctly as a 32bit
	     integer even if CORE_ADDR is 64 bit wide.  */
 	  struct bound_minimal_symbol s;
 	  CORE_ADDR call_dest;

	  call_dest = pc + 5 + extract_signed_integer (buf, 4, byte_order);
	  call_dest = call_dest & 0xffffffffU;
 	  s = lookup_minimal_symbol_by_pc (call_dest);
 	  if (s.minsym != NULL
 	      && MSYMBOL_LINKAGE_NAME (s.minsym) != NULL
 	      && strcmp (MSYMBOL_LINKAGE_NAME (s.minsym), "__main") == 0)
 	    pc += 5;
 	}
    }

  return pc;
}

/* This function is 64-bit safe.  */

static CORE_ADDR
i386_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
  gdb_byte buf[8];

  frame_unwind_register (next_frame, gdbarch_pc_regnum (gdbarch), buf);
  return extract_typed_address (buf, builtin_type (gdbarch)->builtin_func_ptr);
}


/* Normal frames.  */

static void
i386_frame_cache_1 (struct frame_info *this_frame,
		    struct i386_frame_cache *cache)
{
  struct gdbarch *gdbarch = get_frame_arch (this_frame);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  gdb_byte buf[4];
  int i;

  cache->pc = get_frame_func (this_frame);

  /* In principle, for normal frames, %ebp holds the frame pointer,
     which holds the base address for the current stack frame.
     However, for functions that don't need it, the frame pointer is
     optional.  For these "frameless" functions the frame pointer is
     actually the frame pointer of the calling frame.  Signal
     trampolines are just a special case of a "frameless" function.
     They (usually) share their frame pointer with the frame that was
     in progress when the signal occurred.  */

  get_frame_register (this_frame, I386_EBP_REGNUM, buf);
  cache->base = extract_unsigned_integer (buf, 4, byte_order);
  if (cache->base == 0)
    {
      cache->base_p = 1;
      return;
    }

  /* For normal frames, %eip is stored at 4(%ebp).  */
  cache->saved_regs[I386_EIP_REGNUM] = 4;

  if (cache->pc != 0)
    i386_analyze_prologue (gdbarch, cache->pc, get_frame_pc (this_frame),
			   cache);

  if (cache->locals < 0)
    {
      /* We didn't find a valid frame, which means that CACHE->base
	 currently holds the frame pointer for our calling frame.  If
	 we're at the start of a function, or somewhere half-way its
	 prologue, the function's frame probably hasn't been fully
	 setup yet.  Try to reconstruct the base address for the stack
	 frame by looking at the stack pointer.  For truly "frameless"
	 functions this might work too.  */

      if (cache->saved_sp_reg != -1)
	{
	  /* Saved stack pointer has been saved.  */
	  get_frame_register (this_frame, cache->saved_sp_reg, buf);
	  cache->saved_sp = extract_unsigned_integer (buf, 4, byte_order);

	  /* We're halfway aligning the stack.  */
	  cache->base = ((cache->saved_sp - 4) & 0xfffffff0) - 4;
	  cache->saved_regs[I386_EIP_REGNUM] = cache->saved_sp - 4;

	  /* This will be added back below.  */
	  cache->saved_regs[I386_EIP_REGNUM] -= cache->base;
	}
      else if (cache->pc != 0
	       || target_read_code (get_frame_pc (this_frame), buf, 1))
	{
	  /* We're in a known function, but did not find a frame
	     setup.  Assume that the function does not use %ebp.
	     Alternatively, we may have jumped to an invalid
	     address; in that case there is definitely no new
	     frame in %ebp.  */
	  get_frame_register (this_frame, I386_ESP_REGNUM, buf);
	  cache->base = extract_unsigned_integer (buf, 4, byte_order)
			+ cache->sp_offset;
	}
      else
	/* We're in an unknown function.  We could not find the start
	   of the function to analyze the prologue; our best option is
	   to assume a typical frame layout with the caller's %ebp
	   saved.  */
	cache->saved_regs[I386_EBP_REGNUM] = 0;
    }

  if (cache->saved_sp_reg != -1)
    {
      /* Saved stack pointer has been saved (but the SAVED_SP_REG
	 register may be unavailable).  */
      if (cache->saved_sp == 0
	  && deprecated_frame_register_read (this_frame,
					     cache->saved_sp_reg, buf))
	cache->saved_sp = extract_unsigned_integer (buf, 4, byte_order);
    }
  /* Now that we have the base address for the stack frame we can
     calculate the value of %esp in the calling frame.  */
  else if (cache->saved_sp == 0)
    cache->saved_sp = cache->base + 8;

  /* Adjust all the saved registers such that they contain addresses
     instead of offsets.  */
  for (i = 0; i < I386_NUM_SAVED_REGS; i++)
    if (cache->saved_regs[i] != -1)
      cache->saved_regs[i] += cache->base;

  cache->base_p = 1;
}

static struct i386_frame_cache *
i386_frame_cache (struct frame_info *this_frame, void **this_cache)
{
  struct i386_frame_cache *cache;

  if (*this_cache)
    return (struct i386_frame_cache *) *this_cache;

  cache = i386_alloc_frame_cache ();
  *this_cache = cache;

  TRY
    {
      i386_frame_cache_1 (this_frame, cache);
    }
  CATCH (ex, RETURN_MASK_ERROR)
    {
      if (ex.error != NOT_AVAILABLE_ERROR)
	throw_exception (ex);
    }
  END_CATCH

  return cache;
}

static void
i386_frame_this_id (struct frame_info *this_frame, void **this_cache,
		    struct frame_id *this_id)
{
  struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache);

  if (!cache->base_p)
    (*this_id) = frame_id_build_unavailable_stack (cache->pc);
  else if (cache->base == 0)
    {
      /* This marks the outermost frame.  */
    }
  else
    {
      /* See the end of i386_push_dummy_call.  */
      (*this_id) = frame_id_build (cache->base + 8, cache->pc);
    }
}

static enum unwind_stop_reason
i386_frame_unwind_stop_reason (struct frame_info *this_frame,
			       void **this_cache)
{
  struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache);

  if (!cache->base_p)
    return UNWIND_UNAVAILABLE;

  /* This marks the outermost frame.  */
  if (cache->base == 0)
    return UNWIND_OUTERMOST;

  return UNWIND_NO_REASON;
}

static struct value *
i386_frame_prev_register (struct frame_info *this_frame, void **this_cache,
			  int regnum)
{
  struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache);

  gdb_assert (regnum >= 0);

  /* The System V ABI says that:

     "The flags register contains the system flags, such as the
     direction flag and the carry flag.  The direction flag must be
     set to the forward (that is, zero) direction before entry and
     upon exit from a function.  Other user flags have no specified
     role in the standard calling sequence and are not preserved."

     To guarantee the "upon exit" part of that statement we fake a
     saved flags register that has its direction flag cleared.

     Note that GCC doesn't seem to rely on the fact that the direction
     flag is cleared after a function return; it always explicitly
     clears the flag before operations where it matters.

     FIXME: kettenis/20030316: I'm not quite sure whether this is the
     right thing to do.  The way we fake the flags register here makes
     it impossible to change it.  */

  if (regnum == I386_EFLAGS_REGNUM)
    {
      ULONGEST val;

      val = get_frame_register_unsigned (this_frame, regnum);
      val &= ~(1 << 10);
      return frame_unwind_got_constant (this_frame, regnum, val);
    }

  if (regnum == I386_EIP_REGNUM && cache->pc_in_eax)
    return frame_unwind_got_register (this_frame, regnum, I386_EAX_REGNUM);

  if (regnum == I386_ESP_REGNUM
      && (cache->saved_sp != 0 || cache->saved_sp_reg != -1))
    {
      /* If the SP has been saved, but we don't know where, then this
	 means that SAVED_SP_REG register was found unavailable back
	 when we built the cache.  */
      if (cache->saved_sp == 0)
	return frame_unwind_got_register (this_frame, regnum,
					  cache->saved_sp_reg);
      else
	return frame_unwind_got_constant (this_frame, regnum,
					  cache->saved_sp);
    }

  if (regnum < I386_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1)
    return frame_unwind_got_memory (this_frame, regnum,
				    cache->saved_regs[regnum]);

  return frame_unwind_got_register (this_frame, regnum, regnum);
}

static const struct frame_unwind i386_frame_unwind =
{
  NORMAL_FRAME,
  i386_frame_unwind_stop_reason,
  i386_frame_this_id,
  i386_frame_prev_register,
  NULL,
  default_frame_sniffer
};

/* Normal frames, but in a function epilogue.  */

/* Implement the stack_frame_destroyed_p gdbarch method.

   The epilogue is defined here as the 'ret' instruction, which will
   follow any instruction such as 'leave' or 'pop %ebp' that destroys
   the function's stack frame.  */

static int
i386_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
  gdb_byte insn;
  struct compunit_symtab *cust;

  cust = find_pc_compunit_symtab (pc);
  if (cust != NULL && COMPUNIT_EPILOGUE_UNWIND_VALID (cust))
    return 0;

  if (target_read_memory (pc, &insn, 1))
    return 0;	/* Can't read memory at pc.  */

  if (insn != 0xc3)	/* 'ret' instruction.  */
    return 0;

  return 1;
}

static int
i386_epilogue_frame_sniffer (const struct frame_unwind *self,
			     struct frame_info *this_frame,
			     void **this_prologue_cache)
{
  if (frame_relative_level (this_frame) == 0)
    return i386_stack_frame_destroyed_p (get_frame_arch (this_frame),
					 get_frame_pc (this_frame));
  else
    return 0;
}

static struct i386_frame_cache *
i386_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache)
{
  struct i386_frame_cache *cache;
  CORE_ADDR sp;

  if (*this_cache)
    return (struct i386_frame_cache *) *this_cache;

  cache = i386_alloc_frame_cache ();
  *this_cache = cache;

  TRY
    {
      cache->pc = get_frame_func (this_frame);

      /* At this point the stack looks as if we just entered the
	 function, with the return address at the top of the
	 stack.  */
      sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
      cache->base = sp + cache->sp_offset;
      cache->saved_sp = cache->base + 8;
      cache->saved_regs[I386_EIP_REGNUM] = cache->base + 4;

      cache->base_p = 1;
    }
  CATCH (ex, RETURN_MASK_ERROR)
    {
      if (ex.error != NOT_AVAILABLE_ERROR)
	throw_exception (ex);
    }
  END_CATCH

  return cache;
}

static enum unwind_stop_reason
i386_epilogue_frame_unwind_stop_reason (struct frame_info *this_frame,
					void **this_cache)
{
  struct i386_frame_cache *cache =
    i386_epilogue_frame_cache (this_frame, this_cache);

  if (!cache->base_p)
    return UNWIND_UNAVAILABLE;

  return UNWIND_NO_REASON;
}

static void
i386_epilogue_frame_this_id (struct frame_info *this_frame,
			     void **this_cache,
			     struct frame_id *this_id)
{
  struct i386_frame_cache *cache =
    i386_epilogue_frame_cache (this_frame, this_cache);

  if (!cache->base_p)
    (*this_id) = frame_id_build_unavailable_stack (cache->pc);
  else
    (*this_id) = frame_id_build (cache->base + 8, cache->pc);
}

static struct value *
i386_epilogue_frame_prev_register (struct frame_info *this_frame,
				   void **this_cache, int regnum)
{
  /* Make sure we've initialized the cache.  */
  i386_epilogue_frame_cache (this_frame, this_cache);

  return i386_frame_prev_register (this_frame, this_cache, regnum);
}

static const struct frame_unwind i386_epilogue_frame_unwind =
{
  NORMAL_FRAME,
  i386_epilogue_frame_unwind_stop_reason,
  i386_epilogue_frame_this_id,
  i386_epilogue_frame_prev_register,
  NULL, 
  i386_epilogue_frame_sniffer
};


/* Stack-based trampolines.  */

/* These trampolines are used on cross x86 targets, when taking the
   address of a nested function.  When executing these trampolines,
   no stack frame is set up, so we are in a similar situation as in
   epilogues and i386_epilogue_frame_this_id can be re-used.  */

/* Static chain passed in register.  */

struct i386_insn i386_tramp_chain_in_reg_insns[] =
{
  /* `movl imm32, %eax' and `movl imm32, %ecx' */
  { 5, { 0xb8 }, { 0xfe } },

  /* `jmp imm32' */
  { 5, { 0xe9 }, { 0xff } },

  {0}
};

/* Static chain passed on stack (when regparm=3).  */

struct i386_insn i386_tramp_chain_on_stack_insns[] =
{
  /* `push imm32' */
  { 5, { 0x68 }, { 0xff } },

  /* `jmp imm32' */
  { 5, { 0xe9 }, { 0xff } },

  {0}
};

/* Return whether PC points inside a stack trampoline.   */

static int
i386_in_stack_tramp_p (CORE_ADDR pc)
{
  gdb_byte insn;
  const char *name;

  /* A stack trampoline is detected if no name is associated
    to the current pc and if it points inside a trampoline
    sequence.  */

  find_pc_partial_function (pc, &name, NULL, NULL);
  if (name)
    return 0;

  if (target_read_memory (pc, &insn, 1))
    return 0;

  if (!i386_match_insn_block (pc, i386_tramp_chain_in_reg_insns)
      && !i386_match_insn_block (pc, i386_tramp_chain_on_stack_insns))
    return 0;

  return 1;
}

static int
i386_stack_tramp_frame_sniffer (const struct frame_unwind *self,
				struct frame_info *this_frame,
				void **this_cache)
{
  if (frame_relative_level (this_frame) == 0)
    return i386_in_stack_tramp_p (get_frame_pc (this_frame));
  else
    return 0;
}

static const struct frame_unwind i386_stack_tramp_frame_unwind =
{
  NORMAL_FRAME,
  i386_epilogue_frame_unwind_stop_reason,
  i386_epilogue_frame_this_id,
  i386_epilogue_frame_prev_register,
  NULL, 
  i386_stack_tramp_frame_sniffer
};

/* Generate a bytecode expression to get the value of the saved PC.  */

static void
i386_gen_return_address (struct gdbarch *gdbarch,
			 struct agent_expr *ax, struct axs_value *value,
			 CORE_ADDR scope)
{
  /* The following sequence assumes the traditional use of the base
     register.  */
  ax_reg (ax, I386_EBP_REGNUM);
  ax_const_l (ax, 4);
  ax_simple (ax, aop_add);
  value->type = register_type (gdbarch, I386_EIP_REGNUM);
  value->kind = axs_lvalue_memory;
}


/* Signal trampolines.  */

static struct i386_frame_cache *
i386_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
{
  struct gdbarch *gdbarch = get_frame_arch (this_frame);
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  struct i386_frame_cache *cache;
  CORE_ADDR addr;
  gdb_byte buf[4];

  if (*this_cache)
    return (struct i386_frame_cache *) *this_cache;

  cache = i386_alloc_frame_cache ();

  TRY
    {
      get_frame_register (this_frame, I386_ESP_REGNUM, buf);
      cache->base = extract_unsigned_integer (buf, 4, byte_order) - 4;

      addr = tdep->sigcontext_addr (this_frame);
      if (tdep->sc_reg_offset)
	{
	  int i;

	  gdb_assert (tdep->sc_num_regs <= I386_NUM_SAVED_REGS);

	  for (i = 0; i < tdep->sc_num_regs; i++)
	    if (tdep->sc_reg_offset[i] != -1)
	      cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
	}
      else
	{
	  cache->saved_regs[I386_EIP_REGNUM] = addr + tdep->sc_pc_offset;
	  cache->saved_regs[I386_ESP_REGNUM] = addr + tdep->sc_sp_offset;
	}

      cache->base_p = 1;
    }
  CATCH (ex, RETURN_MASK_ERROR)
    {
      if (ex.error != NOT_AVAILABLE_ERROR)
	throw_exception (ex);
    }
  END_CATCH

  *this_cache = cache;
  return cache;
}

static enum unwind_stop_reason
i386_sigtramp_frame_unwind_stop_reason (struct frame_info *this_frame,
					void **this_cache)
{
  struct i386_frame_cache *cache =
    i386_sigtramp_frame_cache (this_frame, this_cache);

  if (!cache->base_p)
    return UNWIND_UNAVAILABLE;

  return UNWIND_NO_REASON;
}

static void
i386_sigtramp_frame_this_id (struct frame_info *this_frame, void **this_cache,
			     struct frame_id *this_id)
{
  struct i386_frame_cache *cache =
    i386_sigtramp_frame_cache (this_frame, this_cache);

  if (!cache->base_p)
    (*this_id) = frame_id_build_unavailable_stack (get_frame_pc (this_frame));
  else
    {
      /* See the end of i386_push_dummy_call.  */
      (*this_id) = frame_id_build (cache->base + 8, get_frame_pc (this_frame));
    }
}

static struct value *
i386_sigtramp_frame_prev_register (struct frame_info *this_frame,
				   void **this_cache, int regnum)
{
  /* Make sure we've initialized the cache.  */
  i386_sigtramp_frame_cache (this_frame, this_cache);

  return i386_frame_prev_register (this_frame, this_cache, regnum);
}

static int
i386_sigtramp_frame_sniffer (const struct frame_unwind *self,
			     struct frame_info *this_frame,
			     void **this_prologue_cache)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));

  /* We shouldn't even bother if we don't have a sigcontext_addr
     handler.  */
  if (tdep->sigcontext_addr == NULL)
    return 0;

  if (tdep->sigtramp_p != NULL)
    {
      if (tdep->sigtramp_p (this_frame))
	return 1;
    }

  if (tdep->sigtramp_start != 0)
    {
      CORE_ADDR pc = get_frame_pc (this_frame);

      gdb_assert (tdep->sigtramp_end != 0);
      if (pc >= tdep->sigtramp_start && pc < tdep->sigtramp_end)
	return 1;
    }

  return 0;
}

static const struct frame_unwind i386_sigtramp_frame_unwind =
{
  SIGTRAMP_FRAME,
  i386_sigtramp_frame_unwind_stop_reason,
  i386_sigtramp_frame_this_id,
  i386_sigtramp_frame_prev_register,
  NULL,
  i386_sigtramp_frame_sniffer
};


static CORE_ADDR
i386_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
  struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache);

  return cache->base;
}

static const struct frame_base i386_frame_base =
{
  &i386_frame_unwind,
  i386_frame_base_address,
  i386_frame_base_address,
  i386_frame_base_address
};

static struct frame_id
i386_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
  CORE_ADDR fp;

  fp = get_frame_register_unsigned (this_frame, I386_EBP_REGNUM);

  /* See the end of i386_push_dummy_call.  */
  return frame_id_build (fp + 8, get_frame_pc (this_frame));
}

/* _Decimal128 function return values need 16-byte alignment on the
   stack.  */

static CORE_ADDR
i386_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
{
  return sp & -(CORE_ADDR)16;
}


/* Figure out where the longjmp will land.  Slurp the args out of the
   stack.  We expect the first arg to be a pointer to the jmp_buf
   structure from which we extract the address that we will land at.
   This address is copied into PC.  This routine returns non-zero on
   success.  */

static int
i386_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
{
  gdb_byte buf[4];
  CORE_ADDR sp, jb_addr;
  struct gdbarch *gdbarch = get_frame_arch (frame);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  int jb_pc_offset = gdbarch_tdep (gdbarch)->jb_pc_offset;

  /* If JB_PC_OFFSET is -1, we have no way to find out where the
     longjmp will land.  */
  if (jb_pc_offset == -1)
    return 0;

  get_frame_register (frame, I386_ESP_REGNUM, buf);
  sp = extract_unsigned_integer (buf, 4, byte_order);
  if (target_read_memory (sp + 4, buf, 4))
    return 0;

  jb_addr = extract_unsigned_integer (buf, 4, byte_order);
  if (target_read_memory (jb_addr + jb_pc_offset, buf, 4))
    return 0;

  *pc = extract_unsigned_integer (buf, 4, byte_order);
  return 1;
}


/* Check whether TYPE must be 16-byte-aligned when passed as a
   function argument.  16-byte vectors, _Decimal128 and structures or
   unions containing such types must be 16-byte-aligned; other
   arguments are 4-byte-aligned.  */

static int
i386_16_byte_align_p (struct type *type)
{
  type = check_typedef (type);
  if ((TYPE_CODE (type) == TYPE_CODE_DECFLOAT
       || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)))
      && TYPE_LENGTH (type) == 16)
    return 1;
  if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
    return i386_16_byte_align_p (TYPE_TARGET_TYPE (type));
  if (TYPE_CODE (type) == TYPE_CODE_STRUCT
      || TYPE_CODE (type) == TYPE_CODE_UNION)
    {
      int i;
      for (i = 0; i < TYPE_NFIELDS (type); i++)
	{
	  if (i386_16_byte_align_p (TYPE_FIELD_TYPE (type, i)))
	    return 1;
	}
    }
  return 0;
}

/* Implementation for set_gdbarch_push_dummy_code.  */

static CORE_ADDR
i386_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
		      struct value **args, int nargs, struct type *value_type,
		      CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
		      struct regcache *regcache)
{
  /* Use 0xcc breakpoint - 1 byte.  */
  *bp_addr = sp - 1;
  *real_pc = funaddr;

  /* Keep the stack aligned.  */
  return sp - 16;
}

static CORE_ADDR
i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
		      struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
		      struct value **args, CORE_ADDR sp, int struct_return,
		      CORE_ADDR struct_addr)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  gdb_byte buf[4];
  int i;
  int write_pass;
  int args_space = 0;

  /* BND registers can be in arbitrary values at the moment of the
     inferior call.  This can cause boundary violations that are not
     due to a real bug or even desired by the user.  The best to be done
     is set the BND registers to allow access to the whole memory, INIT
     state, before pushing the inferior call.   */
  i387_reset_bnd_regs (gdbarch, regcache);

  /* Determine the total space required for arguments and struct
     return address in a first pass (allowing for 16-byte-aligned
     arguments), then push arguments in a second pass.  */

  for (write_pass = 0; write_pass < 2; write_pass++)
    {
      int args_space_used = 0;

      if (struct_return)
	{
	  if (write_pass)
	    {
	      /* Push value address.  */
	      store_unsigned_integer (buf, 4, byte_order, struct_addr);
	      write_memory (sp, buf, 4);
	      args_space_used += 4;
	    }
	  else
	    args_space += 4;
	}

      for (i = 0; i < nargs; i++)
	{
	  int len = TYPE_LENGTH (value_enclosing_type (args[i]));

	  if (write_pass)
	    {
	      if (i386_16_byte_align_p (value_enclosing_type (args[i])))
		args_space_used = align_up (args_space_used, 16);

	      write_memory (sp + args_space_used,
			    value_contents_all (args[i]), len);
	      /* The System V ABI says that:

	      "An argument's size is increased, if necessary, to make it a
	      multiple of [32-bit] words.  This may require tail padding,
	      depending on the size of the argument."

	      This makes sure the stack stays word-aligned.  */
	      args_space_used += align_up (len, 4);
	    }
	  else
	    {
	      if (i386_16_byte_align_p (value_enclosing_type (args[i])))
		args_space = align_up (args_space, 16);
	      args_space += align_up (len, 4);
	    }
	}

      if (!write_pass)
	{
	  sp -= args_space;

	  /* The original System V ABI only requires word alignment,
	     but modern incarnations need 16-byte alignment in order
	     to support SSE.  Since wasting a few bytes here isn't
	     harmful we unconditionally enforce 16-byte alignment.  */
	  sp &= ~0xf;
	}
    }

  /* Store return address.  */
  sp -= 4;
  store_unsigned_integer (buf, 4, byte_order, bp_addr);
  write_memory (sp, buf, 4);

  /* Finally, update the stack pointer...  */
  store_unsigned_integer (buf, 4, byte_order, sp);
  regcache_cooked_write (regcache, I386_ESP_REGNUM, buf);

  /* ...and fake a frame pointer.  */
  regcache_cooked_write (regcache, I386_EBP_REGNUM, buf);

  /* MarkK wrote: This "+ 8" is all over the place:
     (i386_frame_this_id, i386_sigtramp_frame_this_id,
     i386_dummy_id).  It's there, since all frame unwinders for
     a given target have to agree (within a certain margin) on the
     definition of the stack address of a frame.  Otherwise frame id
     comparison might not work correctly.  Since DWARF2/GCC uses the
     stack address *before* the function call as a frame's CFA.  On
     the i386, when %ebp is used as a frame pointer, the offset
     between the contents %ebp and the CFA as defined by GCC.  */
  return sp + 8;
}

/* These registers are used for returning integers (and on some
   targets also for returning `struct' and `union' values when their
   size and alignment match an integer type).  */
#define LOW_RETURN_REGNUM	I386_EAX_REGNUM /* %eax */
#define HIGH_RETURN_REGNUM	I386_EDX_REGNUM /* %edx */

/* Read, for architecture GDBARCH, a function return value of TYPE
   from REGCACHE, and copy that into VALBUF.  */

static void
i386_extract_return_value (struct gdbarch *gdbarch, struct type *type,
			   struct regcache *regcache, gdb_byte *valbuf)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int len = TYPE_LENGTH (type);
  gdb_byte buf[I386_MAX_REGISTER_SIZE];

  if (TYPE_CODE (type) == TYPE_CODE_FLT)
    {
      if (tdep->st0_regnum < 0)
	{
	  warning (_("Cannot find floating-point return value."));
	  memset (valbuf, 0, len);
	  return;
	}

      /* Floating-point return values can be found in %st(0).  Convert
	 its contents to the desired type.  This is probably not
	 exactly how it would happen on the target itself, but it is
	 the best we can do.  */
      regcache_raw_read (regcache, I386_ST0_REGNUM, buf);
      target_float_convert (buf, i387_ext_type (gdbarch), valbuf, type);
    }
  else
    {
      int low_size = register_size (gdbarch, LOW_RETURN_REGNUM);
      int high_size = register_size (gdbarch, HIGH_RETURN_REGNUM);

      if (len <= low_size)
	{
	  regcache_raw_read (regcache, LOW_RETURN_REGNUM, buf);
	  memcpy (valbuf, buf, len);
	}
      else if (len <= (low_size + high_size))
	{
	  regcache_raw_read (regcache, LOW_RETURN_REGNUM, buf);
	  memcpy (valbuf, buf, low_size);
	  regcache_raw_read (regcache, HIGH_RETURN_REGNUM, buf);
	  memcpy (valbuf + low_size, buf, len - low_size);
	}
      else
	internal_error (__FILE__, __LINE__,
			_("Cannot extract return value of %d bytes long."),
			len);
    }
}

/* Write, for architecture GDBARCH, a function return value of TYPE
   from VALBUF into REGCACHE.  */

static void
i386_store_return_value (struct gdbarch *gdbarch, struct type *type,
			 struct regcache *regcache, const gdb_byte *valbuf)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int len = TYPE_LENGTH (type);

  if (TYPE_CODE (type) == TYPE_CODE_FLT)
    {
      ULONGEST fstat;
      gdb_byte buf[I386_MAX_REGISTER_SIZE];

      if (tdep->st0_regnum < 0)
	{
	  warning (_("Cannot set floating-point return value."));
	  return;
	}

      /* Returning floating-point values is a bit tricky.  Apart from
         storing the return value in %st(0), we have to simulate the
         state of the FPU at function return point.  */

      /* Convert the value found in VALBUF to the extended
	 floating-point format used by the FPU.  This is probably
	 not exactly how it would happen on the target itself, but
	 it is the best we can do.  */
      target_float_convert (valbuf, type, buf, i387_ext_type (gdbarch));
      regcache_raw_write (regcache, I386_ST0_REGNUM, buf);

      /* Set the top of the floating-point register stack to 7.  The
         actual value doesn't really matter, but 7 is what a normal
         function return would end up with if the program started out
         with a freshly initialized FPU.  */
      regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM (tdep), &fstat);
      fstat |= (7 << 11);
      regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM (tdep), fstat);

      /* Mark %st(1) through %st(7) as empty.  Since we set the top of
         the floating-point register stack to 7, the appropriate value
         for the tag word is 0x3fff.  */
      regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM (tdep), 0x3fff);
    }
  else
    {
      int low_size = register_size (gdbarch, LOW_RETURN_REGNUM);
      int high_size = register_size (gdbarch, HIGH_RETURN_REGNUM);

      if (len <= low_size)
	regcache_raw_write_part (regcache, LOW_RETURN_REGNUM, 0, len, valbuf);
      else if (len <= (low_size + high_size))
	{
	  regcache_raw_write (regcache, LOW_RETURN_REGNUM, valbuf);
	  regcache_raw_write_part (regcache, HIGH_RETURN_REGNUM, 0,
				   len - low_size, valbuf + low_size);
	}
      else
	internal_error (__FILE__, __LINE__,
			_("Cannot store return value of %d bytes long."), len);
    }
}


/* This is the variable that is set with "set struct-convention", and
   its legitimate values.  */
static const char default_struct_convention[] = "default";
static const char pcc_struct_convention[] = "pcc";
static const char reg_struct_convention[] = "reg";
static const char *const valid_conventions[] =
{
  default_struct_convention,
  pcc_struct_convention,
  reg_struct_convention,
  NULL
};
static const char *struct_convention = default_struct_convention;

/* Return non-zero if TYPE, which is assumed to be a structure,
   a union type, or an array type, should be returned in registers
   for architecture GDBARCH.  */

static int
i386_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  enum type_code code = TYPE_CODE (type);
  int len = TYPE_LENGTH (type);

  gdb_assert (code == TYPE_CODE_STRUCT
              || code == TYPE_CODE_UNION
              || code == TYPE_CODE_ARRAY);

  if (struct_convention == pcc_struct_convention
      || (struct_convention == default_struct_convention
	  && tdep->struct_return == pcc_struct_return))
    return 0;

  /* Structures consisting of a single `float', `double' or 'long
     double' member are returned in %st(0).  */
  if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
    {
      type = check_typedef (TYPE_FIELD_TYPE (type, 0));
      if (TYPE_CODE (type) == TYPE_CODE_FLT)
	return (len == 4 || len == 8 || len == 12);
    }

  return (len == 1 || len == 2 || len == 4 || len == 8);
}

/* Determine, for architecture GDBARCH, how a return value of TYPE
   should be returned.  If it is supposed to be returned in registers,
   and READBUF is non-zero, read the appropriate value from REGCACHE,
   and copy it into READBUF.  If WRITEBUF is non-zero, write the value
   from WRITEBUF into REGCACHE.  */

static enum return_value_convention
i386_return_value (struct gdbarch *gdbarch, struct value *function,
		   struct type *type, struct regcache *regcache,
		   gdb_byte *readbuf, const gdb_byte *writebuf)
{
  enum type_code code = TYPE_CODE (type);

  if (((code == TYPE_CODE_STRUCT
	|| code == TYPE_CODE_UNION
	|| code == TYPE_CODE_ARRAY)
       && !i386_reg_struct_return_p (gdbarch, type))
      /* Complex double and long double uses the struct return covention.  */
      || (code == TYPE_CODE_COMPLEX && TYPE_LENGTH (type) == 16)
      || (code == TYPE_CODE_COMPLEX && TYPE_LENGTH (type) == 24)
      /* 128-bit decimal float uses the struct return convention.  */
      || (code == TYPE_CODE_DECFLOAT && TYPE_LENGTH (type) == 16))
    {
      /* The System V ABI says that:

	 "A function that returns a structure or union also sets %eax
	 to the value of the original address of the caller's area
	 before it returns.  Thus when the caller receives control
	 again, the address of the returned object resides in register
	 %eax and can be used to access the object."

	 So the ABI guarantees that we can always find the return
	 value just after the function has returned.  */

      /* Note that the ABI doesn't mention functions returning arrays,
         which is something possible in certain languages such as Ada.
         In this case, the value is returned as if it was wrapped in
         a record, so the convention applied to records also applies
         to arrays.  */

      if (readbuf)
	{
	  ULONGEST addr;

	  regcache_raw_read_unsigned (regcache, I386_EAX_REGNUM, &addr);
	  read_memory (addr, readbuf, TYPE_LENGTH (type));
	}

      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
    }

  /* This special case is for structures consisting of a single
     `float', `double' or 'long double' member.  These structures are
     returned in %st(0).  For these structures, we call ourselves
     recursively, changing TYPE into the type of the first member of
     the structure.  Since that should work for all structures that
     have only one member, we don't bother to check the member's type
     here.  */
  if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
    {
      type = check_typedef (TYPE_FIELD_TYPE (type, 0));
      return i386_return_value (gdbarch, function, type, regcache,
				readbuf, writebuf);
    }

  if (readbuf)
    i386_extract_return_value (gdbarch, type, regcache, readbuf);
  if (writebuf)
    i386_store_return_value (gdbarch, type, regcache, writebuf);

  return RETURN_VALUE_REGISTER_CONVENTION;
}


struct type *
i387_ext_type (struct gdbarch *gdbarch)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  if (!tdep->i387_ext_type)
    {
      tdep->i387_ext_type = tdesc_find_type (gdbarch, "i387_ext");
      gdb_assert (tdep->i387_ext_type != NULL);
    }

  return tdep->i387_ext_type;
}

/* Construct type for pseudo BND registers.  We can't use
   tdesc_find_type since a complement of one value has to be used
   to describe the upper bound.  */

static struct type *
i386_bnd_type (struct gdbarch *gdbarch)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);


  if (!tdep->i386_bnd_type)
    {
      struct type *t;
      const struct builtin_type *bt = builtin_type (gdbarch);

      /* The type we're building is described bellow:  */
#if 0
      struct __bound128
      {
	void *lbound;
	void *ubound;		/* One complement of raw ubound field.  */
      };
#endif

      t = arch_composite_type (gdbarch,
			       "__gdb_builtin_type_bound128", TYPE_CODE_STRUCT);

      append_composite_type_field (t, "lbound", bt->builtin_data_ptr);
      append_composite_type_field (t, "ubound", bt->builtin_data_ptr);

      TYPE_NAME (t) = "builtin_type_bound128";
      tdep->i386_bnd_type = t;
    }

  return tdep->i386_bnd_type;
}

/* Construct vector type for pseudo ZMM registers.  We can't use
   tdesc_find_type since ZMM isn't described in target description.  */

static struct type *
i386_zmm_type (struct gdbarch *gdbarch)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  if (!tdep->i386_zmm_type)
    {
      const struct builtin_type *bt = builtin_type (gdbarch);

      /* The type we're building is this:  */
#if 0
      union __gdb_builtin_type_vec512i
      {
	int128_t uint128[4];
	int64_t v4_int64[8];
	int32_t v8_int32[16];
	int16_t v16_int16[32];
	int8_t v32_int8[64];
	double v4_double[8];
	float v8_float[16];
      };
#endif

      struct type *t;

      t = arch_composite_type (gdbarch,
			       "__gdb_builtin_type_vec512i", TYPE_CODE_UNION);
      append_composite_type_field (t, "v16_float",
				   init_vector_type (bt->builtin_float, 16));
      append_composite_type_field (t, "v8_double",
				   init_vector_type (bt->builtin_double, 8));
      append_composite_type_field (t, "v64_int8",
				   init_vector_type (bt->builtin_int8, 64));
      append_composite_type_field (t, "v32_int16",
				   init_vector_type (bt->builtin_int16, 32));
      append_composite_type_field (t, "v16_int32",
				   init_vector_type (bt->builtin_int32, 16));
      append_composite_type_field (t, "v8_int64",
				   init_vector_type (bt->builtin_int64, 8));
      append_composite_type_field (t, "v4_int128",
				   init_vector_type (bt->builtin_int128, 4));

      TYPE_VECTOR (t) = 1;
      TYPE_NAME (t) = "builtin_type_vec512i";
      tdep->i386_zmm_type = t;
    }

  return tdep->i386_zmm_type;
}

/* Construct vector type for pseudo YMM registers.  We can't use
   tdesc_find_type since YMM isn't described in target description.  */

static struct type *
i386_ymm_type (struct gdbarch *gdbarch)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  if (!tdep->i386_ymm_type)
    {
      const struct builtin_type *bt = builtin_type (gdbarch);

      /* The type we're building is this: */
#if 0
      union __gdb_builtin_type_vec256i
      {
        int128_t uint128[2];
        int64_t v2_int64[4];
        int32_t v4_int32[8];
        int16_t v8_int16[16];
        int8_t v16_int8[32];
        double v2_double[4];
        float v4_float[8];
      };
#endif

      struct type *t;

      t = arch_composite_type (gdbarch,
			       "__gdb_builtin_type_vec256i", TYPE_CODE_UNION);
      append_composite_type_field (t, "v8_float",
				   init_vector_type (bt->builtin_float, 8));
      append_composite_type_field (t, "v4_double",
				   init_vector_type (bt->builtin_double, 4));
      append_composite_type_field (t, "v32_int8",
				   init_vector_type (bt->builtin_int8, 32));
      append_composite_type_field (t, "v16_int16",
				   init_vector_type (bt->builtin_int16, 16));
      append_composite_type_field (t, "v8_int32",
				   init_vector_type (bt->builtin_int32, 8));
      append_composite_type_field (t, "v4_int64",
				   init_vector_type (bt->builtin_int64, 4));
      append_composite_type_field (t, "v2_int128",
				   init_vector_type (bt->builtin_int128, 2));

      TYPE_VECTOR (t) = 1;
      TYPE_NAME (t) = "builtin_type_vec256i";
      tdep->i386_ymm_type = t;
    }

  return tdep->i386_ymm_type;
}

/* Construct vector type for MMX registers.  */
static struct type *
i386_mmx_type (struct gdbarch *gdbarch)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  if (!tdep->i386_mmx_type)
    {
      const struct builtin_type *bt = builtin_type (gdbarch);

      /* The type we're building is this: */
#if 0
      union __gdb_builtin_type_vec64i
      {
        int64_t uint64;
        int32_t v2_int32[2];
        int16_t v4_int16[4];
        int8_t v8_int8[8];
      };
#endif

      struct type *t;

      t = arch_composite_type (gdbarch,
			       "__gdb_builtin_type_vec64i", TYPE_CODE_UNION);

      append_composite_type_field (t, "uint64", bt->builtin_int64);
      append_composite_type_field (t, "v2_int32",
				   init_vector_type (bt->builtin_int32, 2));
      append_composite_type_field (t, "v4_int16",
				   init_vector_type (bt->builtin_int16, 4));
      append_composite_type_field (t, "v8_int8",
				   init_vector_type (bt->builtin_int8, 8));

      TYPE_VECTOR (t) = 1;
      TYPE_NAME (t) = "builtin_type_vec64i";
      tdep->i386_mmx_type = t;
    }

  return tdep->i386_mmx_type;
}

/* Return the GDB type object for the "standard" data type of data in
   register REGNUM.  */

struct type *
i386_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
{
  if (i386_bnd_regnum_p (gdbarch, regnum))
    return i386_bnd_type (gdbarch);
  if (i386_mmx_regnum_p (gdbarch, regnum))
    return i386_mmx_type (gdbarch);
  else if (i386_ymm_regnum_p (gdbarch, regnum))
    return i386_ymm_type (gdbarch);
  else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
    return i386_ymm_type (gdbarch);
  else if (i386_zmm_regnum_p (gdbarch, regnum))
    return i386_zmm_type (gdbarch);
  else
    {
      const struct builtin_type *bt = builtin_type (gdbarch);
      if (i386_byte_regnum_p (gdbarch, regnum))
	return bt->builtin_int8;
      else if (i386_word_regnum_p (gdbarch, regnum))
	return bt->builtin_int16;
      else if (i386_dword_regnum_p (gdbarch, regnum))
	return bt->builtin_int32;
      else if (i386_k_regnum_p (gdbarch, regnum))
	return bt->builtin_int64;
    }

  internal_error (__FILE__, __LINE__, _("invalid regnum"));
}

/* Map a cooked register onto a raw register or memory.  For the i386,
   the MMX registers need to be mapped onto floating point registers.  */

static int
i386_mmx_regnum_to_fp_regnum (struct regcache *regcache, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
  int mmxreg, fpreg;
  ULONGEST fstat;
  int tos;

  mmxreg = regnum - tdep->mm0_regnum;
  regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM (tdep), &fstat);
  tos = (fstat >> 11) & 0x7;
  fpreg = (mmxreg + tos) % 8;

  return (I387_ST0_REGNUM (tdep) + fpreg);
}

/* A helper function for us by i386_pseudo_register_read_value and
   amd64_pseudo_register_read_value.  It does all the work but reads
   the data into an already-allocated value.  */

void
i386_pseudo_register_read_into_value (struct gdbarch *gdbarch,
				      struct regcache *regcache,
				      int regnum,
				      struct value *result_value)
{
  gdb_byte raw_buf[I386_MAX_REGISTER_SIZE];
  enum register_status status;
  gdb_byte *buf = value_contents_raw (result_value);

  if (i386_mmx_regnum_p (gdbarch, regnum))
    {
      int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);

      /* Extract (always little endian).  */
      status = regcache_raw_read (regcache, fpnum, raw_buf);
      if (status != REG_VALID)
	mark_value_bytes_unavailable (result_value, 0,
				      TYPE_LENGTH (value_type (result_value)));
      else
	memcpy (buf, raw_buf, register_size (gdbarch, regnum));
    }
  else
    {
      struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
      if (i386_bnd_regnum_p (gdbarch, regnum))
	{
	  regnum -= tdep->bnd0_regnum;

	  /* Extract (always little endian).  Read lower 128bits.  */
	  status = regcache_raw_read (regcache,
				      I387_BND0R_REGNUM (tdep) + regnum,
				      raw_buf);
	  if (status != REG_VALID)
	    mark_value_bytes_unavailable (result_value, 0, 16);
	  else
	    {
	      enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
	      LONGEST upper, lower;
	      int size = TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr);

	      lower = extract_unsigned_integer (raw_buf, 8, byte_order);
	      upper = extract_unsigned_integer (raw_buf + 8, 8, byte_order);
	      upper = ~upper;

	      memcpy (buf, &lower, size);
	      memcpy (buf + size, &upper, size);
	    }
	}
      else if (i386_k_regnum_p (gdbarch, regnum))
	{
	  regnum -= tdep->k0_regnum;

	  /* Extract (always little endian).  */
	  status = regcache_raw_read (regcache,
				      tdep->k0_regnum + regnum,
				      raw_buf);
	  if (status != REG_VALID)
	    mark_value_bytes_unavailable (result_value, 0, 8);
	  else
	    memcpy (buf, raw_buf, 8);
	}
      else if (i386_zmm_regnum_p (gdbarch, regnum))
	{
	  regnum -= tdep->zmm0_regnum;

	  if (regnum < num_lower_zmm_regs)
	    {
	      /* Extract (always little endian).  Read lower 128bits.  */
	      status = regcache_raw_read (regcache,
					  I387_XMM0_REGNUM (tdep) + regnum,
					  raw_buf);
	      if (status != REG_VALID)
		mark_value_bytes_unavailable (result_value, 0, 16);
	      else
		memcpy (buf, raw_buf, 16);

	      /* Extract (always little endian).  Read upper 128bits.  */
	      status = regcache_raw_read (regcache,
					  tdep->ymm0h_regnum + regnum,
					  raw_buf);
	      if (status != REG_VALID)
		mark_value_bytes_unavailable (result_value, 16, 16);
	      else
		memcpy (buf + 16, raw_buf, 16);
	    }
	  else
	    {
	      /* Extract (always little endian).  Read lower 128bits.  */
	      status = regcache_raw_read (regcache,
					  I387_XMM16_REGNUM (tdep) + regnum
					  - num_lower_zmm_regs,
					  raw_buf);
	      if (status != REG_VALID)
		mark_value_bytes_unavailable (result_value, 0, 16);
	      else
		memcpy (buf, raw_buf, 16);

	      /* Extract (always little endian).  Read upper 128bits.  */
	      status = regcache_raw_read (regcache,
					  I387_YMM16H_REGNUM (tdep) + regnum
					  - num_lower_zmm_regs,
					  raw_buf);
	      if (status != REG_VALID)
		mark_value_bytes_unavailable (result_value, 16, 16);
	      else
		memcpy (buf + 16, raw_buf, 16);
	    }

	  /* Read upper 256bits.  */
	  status = regcache_raw_read (regcache,
				      tdep->zmm0h_regnum + regnum,
				      raw_buf);
	  if (status != REG_VALID)
	    mark_value_bytes_unavailable (result_value, 32, 32);
	  else
	    memcpy (buf + 32, raw_buf, 32);
	}
      else if (i386_ymm_regnum_p (gdbarch, regnum))
	{
	  regnum -= tdep->ymm0_regnum;

	  /* Extract (always little endian).  Read lower 128bits.  */
	  status = regcache_raw_read (regcache,
				      I387_XMM0_REGNUM (tdep) + regnum,
				      raw_buf);
	  if (status != REG_VALID)
	    mark_value_bytes_unavailable (result_value, 0, 16);
	  else
	    memcpy (buf, raw_buf, 16);
	  /* Read upper 128bits.  */
	  status = regcache_raw_read (regcache,
				      tdep->ymm0h_regnum + regnum,
				      raw_buf);
	  if (status != REG_VALID)
	    mark_value_bytes_unavailable (result_value, 16, 32);
	  else
	    memcpy (buf + 16, raw_buf, 16);
	}
      else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
	{
	  regnum -= tdep->ymm16_regnum;
	  /* Extract (always little endian).  Read lower 128bits.  */
	  status = regcache_raw_read (regcache,
				      I387_XMM16_REGNUM (tdep) + regnum,
				      raw_buf);
	  if (status != REG_VALID)
	    mark_value_bytes_unavailable (result_value, 0, 16);
	  else
	    memcpy (buf, raw_buf, 16);
	  /* Read upper 128bits.  */
	  status = regcache_raw_read (regcache,
				      tdep->ymm16h_regnum + regnum,
				      raw_buf);
	  if (status != REG_VALID)
	    mark_value_bytes_unavailable (result_value, 16, 16);
	  else
	    memcpy (buf + 16, raw_buf, 16);
	}
      else if (i386_word_regnum_p (gdbarch, regnum))
	{
	  int gpnum = regnum - tdep->ax_regnum;

	  /* Extract (always little endian).  */
	  status = regcache_raw_read (regcache, gpnum, raw_buf);
	  if (status != REG_VALID)
	    mark_value_bytes_unavailable (result_value, 0,
					  TYPE_LENGTH (value_type (result_value)));
	  else
	    memcpy (buf, raw_buf, 2);
	}
      else if (i386_byte_regnum_p (gdbarch, regnum))
	{
	  int gpnum = regnum - tdep->al_regnum;

	  /* Extract (always little endian).  We read both lower and
	     upper registers.  */
	  status = regcache_raw_read (regcache, gpnum % 4, raw_buf);
	  if (status != REG_VALID)
	    mark_value_bytes_unavailable (result_value, 0,
					  TYPE_LENGTH (value_type (result_value)));
	  else if (gpnum >= 4)
	    memcpy (buf, raw_buf + 1, 1);
	  else
	    memcpy (buf, raw_buf, 1);
	}
      else
	internal_error (__FILE__, __LINE__, _("invalid regnum"));
    }
}

static struct value *
i386_pseudo_register_read_value (struct gdbarch *gdbarch,
				 struct regcache *regcache,
				 int regnum)
{
  struct value *result;

  result = allocate_value (register_type (gdbarch, regnum));
  VALUE_LVAL (result) = lval_register;
  VALUE_REGNUM (result) = regnum;

  i386_pseudo_register_read_into_value (gdbarch, regcache, regnum, result);

  return result;
}

void
i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
			    int regnum, const gdb_byte *buf)
{
  gdb_byte raw_buf[I386_MAX_REGISTER_SIZE];

  if (i386_mmx_regnum_p (gdbarch, regnum))
    {
      int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);

      /* Read ...  */
      regcache_raw_read (regcache, fpnum, raw_buf);
      /* ... Modify ... (always little endian).  */
      memcpy (raw_buf, buf, register_size (gdbarch, regnum));
      /* ... Write.  */
      regcache_raw_write (regcache, fpnum, raw_buf);
    }
  else
    {
      struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

      if (i386_bnd_regnum_p (gdbarch, regnum))
	{
	  ULONGEST upper, lower;
	  int size = TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr);
	  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());

	  /* New values from input value.  */
	  regnum -= tdep->bnd0_regnum;
	  lower = extract_unsigned_integer (buf, size, byte_order);
	  upper = extract_unsigned_integer (buf + size, size, byte_order);

	  /* Fetching register buffer.  */
	  regcache_raw_read (regcache,
			     I387_BND0R_REGNUM (tdep) + regnum,
			     raw_buf);

	  upper = ~upper;

	  /* Set register bits.  */
	  memcpy (raw_buf, &lower, 8);
	  memcpy (raw_buf + 8, &upper, 8);


	  regcache_raw_write (regcache,
			      I387_BND0R_REGNUM (tdep) + regnum,
			      raw_buf);
	}
      else if (i386_k_regnum_p (gdbarch, regnum))
	{
	  regnum -= tdep->k0_regnum;

	  regcache_raw_write (regcache,
			      tdep->k0_regnum + regnum,
			      buf);
	}
      else if (i386_zmm_regnum_p (gdbarch, regnum))
	{
	  regnum -= tdep->zmm0_regnum;

	  if (regnum < num_lower_zmm_regs)
	    {
	      /* Write lower 128bits.  */
	      regcache_raw_write (regcache,
				  I387_XMM0_REGNUM (tdep) + regnum,
				  buf);
	      /* Write upper 128bits.  */
	      regcache_raw_write (regcache,
				  I387_YMM0_REGNUM (tdep) + regnum,
				  buf + 16);
	    }
	  else
	    {
	      /* Write lower 128bits.  */
	      regcache_raw_write (regcache,
				  I387_XMM16_REGNUM (tdep) + regnum
				  - num_lower_zmm_regs,
				  buf);
	      /* Write upper 128bits.  */
	      regcache_raw_write (regcache,
				  I387_YMM16H_REGNUM (tdep) + regnum
				  - num_lower_zmm_regs,
				  buf + 16);
	    }
	  /* Write upper 256bits.  */
	  regcache_raw_write (regcache,
			      tdep->zmm0h_regnum + regnum,
			      buf + 32);
	}
      else if (i386_ymm_regnum_p (gdbarch, regnum))
	{
	  regnum -= tdep->ymm0_regnum;

	  /* ... Write lower 128bits.  */
	  regcache_raw_write (regcache,
			     I387_XMM0_REGNUM (tdep) + regnum,
			     buf);
	  /* ... Write upper 128bits.  */
	  regcache_raw_write (regcache,
			     tdep->ymm0h_regnum + regnum,
			     buf + 16);
	}
      else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
	{
	  regnum -= tdep->ymm16_regnum;

	  /* ... Write lower 128bits.  */
	  regcache_raw_write (regcache,
			      I387_XMM16_REGNUM (tdep) + regnum,
			      buf);
	  /* ... Write upper 128bits.  */
	  regcache_raw_write (regcache,
			      tdep->ymm16h_regnum + regnum,
			      buf + 16);
	}
      else if (i386_word_regnum_p (gdbarch, regnum))
	{
	  int gpnum = regnum - tdep->ax_regnum;

	  /* Read ...  */
	  regcache_raw_read (regcache, gpnum, raw_buf);
	  /* ... Modify ... (always little endian).  */
	  memcpy (raw_buf, buf, 2);
	  /* ... Write.  */
	  regcache_raw_write (regcache, gpnum, raw_buf);
	}
      else if (i386_byte_regnum_p (gdbarch, regnum))
	{
	  int gpnum = regnum - tdep->al_regnum;

	  /* Read ...  We read both lower and upper registers.  */
	  regcache_raw_read (regcache, gpnum % 4, raw_buf);
	  /* ... Modify ... (always little endian).  */
	  if (gpnum >= 4)
	    memcpy (raw_buf + 1, buf, 1);
	  else
	    memcpy (raw_buf, buf, 1);
	  /* ... Write.  */
	  regcache_raw_write (regcache, gpnum % 4, raw_buf);
	}
      else
	internal_error (__FILE__, __LINE__, _("invalid regnum"));
    }
}

/* Implement the 'ax_pseudo_register_collect' gdbarch method.  */

int
i386_ax_pseudo_register_collect (struct gdbarch *gdbarch,
				 struct agent_expr *ax, int regnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  if (i386_mmx_regnum_p (gdbarch, regnum))
    {
      /* MMX to FPU register mapping depends on current TOS.  Let's just
	 not care and collect everything...  */
      int i;

      ax_reg_mask (ax, I387_FSTAT_REGNUM (tdep));
      for (i = 0; i < 8; i++)
	ax_reg_mask (ax, I387_ST0_REGNUM (tdep) + i);
      return 0;
    }
  else if (i386_bnd_regnum_p (gdbarch, regnum))
    {
      regnum -= tdep->bnd0_regnum;
      ax_reg_mask (ax, I387_BND0R_REGNUM (tdep) + regnum);
      return 0;
    }
  else if (i386_k_regnum_p (gdbarch, regnum))
    {
      regnum -= tdep->k0_regnum;
      ax_reg_mask (ax, tdep->k0_regnum + regnum);
      return 0;
    }
  else if (i386_zmm_regnum_p (gdbarch, regnum))
    {
      regnum -= tdep->zmm0_regnum;
      if (regnum < num_lower_zmm_regs)
	{
	  ax_reg_mask (ax, I387_XMM0_REGNUM (tdep) + regnum);
	  ax_reg_mask (ax, tdep->ymm0h_regnum + regnum);
	}
      else
	{
	  ax_reg_mask (ax, I387_XMM16_REGNUM (tdep) + regnum
			   - num_lower_zmm_regs);
	  ax_reg_mask (ax, I387_YMM16H_REGNUM (tdep) + regnum
			   - num_lower_zmm_regs);
	}
      ax_reg_mask (ax, tdep->zmm0h_regnum + regnum);
      return 0;
    }
  else if (i386_ymm_regnum_p (gdbarch, regnum))
    {
      regnum -= tdep->ymm0_regnum;
      ax_reg_mask (ax, I387_XMM0_REGNUM (tdep) + regnum);
      ax_reg_mask (ax, tdep->ymm0h_regnum + regnum);
      return 0;
    }
  else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
    {
      regnum -= tdep->ymm16_regnum;
      ax_reg_mask (ax, I387_XMM16_REGNUM (tdep) + regnum);
      ax_reg_mask (ax, tdep->ymm16h_regnum + regnum);
      return 0;
    }
  else if (i386_word_regnum_p (gdbarch, regnum))
    {
      int gpnum = regnum - tdep->ax_regnum;

      ax_reg_mask (ax, gpnum);
      return 0;
    }
  else if (i386_byte_regnum_p (gdbarch, regnum))
    {
      int gpnum = regnum - tdep->al_regnum;

      ax_reg_mask (ax, gpnum % 4);
      return 0;
    }
  else
    internal_error (__FILE__, __LINE__, _("invalid regnum"));
  return 1;
}


/* Return the register number of the register allocated by GCC after
   REGNUM, or -1 if there is no such register.  */

static int
i386_next_regnum (int regnum)
{
  /* GCC allocates the registers in the order:

     %eax, %edx, %ecx, %ebx, %esi, %edi, %ebp, %esp, ...

     Since storing a variable in %esp doesn't make any sense we return
     -1 for %ebp and for %esp itself.  */
  static int next_regnum[] =
  {
    I386_EDX_REGNUM,		/* Slot for %eax.  */
    I386_EBX_REGNUM,		/* Slot for %ecx.  */
    I386_ECX_REGNUM,		/* Slot for %edx.  */
    I386_ESI_REGNUM,		/* Slot for %ebx.  */
    -1, -1,			/* Slots for %esp and %ebp.  */
    I386_EDI_REGNUM,		/* Slot for %esi.  */
    I386_EBP_REGNUM		/* Slot for %edi.  */
  };

  if (regnum >= 0 && regnum < sizeof (next_regnum) / sizeof (next_regnum[0]))
    return next_regnum[regnum];

  return -1;
}

/* Return nonzero if a value of type TYPE stored in register REGNUM
   needs any special handling.  */

static int
i386_convert_register_p (struct gdbarch *gdbarch,
			 int regnum, struct type *type)
{
  int len = TYPE_LENGTH (type);

  /* Values may be spread across multiple registers.  Most debugging
     formats aren't expressive enough to specify the locations, so
     some heuristics is involved.  Right now we only handle types that
     have a length that is a multiple of the word size, since GCC
     doesn't seem to put any other types into registers.  */
  if (len > 4 && len % 4 == 0)
    {
      int last_regnum = regnum;

      while (len > 4)
	{
	  last_regnum = i386_next_regnum (last_regnum);
	  len -= 4;
	}

      if (last_regnum != -1)
	return 1;
    }

  return i387_convert_register_p (gdbarch, regnum, type);
}

/* Read a value of type TYPE from register REGNUM in frame FRAME, and
   return its contents in TO.  */

static int
i386_register_to_value (struct frame_info *frame, int regnum,
			struct type *type, gdb_byte *to,
			int *optimizedp, int *unavailablep)
{
  struct gdbarch *gdbarch = get_frame_arch (frame);
  int len = TYPE_LENGTH (type);

  if (i386_fp_regnum_p (gdbarch, regnum))
    return i387_register_to_value (frame, regnum, type, to,
				   optimizedp, unavailablep);

  /* Read a value spread across multiple registers.  */

  gdb_assert (len > 4 && len % 4 == 0);

  while (len > 0)
    {
      gdb_assert (regnum != -1);
      gdb_assert (register_size (gdbarch, regnum) == 4);

      if (!get_frame_register_bytes (frame, regnum, 0,
				     register_size (gdbarch, regnum),
				     to, optimizedp, unavailablep))
	return 0;

      regnum = i386_next_regnum (regnum);
      len -= 4;
      to += 4;
    }

  *optimizedp = *unavailablep = 0;
  return 1;
}

/* Write the contents FROM of a value of type TYPE into register
   REGNUM in frame FRAME.  */

static void
i386_value_to_register (struct frame_info *frame, int regnum,
			struct type *type, const gdb_byte *from)
{
  int len = TYPE_LENGTH (type);

  if (i386_fp_regnum_p (get_frame_arch (frame), regnum))
    {
      i387_value_to_register (frame, regnum, type, from);
      return;
    }

  /* Write a value spread across multiple registers.  */

  gdb_assert (len > 4 && len % 4 == 0);

  while (len > 0)
    {
      gdb_assert (regnum != -1);
      gdb_assert (register_size (get_frame_arch (frame), regnum) == 4);

      put_frame_register (frame, regnum, from);
      regnum = i386_next_regnum (regnum);
      len -= 4;
      from += 4;
    }
}

/* Supply register REGNUM from the buffer specified by GREGS and LEN
   in the general-purpose register set REGSET to register cache
   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */

void
i386_supply_gregset (const struct regset *regset, struct regcache *regcache,
		     int regnum, const void *gregs, size_t len)
{
  struct gdbarch *gdbarch = regcache->arch ();
  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  const gdb_byte *regs = (const gdb_byte *) gregs;
  int i;

  gdb_assert (len >= tdep->sizeof_gregset);

  for (i = 0; i < tdep->gregset_num_regs; i++)
    {
      if ((regnum == i || regnum == -1)
	  && tdep->gregset_reg_offset[i] != -1)
	regcache_raw_supply (regcache, i, regs + tdep->gregset_reg_offset[i]);
    }
}

/* Collect register REGNUM from the register cache REGCACHE and store
   it in the buffer specified by GREGS and LEN as described by the
   general-purpose register set REGSET.  If REGNUM is -1, do this for
   all registers in REGSET.  */

static void
i386_collect_gregset (const struct regset *regset,
		      const struct regcache *regcache,
		      int regnum, void *gregs, size_t len)
{
  struct gdbarch *gdbarch = regcache->arch ();
  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  gdb_byte *regs = (gdb_byte *) gregs;
  int i;

  gdb_assert (len >= tdep->sizeof_gregset);

  for (i = 0; i < tdep->gregset_num_regs; i++)
    {
      if ((regnum == i || regnum == -1)
	  && tdep->gregset_reg_offset[i] != -1)
	regcache_raw_collect (regcache, i, regs + tdep->gregset_reg_offset[i]);
    }
}

/* Supply register REGNUM from the buffer specified by FPREGS and LEN
   in the floating-point register set REGSET to register cache
   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */

static void
i386_supply_fpregset (const struct regset *regset, struct regcache *regcache,
		      int regnum, const void *fpregs, size_t len)
{
  struct gdbarch *gdbarch = regcache->arch ();
  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  if (len == I387_SIZEOF_FXSAVE)
    {
      i387_supply_fxsave (regcache, regnum, fpregs);
      return;
    }

  gdb_assert (len >= tdep->sizeof_fpregset);
  i387_supply_fsave (regcache, regnum, fpregs);
}

/* Collect register REGNUM from the register cache REGCACHE and store
   it in the buffer specified by FPREGS and LEN as described by the
   floating-point register set REGSET.  If REGNUM is -1, do this for
   all registers in REGSET.  */

static void
i386_collect_fpregset (const struct regset *regset,
		       const struct regcache *regcache,
		       int regnum, void *fpregs, size_t len)
{
  struct gdbarch *gdbarch = regcache->arch ();
  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  if (len == I387_SIZEOF_FXSAVE)
    {
      i387_collect_fxsave (regcache, regnum, fpregs);
      return;
    }

  gdb_assert (len >= tdep->sizeof_fpregset);
  i387_collect_fsave (regcache, regnum, fpregs);
}

/* Register set definitions.  */

const struct regset i386_gregset =
  {
    NULL, i386_supply_gregset, i386_collect_gregset
  };

const struct regset i386_fpregset =
  {
    NULL, i386_supply_fpregset, i386_collect_fpregset
  };

/* Default iterator over core file register note sections.  */

void
i386_iterate_over_regset_sections (struct gdbarch *gdbarch,
				   iterate_over_regset_sections_cb *cb,
				   void *cb_data,
				   const struct regcache *regcache)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  cb (".reg", tdep->sizeof_gregset, &i386_gregset, NULL, cb_data);
  if (tdep->sizeof_fpregset)
    cb (".reg2", tdep->sizeof_fpregset, tdep->fpregset, NULL, cb_data);
}


/* Stuff for WIN32 PE style DLL's but is pretty generic really.  */

CORE_ADDR
i386_pe_skip_trampoline_code (struct frame_info *frame,
			      CORE_ADDR pc, char *name)
{
  struct gdbarch *gdbarch = get_frame_arch (frame);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);

  /* jmp *(dest) */
  if (pc && read_memory_unsigned_integer (pc, 2, byte_order) == 0x25ff)
    {
      unsigned long indirect =
	read_memory_unsigned_integer (pc + 2, 4, byte_order);
      struct minimal_symbol *indsym =
	indirect ? lookup_minimal_symbol_by_pc (indirect).minsym : 0;
      const char *symname = indsym ? MSYMBOL_LINKAGE_NAME (indsym) : 0;

      if (symname)
	{
	  if (startswith (symname, "__imp_")
	      || startswith (symname, "_imp_"))
	    return name ? 1 :
		   read_memory_unsigned_integer (indirect, 4, byte_order);
	}
    }
  return 0;			/* Not a trampoline.  */
}


/* Return whether the THIS_FRAME corresponds to a sigtramp
   routine.  */

int
i386_sigtramp_p (struct frame_info *this_frame)
{
  CORE_ADDR pc = get_frame_pc (this_frame);
  const char *name;

  find_pc_partial_function (pc, &name, NULL, NULL);
  return (name && strcmp ("_sigtramp", name) == 0);
}


/* We have two flavours of disassembly.  The machinery on this page
   deals with switching between those.  */

static int
i386_print_insn (bfd_vma pc, struct disassemble_info *info)
{
  gdb_assert (disassembly_flavor == att_flavor
	      || disassembly_flavor == intel_flavor);

  info->disassembler_options = disassembly_flavor;

  return default_print_insn (pc, info);
}


/* There are a few i386 architecture variants that differ only
   slightly from the generic i386 target.  For now, we don't give them
   their own source file, but include them here.  As a consequence,
   they'll always be included.  */

/* System V Release 4 (SVR4).  */

/* Return whether THIS_FRAME corresponds to a SVR4 sigtramp
   routine.  */

static int
i386_svr4_sigtramp_p (struct frame_info *this_frame)
{
  CORE_ADDR pc = get_frame_pc (this_frame);
  const char *name;

  /* The origin of these symbols is currently unknown.  */
  find_pc_partial_function (pc, &name, NULL, NULL);
  return (name && (strcmp ("_sigreturn", name) == 0
		   || strcmp ("sigvechandler", name) == 0));
}

/* Assuming THIS_FRAME is for a SVR4 sigtramp routine, return the
   address of the associated sigcontext (ucontext) structure.  */

static CORE_ADDR
i386_svr4_sigcontext_addr (struct frame_info *this_frame)
{
  struct gdbarch *gdbarch = get_frame_arch (this_frame);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  gdb_byte buf[4];
  CORE_ADDR sp;

  get_frame_register (this_frame, I386_ESP_REGNUM, buf);
  sp = extract_unsigned_integer (buf, 4, byte_order);

  return read_memory_unsigned_integer (sp + 8, 4, byte_order);
}



/* Implementation of `gdbarch_stap_is_single_operand', as defined in
   gdbarch.h.  */

int
i386_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
{
  return (*s == '$' /* Literal number.  */
	  || (isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement.  */
	  || (*s == '(' && s[1] == '%') /* Register indirection.  */
	  || (*s == '%' && isalpha (s[1]))); /* Register access.  */
}

/* Helper function for i386_stap_parse_special_token.

   This function parses operands of the form `-8+3+1(%rbp)', which
   must be interpreted as `*(-8 + 3 - 1 + (void *) $eax)'.

   Return 1 if the operand was parsed successfully, zero
   otherwise.  */

static int
i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
				       struct stap_parse_info *p)
{
  const char *s = p->arg;

  if (isdigit (*s) || *s == '-' || *s == '+')
    {
      int got_minus[3];
      int i;
      long displacements[3];
      const char *start;
      char *regname;
      int len;
      struct stoken str;
      char *endp;

      got_minus[0] = 0;
      if (*s == '+')
	++s;
      else if (*s == '-')
	{
	  ++s;
	  got_minus[0] = 1;
	}

      if (!isdigit ((unsigned char) *s))
	return 0;

      displacements[0] = strtol (s, &endp, 10);
      s = endp;

      if (*s != '+' && *s != '-')
	{
	  /* We are not dealing with a triplet.  */
	  return 0;
	}

      got_minus[1] = 0;
      if (*s == '+')
	++s;
      else
	{
	  ++s;
	  got_minus[1] = 1;
	}

      if (!isdigit ((unsigned char) *s))
	return 0;

      displacements[1] = strtol (s, &endp, 10);
      s = endp;

      if (*s != '+' && *s != '-')
	{
	  /* We are not dealing with a triplet.  */
	  return 0;
	}

      got_minus[2] = 0;
      if (*s == '+')
	++s;
      else
	{
	  ++s;
	  got_minus[2] = 1;
	}

      if (!isdigit ((unsigned char) *s))
	return 0;

      displacements[2] = strtol (s, &endp, 10);
      s = endp;

      if (*s != '(' || s[1] != '%')
	return 0;

      s += 2;
      start = s;

      while (isalnum (*s))
	++s;

      if (*s++ != ')')
	return 0;

      len = s - start - 1;
      regname = (char *) alloca (len + 1);

      strncpy (regname, start, len);
      regname[len] = '\0';

      if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
	error (_("Invalid register name `%s' on expression `%s'."),
	       regname, p->saved_arg);

      for (i = 0; i < 3; i++)
	{
	  write_exp_elt_opcode (&p->pstate, OP_LONG);
	  write_exp_elt_type
	    (&p->pstate, builtin_type (gdbarch)->builtin_long);
	  write_exp_elt_longcst (&p->pstate, displacements[i]);
	  write_exp_elt_opcode (&p->pstate, OP_LONG);
	  if (got_minus[i])
	    write_exp_elt_opcode (&p->pstate, UNOP_NEG);
	}

      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
      str.ptr = regname;
      str.length = len;
      write_exp_string (&p->pstate, str);
      write_exp_elt_opcode (&p->pstate, OP_REGISTER);

      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
      write_exp_elt_type (&p->pstate,
			  builtin_type (gdbarch)->builtin_data_ptr);
      write_exp_elt_opcode (&p->pstate, UNOP_CAST);

      write_exp_elt_opcode (&p->pstate, BINOP_ADD);
      write_exp_elt_opcode (&p->pstate, BINOP_ADD);
      write_exp_elt_opcode (&p->pstate, BINOP_ADD);

      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
      write_exp_elt_type (&p->pstate,
			  lookup_pointer_type (p->arg_type));
      write_exp_elt_opcode (&p->pstate, UNOP_CAST);

      write_exp_elt_opcode (&p->pstate, UNOP_IND);

      p->arg = s;

      return 1;
    }

  return 0;
}

/* Helper function for i386_stap_parse_special_token.

   This function parses operands of the form `register base +
   (register index * size) + offset', as represented in
   `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.

   Return 1 if the operand was parsed successfully, zero
   otherwise.  */

static int
i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
					      struct stap_parse_info *p)
{
  const char *s = p->arg;

  if (isdigit (*s) || *s == '(' || *s == '-' || *s == '+')
    {
      int offset_minus = 0;
      long offset = 0;
      int size_minus = 0;
      long size = 0;
      const char *start;
      char *base;
      int len_base;
      char *index;
      int len_index;
      struct stoken base_token, index_token;

      if (*s == '+')
	++s;
      else if (*s == '-')
	{
	  ++s;
	  offset_minus = 1;
	}

      if (offset_minus && !isdigit (*s))
	return 0;

      if (isdigit (*s))
	{
	  char *endp;

	  offset = strtol (s, &endp, 10);
	  s = endp;
	}

      if (*s != '(' || s[1] != '%')
	return 0;

      s += 2;
      start = s;

      while (isalnum (*s))
	++s;

      if (*s != ',' || s[1] != '%')
	return 0;

      len_base = s - start;
      base = (char *) alloca (len_base + 1);
      strncpy (base, start, len_base);
      base[len_base] = '\0';

      if (user_reg_map_name_to_regnum (gdbarch, base, len_base) == -1)
	error (_("Invalid register name `%s' on expression `%s'."),
	       base, p->saved_arg);

      s += 2;
      start = s;

      while (isalnum (*s))
	++s;

      len_index = s - start;
      index = (char *) alloca (len_index + 1);
      strncpy (index, start, len_index);
      index[len_index] = '\0';

      if (user_reg_map_name_to_regnum (gdbarch, index, len_index) == -1)
	error (_("Invalid register name `%s' on expression `%s'."),
	       index, p->saved_arg);

      if (*s != ',' && *s != ')')
	return 0;

      if (*s == ',')
	{
	  char *endp;

	  ++s;
	  if (*s == '+')
	    ++s;
	  else if (*s == '-')
	    {
	      ++s;
	      size_minus = 1;
	    }

	  size = strtol (s, &endp, 10);
	  s = endp;

	  if (*s != ')')
	    return 0;
	}

      ++s;

      if (offset)
	{
	  write_exp_elt_opcode (&p->pstate, OP_LONG);
	  write_exp_elt_type (&p->pstate,
			      builtin_type (gdbarch)->builtin_long);
	  write_exp_elt_longcst (&p->pstate, offset);
	  write_exp_elt_opcode (&p->pstate, OP_LONG);
	  if (offset_minus)
	    write_exp_elt_opcode (&p->pstate, UNOP_NEG);
	}

      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
      base_token.ptr = base;
      base_token.length = len_base;
      write_exp_string (&p->pstate, base_token);
      write_exp_elt_opcode (&p->pstate, OP_REGISTER);

      if (offset)
	write_exp_elt_opcode (&p->pstate, BINOP_ADD);

      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
      index_token.ptr = index;
      index_token.length = len_index;
      write_exp_string (&p->pstate, index_token);
      write_exp_elt_opcode (&p->pstate, OP_REGISTER);

      if (size)
	{
	  write_exp_elt_opcode (&p->pstate, OP_LONG);
	  write_exp_elt_type (&p->pstate,
			      builtin_type (gdbarch)->builtin_long);
	  write_exp_elt_longcst (&p->pstate, size);
	  write_exp_elt_opcode (&p->pstate, OP_LONG);
	  if (size_minus)
	    write_exp_elt_opcode (&p->pstate, UNOP_NEG);
	  write_exp_elt_opcode (&p->pstate, BINOP_MUL);
	}

      write_exp_elt_opcode (&p->pstate, BINOP_ADD);

      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
      write_exp_elt_type (&p->pstate,
			  lookup_pointer_type (p->arg_type));
      write_exp_elt_opcode (&p->pstate, UNOP_CAST);

      write_exp_elt_opcode (&p->pstate, UNOP_IND);

      p->arg = s;

      return 1;
    }

  return 0;
}

/* Implementation of `gdbarch_stap_parse_special_token', as defined in
   gdbarch.h.  */

int
i386_stap_parse_special_token (struct gdbarch *gdbarch,
			       struct stap_parse_info *p)
{
  /* In order to parse special tokens, we use a state-machine that go
     through every known token and try to get a match.  */
  enum
    {
      TRIPLET,
      THREE_ARG_DISPLACEMENT,
      DONE
    };
  int current_state;

  current_state = TRIPLET;

  /* The special tokens to be parsed here are:

     - `register base + (register index * size) + offset', as represented
     in `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.

     - Operands of the form `-8+3+1(%rbp)', which must be interpreted as
     `*(-8 + 3 - 1 + (void *) $eax)'.  */

  while (current_state != DONE)
    {
      switch (current_state)
	{
	case TRIPLET:
	  if (i386_stap_parse_special_token_triplet (gdbarch, p))
	    return 1;
	  break;

	case THREE_ARG_DISPLACEMENT:
	  if (i386_stap_parse_special_token_three_arg_disp (gdbarch, p))
	    return 1;
	  break;
	}

      /* Advancing to the next state.  */
      ++current_state;
    }

  return 0;
}



/* gdbarch gnu_triplet_regexp method.  Both arches are acceptable as GDB always
   also supplies -m64 or -m32 by gdbarch_gcc_target_options.  */

static const char *
i386_gnu_triplet_regexp (struct gdbarch *gdbarch)
{
  return "(x86_64|i.86)";
}



/* Generic ELF.  */

void
i386_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
  static const char *const stap_integer_prefixes[] = { "$", NULL };
  static const char *const stap_register_prefixes[] = { "%", NULL };
  static const char *const stap_register_indirection_prefixes[] = { "(",
								    NULL };
  static const char *const stap_register_indirection_suffixes[] = { ")",
								    NULL };

  /* We typically use stabs-in-ELF with the SVR4 register numbering.  */
  set_gdbarch_stab_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);

  /* Registering SystemTap handlers.  */
  set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes);
  set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes);
  set_gdbarch_stap_register_indirection_prefixes (gdbarch,
					  stap_register_indirection_prefixes);
  set_gdbarch_stap_register_indirection_suffixes (gdbarch,
					  stap_register_indirection_suffixes);
  set_gdbarch_stap_is_single_operand (gdbarch,
				      i386_stap_is_single_operand);
  set_gdbarch_stap_parse_special_token (gdbarch,
					i386_stap_parse_special_token);
}

/* System V Release 4 (SVR4).  */

void
i386_svr4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  /* System V Release 4 uses ELF.  */
  i386_elf_init_abi (info, gdbarch);

  /* System V Release 4 has shared libraries.  */
  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);

  tdep->sigtramp_p = i386_svr4_sigtramp_p;
  tdep->sigcontext_addr = i386_svr4_sigcontext_addr;
  tdep->sc_pc_offset = 36 + 14 * 4;
  tdep->sc_sp_offset = 36 + 17 * 4;

  tdep->jb_pc_offset = 20;
}



/* i386 register groups.  In addition to the normal groups, add "mmx"
   and "sse".  */

static struct reggroup *i386_sse_reggroup;
static struct reggroup *i386_mmx_reggroup;

static void
i386_init_reggroups (void)
{
  i386_sse_reggroup = reggroup_new ("sse", USER_REGGROUP);
  i386_mmx_reggroup = reggroup_new ("mmx", USER_REGGROUP);
}

static void
i386_add_reggroups (struct gdbarch *gdbarch)
{
  reggroup_add (gdbarch, i386_sse_reggroup);
  reggroup_add (gdbarch, i386_mmx_reggroup);
  reggroup_add (gdbarch, general_reggroup);
  reggroup_add (gdbarch, float_reggroup);
  reggroup_add (gdbarch, all_reggroup);
  reggroup_add (gdbarch, save_reggroup);
  reggroup_add (gdbarch, restore_reggroup);
  reggroup_add (gdbarch, vector_reggroup);
  reggroup_add (gdbarch, system_reggroup);
}

int
i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
			  struct reggroup *group)
{
  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int fp_regnum_p, mmx_regnum_p, xmm_regnum_p, mxcsr_regnum_p,
      ymm_regnum_p, ymmh_regnum_p, ymm_avx512_regnum_p, ymmh_avx512_regnum_p,
      bndr_regnum_p, bnd_regnum_p, zmm_regnum_p, zmmh_regnum_p,
      mpx_ctrl_regnum_p, xmm_avx512_regnum_p,
      avx512_p, avx_p, sse_p, pkru_regnum_p;

  /* Don't include pseudo registers, except for MMX, in any register
     groups.  */
  if (i386_byte_regnum_p (gdbarch, regnum))
    return 0;

  if (i386_word_regnum_p (gdbarch, regnum))
    return 0;

  if (i386_dword_regnum_p (gdbarch, regnum))
    return 0;

  mmx_regnum_p = i386_mmx_regnum_p (gdbarch, regnum);
  if (group == i386_mmx_reggroup)
    return mmx_regnum_p;

  pkru_regnum_p = i386_pkru_regnum_p(gdbarch, regnum);
  xmm_regnum_p = i386_xmm_regnum_p (gdbarch, regnum);
  xmm_avx512_regnum_p = i386_xmm_avx512_regnum_p (gdbarch, regnum);
  mxcsr_regnum_p = i386_mxcsr_regnum_p (gdbarch, regnum);
  if (group == i386_sse_reggroup)
    return xmm_regnum_p || xmm_avx512_regnum_p || mxcsr_regnum_p;

  ymm_regnum_p = i386_ymm_regnum_p (gdbarch, regnum);
  ymm_avx512_regnum_p = i386_ymm_avx512_regnum_p (gdbarch, regnum);
  zmm_regnum_p = i386_zmm_regnum_p (gdbarch, regnum);

  avx512_p = ((tdep->xcr0 & X86_XSTATE_AVX_AVX512_MASK)
	      == X86_XSTATE_AVX_AVX512_MASK);
  avx_p = ((tdep->xcr0 & X86_XSTATE_AVX_AVX512_MASK)
	   == X86_XSTATE_AVX_MASK) && !avx512_p;
  sse_p = ((tdep->xcr0 & X86_XSTATE_AVX_AVX512_MASK)
	   == X86_XSTATE_SSE_MASK) && !avx512_p && ! avx_p;

  if (group == vector_reggroup)
    return (mmx_regnum_p
	    || (zmm_regnum_p && avx512_p)
	    || ((ymm_regnum_p || ymm_avx512_regnum_p) && avx_p)
	    || ((xmm_regnum_p || xmm_avx512_regnum_p) && sse_p)
	    || mxcsr_regnum_p);

  fp_regnum_p = (i386_fp_regnum_p (gdbarch, regnum)
		 || i386_fpc_regnum_p (gdbarch, regnum));
  if (group == float_reggroup)
    return fp_regnum_p;

  /* For "info reg all", don't include upper YMM registers nor XMM
     registers when AVX is supported.  */
  ymmh_regnum_p = i386_ymmh_regnum_p (gdbarch, regnum);
  ymmh_avx512_regnum_p = i386_ymmh_avx512_regnum_p (gdbarch, regnum);
  zmmh_regnum_p = i386_zmmh_regnum_p (gdbarch, regnum);
  if (group == all_reggroup
      && (((xmm_regnum_p || xmm_avx512_regnum_p) && !sse_p)
	  || ((ymm_regnum_p || ymm_avx512_regnum_p) && !avx_p)
	  || ymmh_regnum_p
	  || ymmh_avx512_regnum_p
	  || zmmh_regnum_p))
    return 0;

  bnd_regnum_p = i386_bnd_regnum_p (gdbarch, regnum);
  if (group == all_reggroup
      && ((bnd_regnum_p && (tdep->xcr0 & X86_XSTATE_MPX_MASK))))
    return bnd_regnum_p;

  bndr_regnum_p = i386_bndr_regnum_p (gdbarch, regnum);
  if (group == all_reggroup
      && ((bndr_regnum_p && (tdep->xcr0 & X86_XSTATE_MPX_MASK))))
    return 0;

  mpx_ctrl_regnum_p = i386_mpx_ctrl_regnum_p (gdbarch, regnum);
  if (group == all_reggroup
      && ((mpx_ctrl_regnum_p && (tdep->xcr0 & X86_XSTATE_MPX_MASK))))
    return mpx_ctrl_regnum_p;

  if (group == general_reggroup)
    return (!fp_regnum_p
	    && !mmx_regnum_p
	    && !mxcsr_regnum_p
	    && !xmm_regnum_p
	    && !xmm_avx512_regnum_p
	    && !ymm_regnum_p
	    && !ymmh_regnum_p
	    && !ymm_avx512_regnum_p
	    && !ymmh_avx512_regnum_p
	    && !bndr_regnum_p
	    && !bnd_regnum_p
	    && !mpx_ctrl_regnum_p
	    && !zmm_regnum_p
	    && !zmmh_regnum_p
	    && !pkru_regnum_p);

  return default_register_reggroup_p (gdbarch, regnum, group);
}


/* Get the ARGIth function argument for the current function.  */

static CORE_ADDR
i386_fetch_pointer_argument (struct frame_info *frame, int argi, 
			     struct type *type)
{
  struct gdbarch *gdbarch = get_frame_arch (frame);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  CORE_ADDR sp = get_frame_register_unsigned (frame, I386_ESP_REGNUM);
  return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4, byte_order);
}

#define PREFIX_REPZ	0x01
#define PREFIX_REPNZ	0x02
#define PREFIX_LOCK	0x04
#define PREFIX_DATA	0x08
#define PREFIX_ADDR	0x10

/* operand size */
enum
{
  OT_BYTE = 0,
  OT_WORD,
  OT_LONG,
  OT_QUAD,
  OT_DQUAD,
};

/* i386 arith/logic operations */
enum
{
  OP_ADDL,
  OP_ORL,
  OP_ADCL,
  OP_SBBL,
  OP_ANDL,
  OP_SUBL,
  OP_XORL,
  OP_CMPL,
};

struct i386_record_s
{
  struct gdbarch *gdbarch;
  struct regcache *regcache;
  CORE_ADDR orig_addr;
  CORE_ADDR addr;
  int aflag;
  int dflag;
  int override;
  uint8_t modrm;
  uint8_t mod, reg, rm;
  int ot;
  uint8_t rex_x;
  uint8_t rex_b;
  int rip_offset;
  int popl_esp_hack;
  const int *regmap;
};

/* Parse the "modrm" part of the memory address irp->addr points at.
   Returns -1 if something goes wrong, 0 otherwise.  */

static int
i386_record_modrm (struct i386_record_s *irp)
{
  struct gdbarch *gdbarch = irp->gdbarch;

  if (record_read_memory (gdbarch, irp->addr, &irp->modrm, 1))
    return -1;

  irp->addr++;
  irp->mod = (irp->modrm >> 6) & 3;
  irp->reg = (irp->modrm >> 3) & 7;
  irp->rm = irp->modrm & 7;

  return 0;
}

/* Extract the memory address that the current instruction writes to,
   and return it in *ADDR.  Return -1 if something goes wrong.  */

static int
i386_record_lea_modrm_addr (struct i386_record_s *irp, uint64_t *addr)
{
  struct gdbarch *gdbarch = irp->gdbarch;
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  gdb_byte buf[4];
  ULONGEST offset64;

  *addr = 0;
  if (irp->aflag || irp->regmap[X86_RECORD_R8_REGNUM])
    {
      /* 32/64 bits */
      int havesib = 0;
      uint8_t scale = 0;
      uint8_t byte;
      uint8_t index = 0;
      uint8_t base = irp->rm;

      if (base == 4)
	{
	  havesib = 1;
	  if (record_read_memory (gdbarch, irp->addr, &byte, 1))
	    return -1;
	  irp->addr++;
	  scale = (byte >> 6) & 3;
	  index = ((byte >> 3) & 7) | irp->rex_x;
	  base = (byte & 7);
	}
      base |= irp->rex_b;

      switch (irp->mod)
	{
	case 0:
	  if ((base & 7) == 5)
	    {
	      base = 0xff;
	      if (record_read_memory (gdbarch, irp->addr, buf, 4))
		return -1;
	      irp->addr += 4;
	      *addr = extract_signed_integer (buf, 4, byte_order);
	      if (irp->regmap[X86_RECORD_R8_REGNUM] && !havesib)
		*addr += irp->addr + irp->rip_offset;
	    }
	  break;
	case 1:
	  if (record_read_memory (gdbarch, irp->addr, buf, 1))
	    return -1;
	  irp->addr++;
	  *addr = (int8_t) buf[0];
	  break;
	case 2:
	  if (record_read_memory (gdbarch, irp->addr, buf, 4))
	    return -1;
	  *addr = extract_signed_integer (buf, 4, byte_order);
	  irp->addr += 4;
	  break;
	}

      offset64 = 0;
      if (base != 0xff)
        {
	  if (base == 4 && irp->popl_esp_hack)
	    *addr += irp->popl_esp_hack;
	  regcache_raw_read_unsigned (irp->regcache, irp->regmap[base],
                                      &offset64);
	}
      if (irp->aflag == 2)
        {
	  *addr += offset64;
        }
      else
        *addr = (uint32_t) (offset64 + *addr);

      if (havesib && (index != 4 || scale != 0))
	{
	  regcache_raw_read_unsigned (irp->regcache, irp->regmap[index],
                                      &offset64);
	  if (irp->aflag == 2)
	    *addr += offset64 << scale;
	  else
	    *addr = (uint32_t) (*addr + (offset64 << scale));
	}

      if (!irp->aflag)
	{
	  /* Since we are in 64-bit mode with ADDR32 prefix, zero-extend
	     address from 32-bit to 64-bit.  */
	    *addr = (uint32_t) *addr;
	}
    }
  else
    {
      /* 16 bits */
      switch (irp->mod)
	{
	case 0:
	  if (irp->rm == 6)
	    {
	      if (record_read_memory (gdbarch, irp->addr, buf, 2))
		return -1;
	      irp->addr += 2;
	      *addr = extract_signed_integer (buf, 2, byte_order);
	      irp->rm = 0;
	      goto no_rm;
	    }
	  break;
	case 1:
	  if (record_read_memory (gdbarch, irp->addr, buf, 1))
	    return -1;
	  irp->addr++;
	  *addr = (int8_t) buf[0];
	  break;
	case 2:
	  if (record_read_memory (gdbarch, irp->addr, buf, 2))
	    return -1;
	  irp->addr += 2;
	  *addr = extract_signed_integer (buf, 2, byte_order);
	  break;
	}

      switch (irp->rm)
	{
	case 0:
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_REBX_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_RESI_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  break;
	case 1:
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_REBX_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_REDI_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  break;
	case 2:
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_REBP_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_RESI_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  break;
	case 3:
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_REBP_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_REDI_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  break;
	case 4:
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_RESI_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  break;
	case 5:
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_REDI_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  break;
	case 6:
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_REBP_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  break;
	case 7:
	  regcache_raw_read_unsigned (irp->regcache,
				      irp->regmap[X86_RECORD_REBX_REGNUM],
                                      &offset64);
	  *addr = (uint32_t) (*addr + offset64);
	  break;
	}
      *addr &= 0xffff;
    }

 no_rm:
  return 0;
}

/* Record the address and contents of the memory that will be changed
   by the current instruction.  Return -1 if something goes wrong, 0
   otherwise.  */

static int
i386_record_lea_modrm (struct i386_record_s *irp)
{
  struct gdbarch *gdbarch = irp->gdbarch;
  uint64_t addr;

  if (irp->override >= 0)
    {
      if (record_full_memory_query)
        {
          if (yquery (_("\
Process record ignores the memory change of instruction at address %s\n\
because it can't get the value of the segment register.\n\
Do you want to stop the program?"),
                      paddress (gdbarch, irp->orig_addr)))
	    return -1;
        }

      return 0;
    }

  if (i386_record_lea_modrm_addr (irp, &addr))
    return -1;

  if (record_full_arch_list_add_mem (addr, 1 << irp->ot))
    return -1;

  return 0;
}

/* Record the effects of a push operation.  Return -1 if something
   goes wrong, 0 otherwise.  */

static int
i386_record_push (struct i386_record_s *irp, int size)
{
  ULONGEST addr;

  if (record_full_arch_list_add_reg (irp->regcache,
				     irp->regmap[X86_RECORD_RESP_REGNUM]))
    return -1;
  regcache_raw_read_unsigned (irp->regcache,
			      irp->regmap[X86_RECORD_RESP_REGNUM],
			      &addr);
  if (record_full_arch_list_add_mem ((CORE_ADDR) addr - size, size))
    return -1;

  return 0;
}


/* Defines contents to record.  */
#define I386_SAVE_FPU_REGS              0xfffd
#define I386_SAVE_FPU_ENV               0xfffe
#define I386_SAVE_FPU_ENV_REG_STACK     0xffff

/* Record the values of the floating point registers which will be
   changed by the current instruction.  Returns -1 if something is
   wrong, 0 otherwise.  */

static int i386_record_floats (struct gdbarch *gdbarch,
                               struct i386_record_s *ir,
                               uint32_t iregnum)
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  int i;

  /* Oza: Because of floating point insn push/pop of fpu stack is going to
     happen.  Currently we store st0-st7 registers, but we need not store all
     registers all the time, in future we use ftag register and record only
     those who are not marked as an empty.  */

  if (I386_SAVE_FPU_REGS == iregnum)
    {
      for (i = I387_ST0_REGNUM (tdep); i <= I387_ST0_REGNUM (tdep) + 7; i++)
        {
          if (record_full_arch_list_add_reg (ir->regcache, i))
            return -1;
        }
    }
  else if (I386_SAVE_FPU_ENV == iregnum)
    {
      for (i = I387_FCTRL_REGNUM (tdep); i <= I387_FOP_REGNUM (tdep); i++)
	      {
	      if (record_full_arch_list_add_reg (ir->regcache, i))
	        return -1;
	      }
    }
  else if (I386_SAVE_FPU_ENV_REG_STACK == iregnum)
    {
      for (i = I387_ST0_REGNUM (tdep); i <= I387_FOP_REGNUM (tdep); i++)
      {
        if (record_full_arch_list_add_reg (ir->regcache, i))
          return -1;
      }
    }
  else if ((iregnum >= I387_ST0_REGNUM (tdep)) &&
           (iregnum <= I387_FOP_REGNUM (tdep)))
    {
      if (record_full_arch_list_add_reg (ir->regcache,iregnum))
        return -1;
    }
  else
    {
      /* Parameter error.  */
      return -1;
    }
  if(I386_SAVE_FPU_ENV != iregnum)
    {
    for (i = I387_FCTRL_REGNUM (tdep); i <= I387_FOP_REGNUM (tdep); i++)
      {
      if (record_full_arch_list_add_reg (ir->regcache, i))
        return -1;
      }
    }
  return 0;
}

/* Parse the current instruction, and record the values of the
   registers and memory that will be changed by the current
   instruction.  Returns -1 if something goes wrong, 0 otherwise.  */

#define I386_RECORD_FULL_ARCH_LIST_ADD_REG(regnum) \
    record_full_arch_list_add_reg (ir.regcache, ir.regmap[(regnum)])

int
i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
		     CORE_ADDR input_addr)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  int prefixes = 0;
  int regnum = 0;
  uint32_t opcode;
  uint8_t opcode8;
  ULONGEST addr;
  gdb_byte buf[I386_MAX_REGISTER_SIZE];
  struct i386_record_s ir;
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  uint8_t rex_w = -1;
  uint8_t rex_r = 0;

  memset (&ir, 0, sizeof (struct i386_record_s));
  ir.regcache = regcache;
  ir.addr = input_addr;
  ir.orig_addr = input_addr;
  ir.aflag = 1;
  ir.dflag = 1;
  ir.override = -1;
  ir.popl_esp_hack = 0;
  ir.regmap = tdep->record_regmap;
  ir.gdbarch = gdbarch;

  if (record_debug > 1)
    fprintf_unfiltered (gdb_stdlog, "Process record: i386_process_record "
			            "addr = %s\n",
			paddress (gdbarch, ir.addr));

  /* prefixes */
  while (1)
    {
      if (record_read_memory (gdbarch, ir.addr, &opcode8, 1))
	return -1;
      ir.addr++;
      switch (opcode8)	/* Instruction prefixes */
	{
	case REPE_PREFIX_OPCODE:
	  prefixes |= PREFIX_REPZ;
	  break;
	case REPNE_PREFIX_OPCODE:
	  prefixes |= PREFIX_REPNZ;
	  break;
	case LOCK_PREFIX_OPCODE:
	  prefixes |= PREFIX_LOCK;
	  break;
	case CS_PREFIX_OPCODE:
	  ir.override = X86_RECORD_CS_REGNUM;
	  break;
	case SS_PREFIX_OPCODE:
	  ir.override = X86_RECORD_SS_REGNUM;
	  break;
	case DS_PREFIX_OPCODE:
	  ir.override = X86_RECORD_DS_REGNUM;
	  break;
	case ES_PREFIX_OPCODE:
	  ir.override = X86_RECORD_ES_REGNUM;
	  break;
	case FS_PREFIX_OPCODE:
	  ir.override = X86_RECORD_FS_REGNUM;
	  break;
	case GS_PREFIX_OPCODE:
	  ir.override = X86_RECORD_GS_REGNUM;
	  break;
	case DATA_PREFIX_OPCODE:
	  prefixes |= PREFIX_DATA;
	  break;
	case ADDR_PREFIX_OPCODE:
	  prefixes |= PREFIX_ADDR;
	  break;
        case 0x40:	/* i386 inc %eax */
        case 0x41:	/* i386 inc %ecx */
        case 0x42:	/* i386 inc %edx */
        case 0x43:	/* i386 inc %ebx */
        case 0x44:	/* i386 inc %esp */
        case 0x45:	/* i386 inc %ebp */
        case 0x46:	/* i386 inc %esi */
        case 0x47:	/* i386 inc %edi */
        case 0x48:	/* i386 dec %eax */
        case 0x49:	/* i386 dec %ecx */
        case 0x4a:	/* i386 dec %edx */
        case 0x4b:	/* i386 dec %ebx */
        case 0x4c:	/* i386 dec %esp */
        case 0x4d:	/* i386 dec %ebp */
        case 0x4e:	/* i386 dec %esi */
        case 0x4f:	/* i386 dec %edi */
          if (ir.regmap[X86_RECORD_R8_REGNUM])	/* 64 bit target */
            {
               /* REX */
               rex_w = (opcode8 >> 3) & 1;
               rex_r = (opcode8 & 0x4) << 1;
               ir.rex_x = (opcode8 & 0x2) << 2;
               ir.rex_b = (opcode8 & 0x1) << 3;
            }
	  else					/* 32 bit target */
	    goto out_prefixes;
          break;
	default:
	  goto out_prefixes;
	  break;
	}
    }
 out_prefixes:
  if (ir.regmap[X86_RECORD_R8_REGNUM] && rex_w == 1)
    {
      ir.dflag = 2;
    }
  else
    {
      if (prefixes & PREFIX_DATA)
        ir.dflag ^= 1;
    }
  if (prefixes & PREFIX_ADDR)
    ir.aflag ^= 1;
  else if (ir.regmap[X86_RECORD_R8_REGNUM])
    ir.aflag = 2;

  /* Now check op code.  */
  opcode = (uint32_t) opcode8;
 reswitch:
  switch (opcode)
    {
    case 0x0f:
      if (record_read_memory (gdbarch, ir.addr, &opcode8, 1))
	return -1;
      ir.addr++;
      opcode = (uint32_t) opcode8 | 0x0f00;
      goto reswitch;
      break;

    case 0x00:    /* arith & logic */
    case 0x01:
    case 0x02:
    case 0x03:
    case 0x04:
    case 0x05:
    case 0x08:
    case 0x09:
    case 0x0a:
    case 0x0b:
    case 0x0c:
    case 0x0d:
    case 0x10:
    case 0x11:
    case 0x12:
    case 0x13:
    case 0x14:
    case 0x15:
    case 0x18:
    case 0x19:
    case 0x1a:
    case 0x1b:
    case 0x1c:
    case 0x1d:
    case 0x20:
    case 0x21:
    case 0x22:
    case 0x23:
    case 0x24:
    case 0x25:
    case 0x28:
    case 0x29:
    case 0x2a:
    case 0x2b:
    case 0x2c:
    case 0x2d:
    case 0x30:
    case 0x31:
    case 0x32:
    case 0x33:
    case 0x34:
    case 0x35:
    case 0x38:
    case 0x39:
    case 0x3a:
    case 0x3b:
    case 0x3c:
    case 0x3d:
      if (((opcode >> 3) & 7) != OP_CMPL)
	{
	  if ((opcode & 1) == 0)
	    ir.ot = OT_BYTE;
	  else
	    ir.ot = ir.dflag + OT_WORD;

	  switch ((opcode >> 1) & 3)
	    {
	    case 0:    /* OP Ev, Gv */
	      if (i386_record_modrm (&ir))
		return -1;
	      if (ir.mod != 3)
		{
		  if (i386_record_lea_modrm (&ir))
		    return -1;
		}
	      else
		{
                  ir.rm |= ir.rex_b;
		  if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
		    ir.rm &= 0x3;
		  I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
		}
	      break;
	    case 1:    /* OP Gv, Ev */
	      if (i386_record_modrm (&ir))
		return -1;
              ir.reg |= rex_r;
	      if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
		ir.reg &= 0x3;
	      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
	      break;
	    case 2:    /* OP A, Iv */
	      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
	      break;
	    }
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x80:    /* GRP1 */
    case 0x81:
    case 0x82:
    case 0x83:
      if (i386_record_modrm (&ir))
	return -1;

      if (ir.reg != OP_CMPL)
	{
	  if ((opcode & 1) == 0)
	    ir.ot = OT_BYTE;
	  else
	    ir.ot = ir.dflag + OT_WORD;

	  if (ir.mod != 3)
	    {
              if (opcode == 0x83)
                ir.rip_offset = 1;
              else
                ir.rip_offset = (ir.ot > OT_LONG) ? 4 : (1 << ir.ot);
	      if (i386_record_lea_modrm (&ir))
		return -1;
	    }
	  else
	    I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x40:      /* inc */
    case 0x41:
    case 0x42:
    case 0x43:
    case 0x44:
    case 0x45:
    case 0x46:
    case 0x47:

    case 0x48:      /* dec */
    case 0x49:
    case 0x4a:
    case 0x4b:
    case 0x4c:
    case 0x4d:
    case 0x4e:
    case 0x4f:

      I386_RECORD_FULL_ARCH_LIST_ADD_REG (opcode & 7);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0xf6:    /* GRP3 */
    case 0xf7:
      if ((opcode & 1) == 0)
	ir.ot = OT_BYTE;
      else
	ir.ot = ir.dflag + OT_WORD;
      if (i386_record_modrm (&ir))
	return -1;

      if (ir.mod != 3 && ir.reg == 0)
        ir.rip_offset = (ir.ot > OT_LONG) ? 4 : (1 << ir.ot);

      switch (ir.reg)
	{
	case 0:    /* test */
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	case 2:    /* not */
	case 3:    /* neg */
	  if (ir.mod != 3)
	    {
	      if (i386_record_lea_modrm (&ir))
		return -1;
	    }
	  else
	    {
              ir.rm |= ir.rex_b;
	      if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
		ir.rm &= 0x3;
	      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
	    }
	  if (ir.reg == 3)  /* neg */
	    I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	case 4:    /* mul  */
	case 5:    /* imul */
	case 6:    /* div  */
	case 7:    /* idiv */
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
	  if (ir.ot != OT_BYTE)
	    I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	default:
	  ir.addr -= 2;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	  break;
	}
      break;

    case 0xfe:    /* GRP4 */
    case 0xff:    /* GRP5 */
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.reg >= 2 && opcode == 0xfe)
	{
	  ir.addr -= 2;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	}
      switch (ir.reg)
	{
	case 0:    /* inc */
	case 1:    /* dec */
          if ((opcode & 1) == 0)
	    ir.ot = OT_BYTE;
          else
	    ir.ot = ir.dflag + OT_WORD;
	  if (ir.mod != 3)
	    {
	      if (i386_record_lea_modrm (&ir))
		return -1;
	    }
	  else
	    {
	      ir.rm |= ir.rex_b;
	      if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
		ir.rm &= 0x3;
	      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
	    }
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	case 2:    /* call */
          if (ir.regmap[X86_RECORD_R8_REGNUM] && ir.dflag)
            ir.dflag = 2;
	  if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
	    return -1;
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	case 3:    /* lcall */
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_CS_REGNUM);
	  if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
	    return -1;
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	case 4:    /* jmp  */
	case 5:    /* ljmp */
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	case 6:    /* push */
          if (ir.regmap[X86_RECORD_R8_REGNUM] && ir.dflag)
            ir.dflag = 2;
	  if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
	    return -1;
	  break;
	default:
	  ir.addr -= 2;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	  break;
	}
      break;

    case 0x84:    /* test */
    case 0x85:
    case 0xa8:
    case 0xa9:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x98:    /* CWDE/CBW */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      break;

    case 0x99:    /* CDQ/CWD */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
      break;

    case 0x0faf:  /* imul */
    case 0x69:
    case 0x6b:
      ir.ot = ir.dflag + OT_WORD;
      if (i386_record_modrm (&ir))
	return -1;
      if (opcode == 0x69)
        ir.rip_offset = (ir.ot > OT_LONG) ? 4 : (1 << ir.ot);
      else if (opcode == 0x6b)
        ir.rip_offset = 1;
      ir.reg |= rex_r;
      if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	ir.reg &= 0x3;
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0fc0:  /* xadd */
    case 0x0fc1:
      if ((opcode & 1) == 0)
	ir.ot = OT_BYTE;
      else
	ir.ot = ir.dflag + OT_WORD;
      if (i386_record_modrm (&ir))
	return -1;
      ir.reg |= rex_r;
      if (ir.mod == 3)
	{
	  if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	    ir.reg &= 0x3;
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
	  if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	    ir.rm &= 0x3;
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
	}
      else
	{
	  if (i386_record_lea_modrm (&ir))
	    return -1;
	  if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	    ir.reg &= 0x3;
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0fb0:  /* cmpxchg */
    case 0x0fb1:
      if ((opcode & 1) == 0)
	ir.ot = OT_BYTE;
      else
	ir.ot = ir.dflag + OT_WORD;
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3)
	{
          ir.reg |= rex_r;
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
	  if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	    ir.reg &= 0x3;
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
	}
      else
	{
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
	  if (i386_record_lea_modrm (&ir))
	    return -1;
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0fc7:    /* cmpxchg8b / rdrand / rdseed */
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3)
	{
	  /* rdrand and rdseed use the 3 bits of the REG field of ModR/M as
	     an extended opcode.  rdrand has bits 110 (/6) and rdseed
	     has bits 111 (/7).  */
	  if (ir.reg == 6 || ir.reg == 7)
	    {
	      /* The storage register is described by the 3 R/M bits, but the
		 REX.B prefix may be used to give access to registers
		 R8~R15.  In this case ir.rex_b + R/M will give us the register
		 in the range R8~R15.

		 REX.W may also be used to access 64-bit registers, but we
		 already record entire registers and not just partial bits
		 of them.  */
	      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rex_b + ir.rm);
	      /* These instructions also set conditional bits.  */
	      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	      break;
	    }
	  else
	    {
	      /* We don't handle this particular instruction yet.  */
	      ir.addr -= 2;
	      opcode = opcode << 8 | ir.modrm;
	      goto no_support;
	    }
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
      if (i386_record_lea_modrm (&ir))
	return -1;
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x50:    /* push */
    case 0x51:
    case 0x52:
    case 0x53:
    case 0x54:
    case 0x55:
    case 0x56:
    case 0x57:
    case 0x68:
    case 0x6a:
      if (ir.regmap[X86_RECORD_R8_REGNUM] && ir.dflag)
        ir.dflag = 2;
      if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
	return -1;
      break;

    case 0x06:    /* push es */
    case 0x0e:    /* push cs */
    case 0x16:    /* push ss */
    case 0x1e:    /* push ds */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
	  ir.addr -= 1;
	  goto no_support;
	}
      if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
	return -1;
      break;

    case 0x0fa0:    /* push fs */
    case 0x0fa8:    /* push gs */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
	  ir.addr -= 2;
	  goto no_support;
	}
      if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
	return -1;
      break;

    case 0x60:    /* pusha */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
	  ir.addr -= 1;
	  goto no_support;
	}
      if (i386_record_push (&ir, 1 << (ir.dflag + 4)))
	return -1;
      break;

    case 0x58:    /* pop */
    case 0x59:
    case 0x5a:
    case 0x5b:
    case 0x5c:
    case 0x5d:
    case 0x5e:
    case 0x5f:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG ((opcode & 0x7) | ir.rex_b);
      break;

    case 0x61:    /* popa */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
	  ir.addr -= 1;
	  goto no_support;
	}
      for (regnum = X86_RECORD_REAX_REGNUM; 
	   regnum <= X86_RECORD_REDI_REGNUM;
	   regnum++)
	I386_RECORD_FULL_ARCH_LIST_ADD_REG (regnum);
      break;

    case 0x8f:    /* pop */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
	ir.ot = ir.dflag ? OT_QUAD : OT_WORD;
      else
        ir.ot = ir.dflag + OT_WORD;
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3)
	I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
      else
	{
          ir.popl_esp_hack = 1 << ir.ot;
	  if (i386_record_lea_modrm (&ir))
	    return -1;
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      break;

    case 0xc8:    /* enter */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REBP_REGNUM);
      if (ir.regmap[X86_RECORD_R8_REGNUM] && ir.dflag)
        ir.dflag = 2;
      if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
	return -1;
      break;

    case 0xc9:    /* leave */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REBP_REGNUM);
      break;

    case 0x07:    /* pop es */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
	  ir.addr -= 1;
	  goto no_support;
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_ES_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x17:    /* pop ss */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
	  ir.addr -= 1;
	  goto no_support;
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_SS_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x1f:    /* pop ds */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
	  ir.addr -= 1;
	  goto no_support;
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_DS_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0fa1:    /* pop fs */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_FS_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0fa9:    /* pop gs */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_GS_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x88:    /* mov */
    case 0x89:
    case 0xc6:
    case 0xc7:
      if ((opcode & 1) == 0)
	ir.ot = OT_BYTE;
      else
	ir.ot = ir.dflag + OT_WORD;

      if (i386_record_modrm (&ir))
	return -1;

      if (ir.mod != 3)
	{
          if (opcode == 0xc6 || opcode == 0xc7)
	    ir.rip_offset = (ir.ot > OT_LONG) ? 4 : (1 << ir.ot);
	  if (i386_record_lea_modrm (&ir))
	    return -1;
	}
      else
	{
          if (opcode == 0xc6 || opcode == 0xc7)
	    ir.rm |= ir.rex_b;
	  if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	    ir.rm &= 0x3;
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
	}
      break;

    case 0x8a:    /* mov */
    case 0x8b:
      if ((opcode & 1) == 0)
	ir.ot = OT_BYTE;
      else
	ir.ot = ir.dflag + OT_WORD;
      if (i386_record_modrm (&ir))
	return -1;
      ir.reg |= rex_r;
      if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	ir.reg &= 0x3;
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
      break;

    case 0x8c:    /* mov seg */
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.reg > 5)
	{
	  ir.addr -= 2;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	}

      if (ir.mod == 3)
	I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
      else
	{
	  ir.ot = OT_WORD;
	  if (i386_record_lea_modrm (&ir))
	    return -1;
	}
      break;

    case 0x8e:    /* mov seg */
      if (i386_record_modrm (&ir))
	return -1;
      switch (ir.reg)
	{
	case 0:
	  regnum = X86_RECORD_ES_REGNUM;
	  break;
	case 2:
	  regnum = X86_RECORD_SS_REGNUM;
	  break;
	case 3:
	  regnum = X86_RECORD_DS_REGNUM;
	  break;
	case 4:
	  regnum = X86_RECORD_FS_REGNUM;
	  break;
	case 5:
	  regnum = X86_RECORD_GS_REGNUM;
	  break;
	default:
	  ir.addr -= 2;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	  break;
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (regnum);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0fb6:    /* movzbS */
    case 0x0fb7:    /* movzwS */
    case 0x0fbe:    /* movsbS */
    case 0x0fbf:    /* movswS */
      if (i386_record_modrm (&ir))
	return -1;
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg | rex_r);
      break;

    case 0x8d:      /* lea */
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3)
	{
	  ir.addr -= 2;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	}
      ir.ot = ir.dflag;
      ir.reg |= rex_r;
      if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	ir.reg &= 0x3;
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
      break;

    case 0xa0:    /* mov EAX */
    case 0xa1:

    case 0xd7:    /* xlat */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      break;

    case 0xa2:    /* mov EAX */
    case 0xa3:
      if (ir.override >= 0)
        {
          if (record_full_memory_query)
            {
              if (yquery (_("\
Process record ignores the memory change of instruction at address %s\n\
because it can't get the value of the segment register.\n\
Do you want to stop the program?"),
                          paddress (gdbarch, ir.orig_addr)))
                return -1;
            }
	}
      else
	{
          if ((opcode & 1) == 0)
	    ir.ot = OT_BYTE;
	  else
	    ir.ot = ir.dflag + OT_WORD;
	  if (ir.aflag == 2)
	    {
              if (record_read_memory (gdbarch, ir.addr, buf, 8))
		return -1;
	      ir.addr += 8;
	      addr = extract_unsigned_integer (buf, 8, byte_order);
	    }
          else if (ir.aflag)
	    {
              if (record_read_memory (gdbarch, ir.addr, buf, 4))
		return -1;
	      ir.addr += 4;
              addr = extract_unsigned_integer (buf, 4, byte_order);
	    }
          else
	    {
              if (record_read_memory (gdbarch, ir.addr, buf, 2))
		return -1;
	      ir.addr += 2;
              addr = extract_unsigned_integer (buf, 2, byte_order);
	    }
	  if (record_full_arch_list_add_mem (addr, 1 << ir.ot))
	    return -1;
        }
      break;

    case 0xb0:    /* mov R, Ib */
    case 0xb1:
    case 0xb2:
    case 0xb3:
    case 0xb4:
    case 0xb5:
    case 0xb6:
    case 0xb7:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG ((ir.regmap[X86_RECORD_R8_REGNUM])
					  ? ((opcode & 0x7) | ir.rex_b)
					  : ((opcode & 0x7) & 0x3));
      break;

    case 0xb8:    /* mov R, Iv */
    case 0xb9:
    case 0xba:
    case 0xbb:
    case 0xbc:
    case 0xbd:
    case 0xbe:
    case 0xbf:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG ((opcode & 0x7) | ir.rex_b);
      break;

    case 0x91:    /* xchg R, EAX */
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x96:
    case 0x97:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (opcode & 0x7);
      break;

    case 0x86:    /* xchg Ev, Gv */
    case 0x87:
      if ((opcode & 1) == 0)
	ir.ot = OT_BYTE;
      else
	ir.ot = ir.dflag + OT_WORD;
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3)
	{
	  ir.rm |= ir.rex_b;
	  if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	    ir.rm &= 0x3;
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
	}
      else
	{
	  if (i386_record_lea_modrm (&ir))
	    return -1;
	}
      ir.reg |= rex_r;
      if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	ir.reg &= 0x3;
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
      break;

    case 0xc4:    /* les Gv */
    case 0xc5:    /* lds Gv */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
	  ir.addr -= 1;
	  goto no_support;
	}
      /* FALLTHROUGH */
    case 0x0fb2:    /* lss Gv */
    case 0x0fb4:    /* lfs Gv */
    case 0x0fb5:    /* lgs Gv */
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3)
	{
	  if (opcode > 0xff)
	    ir.addr -= 3;
	  else
	    ir.addr -= 2;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	}
      switch (opcode)
	{
	case 0xc4:    /* les Gv */
	  regnum = X86_RECORD_ES_REGNUM;
	  break;
	case 0xc5:    /* lds Gv */
	  regnum = X86_RECORD_DS_REGNUM;
	  break;
	case 0x0fb2:  /* lss Gv */
	  regnum = X86_RECORD_SS_REGNUM;
	  break;
	case 0x0fb4:  /* lfs Gv */
	  regnum = X86_RECORD_FS_REGNUM;
	  break;
	case 0x0fb5:  /* lgs Gv */
	  regnum = X86_RECORD_GS_REGNUM;
	  break;
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (regnum);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg | rex_r);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0xc0:    /* shifts */
    case 0xc1:
    case 0xd0:
    case 0xd1:
    case 0xd2:
    case 0xd3:
      if ((opcode & 1) == 0)
	ir.ot = OT_BYTE;
      else
	ir.ot = ir.dflag + OT_WORD;
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod != 3 && (opcode == 0xd2 || opcode == 0xd3))
	{
	  if (i386_record_lea_modrm (&ir))
	    return -1;
	}
      else
	{
	  ir.rm |= ir.rex_b;
	  if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
	    ir.rm &= 0x3;
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0fa4:
    case 0x0fa5:
    case 0x0fac:
    case 0x0fad:
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3)
	{
	  if (record_full_arch_list_add_reg (ir.regcache, ir.rm))
	    return -1;
	}
      else
	{
	  if (i386_record_lea_modrm (&ir))
	    return -1;
	}
      break;

    case 0xd8:    /* Floats.  */
    case 0xd9:
    case 0xda:
    case 0xdb:
    case 0xdc:
    case 0xdd:
    case 0xde:
    case 0xdf:
      if (i386_record_modrm (&ir))
	return -1;
      ir.reg |= ((opcode & 7) << 3);
      if (ir.mod != 3)
	{
	  /* Memory.  */
	  uint64_t addr64;

	  if (i386_record_lea_modrm_addr (&ir, &addr64))
	    return -1;
	  switch (ir.reg)
	    {
	    case 0x02:
            case 0x12:
            case 0x22:
            case 0x32:
	      /* For fcom, ficom nothing to do.  */
              break;
	    case 0x03:
            case 0x13:
            case 0x23:
            case 0x33:
	      /* For fcomp, ficomp pop FPU stack, store all.  */
              if (i386_record_floats (gdbarch, &ir, I386_SAVE_FPU_REGS))
                return -1;
              break;
            case 0x00:
            case 0x01:
	    case 0x04:
	    case 0x05:
	    case 0x06:
	    case 0x07:
	    case 0x10:
	    case 0x11:
	    case 0x14:
	    case 0x15:
	    case 0x16:
	    case 0x17:
	    case 0x20:
	    case 0x21:
	    case 0x24:
	    case 0x25:
	    case 0x26:
	    case 0x27:
	    case 0x30:
	    case 0x31:
	    case 0x34:
	    case 0x35:
	    case 0x36:
	    case 0x37:
              /* For fadd, fmul, fsub, fsubr, fdiv, fdivr, fiadd, fimul,
                 fisub, fisubr, fidiv, fidivr, modR/M.reg is an extension
                 of code,  always affects st(0) register.  */
              if (i386_record_floats (gdbarch, &ir, I387_ST0_REGNUM (tdep)))
                return -1;
	      break;
	    case 0x08:
	    case 0x0a:
	    case 0x0b:
	    case 0x18:
	    case 0x19:
	    case 0x1a:
	    case 0x1b:
            case 0x1d:
	    case 0x28:
	    case 0x29:
	    case 0x2a:
	    case 0x2b:
	    case 0x38:
	    case 0x39:
	    case 0x3a:
	    case 0x3b:
            case 0x3c:
            case 0x3d:
	      switch (ir.reg & 7)
		{
		case 0:
		  /* Handling fld, fild.  */
		  if (i386_record_floats (gdbarch, &ir, I386_SAVE_FPU_REGS))
		    return -1;
		  break;
		case 1:
		  switch (ir.reg >> 4)
		    {
		    case 0:
		      if (record_full_arch_list_add_mem (addr64, 4))
			return -1;
		      break;
		    case 2:
		      if (record_full_arch_list_add_mem (addr64, 8))
			return -1;
		      break;
		    case 3:
		      break;
		    default:
		      if (record_full_arch_list_add_mem (addr64, 2))
			return -1;
		      break;
		    }
		  break;
		default:
		  switch (ir.reg >> 4)
		    {
		    case 0:
		      if (record_full_arch_list_add_mem (addr64, 4))
			return -1;
		      if (3 == (ir.reg & 7))
			{
			  /* For fstp m32fp.  */
			  if (i386_record_floats (gdbarch, &ir,
						  I386_SAVE_FPU_REGS))
			    return -1;
			}
		      break;
		    case 1:
		      if (record_full_arch_list_add_mem (addr64, 4))
			return -1;
		      if ((3 == (ir.reg & 7))
			  || (5 == (ir.reg & 7))
			  || (7 == (ir.reg & 7)))
			{
			  /* For fstp insn.  */
			  if (i386_record_floats (gdbarch, &ir,
						  I386_SAVE_FPU_REGS))
			    return -1;
			}
		      break;
		    case 2:
		      if (record_full_arch_list_add_mem (addr64, 8))
			return -1;
		      if (3 == (ir.reg & 7))
			{
			  /* For fstp m64fp.  */
			  if (i386_record_floats (gdbarch, &ir,
						  I386_SAVE_FPU_REGS))
			    return -1;
			}
		      break;
		    case 3:
		      if ((3 <= (ir.reg & 7)) && (6 <= (ir.reg & 7)))
			{
			  /* For fistp, fbld, fild, fbstp.  */
			  if (i386_record_floats (gdbarch, &ir,
						  I386_SAVE_FPU_REGS))
			    return -1;
			}
		      /* Fall through */
		    default:
		      if (record_full_arch_list_add_mem (addr64, 2))
			return -1;
		      break;
		    }
		  break;
		}
	      break;
	    case 0x0c:
              /* Insn fldenv.  */
              if (i386_record_floats (gdbarch, &ir,
                                      I386_SAVE_FPU_ENV_REG_STACK))
                return -1;
              break;
	    case 0x0d:
              /* Insn fldcw.  */
              if (i386_record_floats (gdbarch, &ir, I387_FCTRL_REGNUM (tdep)))
                return -1;
              break;
	    case 0x2c:
              /* Insn frstor.  */
              if (i386_record_floats (gdbarch, &ir,
                                      I386_SAVE_FPU_ENV_REG_STACK))
                return -1;
	      break;
	    case 0x0e:
	      if (ir.dflag)
		{
		  if (record_full_arch_list_add_mem (addr64, 28))
		    return -1;
		}
	      else
		{
		  if (record_full_arch_list_add_mem (addr64, 14))
		    return -1;
		}
	      break;
	    case 0x0f:
	    case 0x2f:
	      if (record_full_arch_list_add_mem (addr64, 2))
		return -1;
              /* Insn fstp, fbstp.  */
              if (i386_record_floats (gdbarch, &ir, I386_SAVE_FPU_REGS))
                return -1;
	      break;
	    case 0x1f:
	    case 0x3e:
	      if (record_full_arch_list_add_mem (addr64, 10))
		return -1;
	      break;
	    case 0x2e:
	      if (ir.dflag)
		{
		  if (record_full_arch_list_add_mem (addr64, 28))
		    return -1;
		  addr64 += 28;
		}
	      else
		{
		  if (record_full_arch_list_add_mem (addr64, 14))
		    return -1;
		  addr64 += 14;
		}
	      if (record_full_arch_list_add_mem (addr64, 80))
		return -1;
	      /* Insn fsave.  */
	      if (i386_record_floats (gdbarch, &ir,
				      I386_SAVE_FPU_ENV_REG_STACK))
		return -1;
	      break;
	    case 0x3f:
	      if (record_full_arch_list_add_mem (addr64, 8))
		return -1;
	      /* Insn fistp.  */
	      if (i386_record_floats (gdbarch, &ir, I386_SAVE_FPU_REGS))
		return -1;
	      break;
	    default:
	      ir.addr -= 2;
	      opcode = opcode << 8 | ir.modrm;
	      goto no_support;
	      break;
	    }
	}
      /* Opcode is an extension of modR/M byte.  */
      else
        {
	  switch (opcode)
	    {
	    case 0xd8:
	      if (i386_record_floats (gdbarch, &ir, I387_ST0_REGNUM (tdep)))
		return -1;
	      break;
	    case 0xd9:
	      if (0x0c == (ir.modrm >> 4))
		{
		  if ((ir.modrm & 0x0f) <= 7)
		    {
		      if (i386_record_floats (gdbarch, &ir,
					      I386_SAVE_FPU_REGS))
			return -1;
		    }
                  else
		    {
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep)))
			return -1;
		      /* If only st(0) is changing, then we have already
			 recorded.  */
		      if ((ir.modrm & 0x0f) - 0x08)
			{
			  if (i386_record_floats (gdbarch, &ir,
						  I387_ST0_REGNUM (tdep) +
						  ((ir.modrm & 0x0f) - 0x08)))
			    return -1;
			}
		    }
		}
              else
                {
		  switch (ir.modrm)
		    {
		    case 0xe0:
		    case 0xe1:
		    case 0xf0:
		    case 0xf5:
		    case 0xf8:
		    case 0xfa:
		    case 0xfc:
		    case 0xfe:
		    case 0xff:
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep)))
			return -1;
		      break;
		    case 0xf1:
		    case 0xf2:
		    case 0xf3:
		    case 0xf4:
		    case 0xf6:
		    case 0xf7:
		    case 0xe8:
		    case 0xe9:
		    case 0xea:
		    case 0xeb:
		    case 0xec:
		    case 0xed:
		    case 0xee:
		    case 0xf9:
		    case 0xfb:
		      if (i386_record_floats (gdbarch, &ir,
					      I386_SAVE_FPU_REGS))
			return -1;
		      break;
		    case 0xfd:
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep)))
			return -1;
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep) + 1))
			return -1;
		      break;
		    }
		}
              break;
            case 0xda:
              if (0xe9 == ir.modrm)
                {
		  if (i386_record_floats (gdbarch, &ir, I386_SAVE_FPU_REGS))
		    return -1;
                }
              else if ((0x0c == ir.modrm >> 4) || (0x0d == ir.modrm >> 4))
                {
		  if (i386_record_floats (gdbarch, &ir,
					  I387_ST0_REGNUM (tdep)))
		    return -1;
		  if (((ir.modrm & 0x0f) > 0) && ((ir.modrm & 0x0f) <= 7))
		    {
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep) +
					      (ir.modrm & 0x0f)))
			return -1;
		    }
		  else if ((ir.modrm & 0x0f) - 0x08)
		    {
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep) +
					      ((ir.modrm & 0x0f) - 0x08)))
			return -1;
		    }
                }
              break;
            case 0xdb:
              if (0xe3 == ir.modrm)
                {
		  if (i386_record_floats (gdbarch, &ir, I386_SAVE_FPU_ENV))
		    return -1;
                }
              else if ((0x0c == ir.modrm >> 4) || (0x0d == ir.modrm >> 4))
                {
		  if (i386_record_floats (gdbarch, &ir,
					  I387_ST0_REGNUM (tdep)))
		    return -1;
		  if (((ir.modrm & 0x0f) > 0) && ((ir.modrm & 0x0f) <= 7))
		    {
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep) +
					      (ir.modrm & 0x0f)))
			return -1;
		    }
		  else if ((ir.modrm & 0x0f) - 0x08)
		    {
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep) +
					      ((ir.modrm & 0x0f) - 0x08)))
			return -1;
		    }
                }
              break;
            case 0xdc:
              if ((0x0c == ir.modrm >> 4)
		  || (0x0d == ir.modrm >> 4)
		  || (0x0f == ir.modrm >> 4))
                {
		  if ((ir.modrm & 0x0f) <= 7)
		    {
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep) +
					      (ir.modrm & 0x0f)))
			return -1;
		    }
		  else
		    {
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep) +
					      ((ir.modrm & 0x0f) - 0x08)))
			return -1;
		    }
                }
	      break;
            case 0xdd:
              if (0x0c == ir.modrm >> 4)
                {
                  if (i386_record_floats (gdbarch, &ir,
                                          I387_FTAG_REGNUM (tdep)))
                    return -1;
                }
              else if ((0x0d == ir.modrm >> 4) || (0x0e == ir.modrm >> 4))
                {
                  if ((ir.modrm & 0x0f) <= 7)
                    {
		      if (i386_record_floats (gdbarch, &ir,
					      I387_ST0_REGNUM (tdep) +
					      (ir.modrm & 0x0f)))
			return -1;
                    }
                  else
                    {
                      if (i386_record_floats (gdbarch, &ir,
					      I386_SAVE_FPU_REGS))
                        return -1;
                    }
                }
              break;
            case 0xde:
              if ((0x0c == ir.modrm >> 4)
		  || (0x0e == ir.modrm >> 4)
		  || (0x0f == ir.modrm >> 4)
		  || (0xd9 == ir.modrm))
                {
		  if (i386_record_floats (gdbarch, &ir, I386_SAVE_FPU_REGS))
		    return -1;
                }
              break;
            case 0xdf:
              if (0xe0 == ir.modrm)
                {
		  if (record_full_arch_list_add_reg (ir.regcache,
						     I386_EAX_REGNUM))
		    return -1;
                }
              else if ((0x0f == ir.modrm >> 4) || (0x0e == ir.modrm >> 4))
                {
		  if (i386_record_floats (gdbarch, &ir, I386_SAVE_FPU_REGS))
		    return -1;
                }
              break;
	    }
	}
      break;
      /* string ops */
    case 0xa4:    /* movsS */
    case 0xa5:
    case 0xaa:    /* stosS */
    case 0xab:
    case 0x6c:    /* insS */
    case 0x6d:
      regcache_raw_read_unsigned (ir.regcache,
                                  ir.regmap[X86_RECORD_RECX_REGNUM],
                                  &addr);
      if (addr)
        {
          ULONGEST es, ds;

          if ((opcode & 1) == 0)
	    ir.ot = OT_BYTE;
          else
	    ir.ot = ir.dflag + OT_WORD;
          regcache_raw_read_unsigned (ir.regcache,
                                      ir.regmap[X86_RECORD_REDI_REGNUM],
                                      &addr);

          regcache_raw_read_unsigned (ir.regcache,
                                      ir.regmap[X86_RECORD_ES_REGNUM],
                                      &es);
          regcache_raw_read_unsigned (ir.regcache,
                                      ir.regmap[X86_RECORD_DS_REGNUM],
                                      &ds);
          if (ir.aflag && (es != ds))
            {
              /* addr += ((uint32_t) read_register (I386_ES_REGNUM)) << 4; */
              if (record_full_memory_query)
                {
                  if (yquery (_("\
Process record ignores the memory change of instruction at address %s\n\
because it can't get the value of the segment register.\n\
Do you want to stop the program?"),
                              paddress (gdbarch, ir.orig_addr)))
                    return -1;
                }
            }
          else
            {
              if (record_full_arch_list_add_mem (addr, 1 << ir.ot))
                return -1;
            }

          if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
            I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
          if (opcode == 0xa4 || opcode == 0xa5)
            I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
          I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
          I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	}
      break;

    case 0xa6:    /* cmpsS */
    case 0xa7:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
        I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0xac:    /* lodsS */
    case 0xad:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
        I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0xae:    /* scasS */
    case 0xaf:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
        I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x6e:    /* outsS */
    case 0x6f:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
        I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0xe4:    /* port I/O */
    case 0xe5:
    case 0xec:
    case 0xed:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      break;

    case 0xe6:
    case 0xe7:
    case 0xee:
    case 0xef:
      break;

      /* control */
    case 0xc2:    /* ret im */
    case 0xc3:    /* ret */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0xca:    /* lret im */
    case 0xcb:    /* lret */
    case 0xcf:    /* iret */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_CS_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0xe8:    /* call im */
      if (ir.regmap[X86_RECORD_R8_REGNUM] && ir.dflag)
        ir.dflag = 2;
      if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
        return -1;
      break;

    case 0x9a:    /* lcall im */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
          ir.addr -= 1;
          goto no_support;
        }
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_CS_REGNUM);
      if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
        return -1;
      break;

    case 0xe9:    /* jmp im */
    case 0xea:    /* ljmp im */
    case 0xeb:    /* jmp Jb */
    case 0x70:    /* jcc Jb */
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x76:
    case 0x77:
    case 0x78:
    case 0x79:
    case 0x7a:
    case 0x7b:
    case 0x7c:
    case 0x7d:
    case 0x7e:
    case 0x7f:
    case 0x0f80:  /* jcc Jv */
    case 0x0f81:
    case 0x0f82:
    case 0x0f83:
    case 0x0f84:
    case 0x0f85:
    case 0x0f86:
    case 0x0f87:
    case 0x0f88:
    case 0x0f89:
    case 0x0f8a:
    case 0x0f8b:
    case 0x0f8c:
    case 0x0f8d:
    case 0x0f8e:
    case 0x0f8f:
      break;

    case 0x0f90:  /* setcc Gv */
    case 0x0f91:
    case 0x0f92:
    case 0x0f93:
    case 0x0f94:
    case 0x0f95:
    case 0x0f96:
    case 0x0f97:
    case 0x0f98:
    case 0x0f99:
    case 0x0f9a:
    case 0x0f9b:
    case 0x0f9c:
    case 0x0f9d:
    case 0x0f9e:
    case 0x0f9f:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      ir.ot = OT_BYTE;
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3)
        I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rex_b ? (ir.rm | ir.rex_b)
					    : (ir.rm & 0x3));
      else
	{
	  if (i386_record_lea_modrm (&ir))
	    return -1;
	}
      break;

    case 0x0f40:    /* cmov Gv, Ev */
    case 0x0f41:
    case 0x0f42:
    case 0x0f43:
    case 0x0f44:
    case 0x0f45:
    case 0x0f46:
    case 0x0f47:
    case 0x0f48:
    case 0x0f49:
    case 0x0f4a:
    case 0x0f4b:
    case 0x0f4c:
    case 0x0f4d:
    case 0x0f4e:
    case 0x0f4f:
      if (i386_record_modrm (&ir))
	return -1;
      ir.reg |= rex_r;
      if (ir.dflag == OT_BYTE)
	ir.reg &= 0x3;
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
      break;

      /* flags */
    case 0x9c:    /* pushf */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      if (ir.regmap[X86_RECORD_R8_REGNUM] && ir.dflag)
        ir.dflag = 2;
      if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
        return -1;
      break;

    case 0x9d:    /* popf */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x9e:    /* sahf */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
          ir.addr -= 1;
          goto no_support;
        }
      /* FALLTHROUGH */
    case 0xf5:    /* cmc */
    case 0xf8:    /* clc */
    case 0xf9:    /* stc */
    case 0xfc:    /* cld */
    case 0xfd:    /* std */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x9f:    /* lahf */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
          ir.addr -= 1;
          goto no_support;
        }
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      break;

      /* bit operations */
    case 0x0fba:    /* bt/bts/btr/btc Gv, im */
      ir.ot = ir.dflag + OT_WORD;
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.reg < 4)
	{
	  ir.addr -= 2;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	}
      if (ir.reg != 4)
	{
          if (ir.mod == 3)
            I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
	  else
	    {
	      if (i386_record_lea_modrm (&ir))
		return -1;
	    }
	}
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0fa3:    /* bt Gv, Ev */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0fab:    /* bts */
    case 0x0fb3:    /* btr */
    case 0x0fbb:    /* btc */
      ir.ot = ir.dflag + OT_WORD;
      if (i386_record_modrm (&ir))
        return -1;
      if (ir.mod == 3)
        I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
      else
        {
          uint64_t addr64;
          if (i386_record_lea_modrm_addr (&ir, &addr64))
            return -1;
          regcache_raw_read_unsigned (ir.regcache,
                                      ir.regmap[ir.reg | rex_r],
                                      &addr);
          switch (ir.dflag)
            {
            case 0:
              addr64 += ((int16_t) addr >> 4) << 4;
              break;
            case 1:
              addr64 += ((int32_t) addr >> 5) << 5;
              break;
            case 2:
              addr64 += ((int64_t) addr >> 6) << 6;
              break;
            }
          if (record_full_arch_list_add_mem (addr64, 1 << ir.ot))
            return -1;
          if (i386_record_lea_modrm (&ir))
            return -1;
        }
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0fbc:    /* bsf */
    case 0x0fbd:    /* bsr */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg | rex_r);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

      /* bcd */
    case 0x27:    /* daa */
    case 0x2f:    /* das */
    case 0x37:    /* aaa */
    case 0x3f:    /* aas */
    case 0xd4:    /* aam */
    case 0xd5:    /* aad */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
          ir.addr -= 1;
          goto no_support;
        }
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

      /* misc */
    case 0x90:    /* nop */
      if (prefixes & PREFIX_LOCK)
	{
	  ir.addr -= 1;
	  goto no_support;
	}
      break;

    case 0x9b:    /* fwait */
      if (record_read_memory (gdbarch, ir.addr, &opcode8, 1))
	return -1;
      opcode = (uint32_t) opcode8;
      ir.addr++;
      goto reswitch;
      break;

      /* XXX */
    case 0xcc:    /* int3 */
      printf_unfiltered (_("Process record does not support instruction "
			   "int3.\n"));
      ir.addr -= 1;
      goto no_support;
      break;

      /* XXX */
    case 0xcd:    /* int */
      {
	int ret;
	uint8_t interrupt;
	if (record_read_memory (gdbarch, ir.addr, &interrupt, 1))
	  return -1;
	ir.addr++;
	if (interrupt != 0x80
	    || tdep->i386_intx80_record == NULL)
	  {
	    printf_unfiltered (_("Process record does not support "
				 "instruction int 0x%02x.\n"),
			       interrupt);
	    ir.addr -= 2;
	    goto no_support;
	  }
	ret = tdep->i386_intx80_record (ir.regcache);
	if (ret)
	  return ret;
      }
      break;

      /* XXX */
    case 0xce:    /* into */
      printf_unfiltered (_("Process record does not support "
			   "instruction into.\n"));
      ir.addr -= 1;
      goto no_support;
      break;

    case 0xfa:    /* cli */
    case 0xfb:    /* sti */
      break;

    case 0x62:    /* bound */
      printf_unfiltered (_("Process record does not support "
			   "instruction bound.\n"));
      ir.addr -= 1;
      goto no_support;
      break;

    case 0x0fc8:    /* bswap reg */
    case 0x0fc9:
    case 0x0fca:
    case 0x0fcb:
    case 0x0fcc:
    case 0x0fcd:
    case 0x0fce:
    case 0x0fcf:
      I386_RECORD_FULL_ARCH_LIST_ADD_REG ((opcode & 7) | ir.rex_b);
      break;

    case 0xd6:    /* salc */
      if (ir.regmap[X86_RECORD_R8_REGNUM])
        {
          ir.addr -= 1;
          goto no_support;
        }
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0xe0:    /* loopnz */
    case 0xe1:    /* loopz */
    case 0xe2:    /* loop */
    case 0xe3:    /* jecxz */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0f30:    /* wrmsr */
      printf_unfiltered (_("Process record does not support "
			   "instruction wrmsr.\n"));
      ir.addr -= 2;
      goto no_support;
      break;

    case 0x0f32:    /* rdmsr */
      printf_unfiltered (_("Process record does not support "
			   "instruction rdmsr.\n"));
      ir.addr -= 2;
      goto no_support;
      break;

    case 0x0f31:    /* rdtsc */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
      break;

    case 0x0f34:    /* sysenter */
      {
	int ret;
        if (ir.regmap[X86_RECORD_R8_REGNUM])
          {
            ir.addr -= 2;
            goto no_support;
          }
	if (tdep->i386_sysenter_record == NULL)
	  {
	    printf_unfiltered (_("Process record does not support "
				 "instruction sysenter.\n"));
	    ir.addr -= 2;
	    goto no_support;
	  }
	ret = tdep->i386_sysenter_record (ir.regcache);
	if (ret)
	  return ret;
      }
      break;

    case 0x0f35:    /* sysexit */
      printf_unfiltered (_("Process record does not support "
			   "instruction sysexit.\n"));
      ir.addr -= 2;
      goto no_support;
      break;

    case 0x0f05:    /* syscall */
      {
	int ret;
	if (tdep->i386_syscall_record == NULL)
	  {
	    printf_unfiltered (_("Process record does not support "
				 "instruction syscall.\n"));
	    ir.addr -= 2;
	    goto no_support;
	  }
	ret = tdep->i386_syscall_record (ir.regcache);
	if (ret)
	  return ret;
      }
      break;

    case 0x0f07:    /* sysret */
      printf_unfiltered (_("Process record does not support "
                           "instruction sysret.\n"));
      ir.addr -= 2;
      goto no_support;
      break;

    case 0x0fa2:    /* cpuid */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REBX_REGNUM);
      break;

    case 0xf4:    /* hlt */
      printf_unfiltered (_("Process record does not support "
			   "instruction hlt.\n"));
      ir.addr -= 1;
      goto no_support;
      break;

    case 0x0f00:
      if (i386_record_modrm (&ir))
	return -1;
      switch (ir.reg)
	{
	case 0:  /* sldt */
	case 1:  /* str  */
	  if (ir.mod == 3)
            I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
	  else
	    {
	      ir.ot = OT_WORD;
	      if (i386_record_lea_modrm (&ir))
		return -1;
	    }
	  break;
	case 2:  /* lldt */
	case 3:  /* ltr */
	  break;
	case 4:  /* verr */
	case 5:  /* verw */
          I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	default:
	  ir.addr -= 3;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	  break;
	}
      break;

    case 0x0f01:
      if (i386_record_modrm (&ir))
	return -1;
      switch (ir.reg)
	{
	case 0:  /* sgdt */
	  {
	    uint64_t addr64;

	    if (ir.mod == 3)
	      {
		ir.addr -= 3;
		opcode = opcode << 8 | ir.modrm;
		goto no_support;
	      }
	    if (ir.override >= 0)
	      {
                if (record_full_memory_query)
                  {
                    if (yquery (_("\
Process record ignores the memory change of instruction at address %s\n\
because it can't get the value of the segment register.\n\
Do you want to stop the program?"),
                                paddress (gdbarch, ir.orig_addr)))
		      return -1;
                  }
	      }
	    else
	      {
		if (i386_record_lea_modrm_addr (&ir, &addr64))
		  return -1;
		if (record_full_arch_list_add_mem (addr64, 2))
		  return -1;
		addr64 += 2;
                if (ir.regmap[X86_RECORD_R8_REGNUM])
                  {
                    if (record_full_arch_list_add_mem (addr64, 8))
		      return -1;
                  }
                else
                  {
                    if (record_full_arch_list_add_mem (addr64, 4))
		      return -1;
                  }
	      }
	  }
	  break;
	case 1:
	  if (ir.mod == 3)
	    {
	      switch (ir.rm)
		{
		case 0:  /* monitor */
		  break;
		case 1:  /* mwait */
		  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
		  break;
		default:
		  ir.addr -= 3;
		  opcode = opcode << 8 | ir.modrm;
		  goto no_support;
		  break;
		}
	    }
	  else
	    {
	      /* sidt */
	      if (ir.override >= 0)
		{
                  if (record_full_memory_query)
                    {
                      if (yquery (_("\
Process record ignores the memory change of instruction at address %s\n\
because it can't get the value of the segment register.\n\
Do you want to stop the program?"),
                                  paddress (gdbarch, ir.orig_addr)))
                        return -1;
                    }
		}
	      else
		{
		  uint64_t addr64;

		  if (i386_record_lea_modrm_addr (&ir, &addr64))
		    return -1;
		  if (record_full_arch_list_add_mem (addr64, 2))
		    return -1;
		  addr64 += 2;
                  if (ir.regmap[X86_RECORD_R8_REGNUM])
                    {
                      if (record_full_arch_list_add_mem (addr64, 8))
		        return -1;
                    }
                  else
                    {
                      if (record_full_arch_list_add_mem (addr64, 4))
		        return -1;
                    }
		}
	    }
	  break;
	case 2:  /* lgdt */
	  if (ir.mod == 3)
	    {
	      /* xgetbv */
	      if (ir.rm == 0)
		{
		  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
		  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
		  break;
		}
	      /* xsetbv */
	      else if (ir.rm == 1)
		break;
	    }
	case 3:  /* lidt */
	  if (ir.mod == 3)
	    {
	      ir.addr -= 3;
	      opcode = opcode << 8 | ir.modrm;
	      goto no_support;
	    }
	  break;
	case 4:  /* smsw */
	  if (ir.mod == 3)
	    {
	      if (record_full_arch_list_add_reg (ir.regcache, ir.rm | ir.rex_b))
		return -1;
	    }
	  else
	    {
	      ir.ot = OT_WORD;
	      if (i386_record_lea_modrm (&ir))
		return -1;
	    }
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	case 6:  /* lmsw */
	  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	case 7:  /* invlpg */
	  if (ir.mod == 3)
	    {
	      if (ir.rm == 0 && ir.regmap[X86_RECORD_R8_REGNUM])
	        I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_GS_REGNUM);
	      else
	        {
	          ir.addr -= 3;
	          opcode = opcode << 8 | ir.modrm;
	          goto no_support;
	        }
	    }
	  else
	    I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  break;
	default:
	  ir.addr -= 3;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	  break;
	}
      break;

    case 0x0f08:    /* invd */
    case 0x0f09:    /* wbinvd */
      break;

    case 0x63:    /* arpl */
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3 || ir.regmap[X86_RECORD_R8_REGNUM])
        {
          I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.regmap[X86_RECORD_R8_REGNUM]
					      ? (ir.reg | rex_r) : ir.rm);
        }
      else
        {
          ir.ot = ir.dflag ? OT_LONG : OT_WORD;
          if (i386_record_lea_modrm (&ir))
            return -1;
        }
      if (!ir.regmap[X86_RECORD_R8_REGNUM])
        I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0f02:    /* lar */
    case 0x0f03:    /* lsl */
      if (i386_record_modrm (&ir))
	return -1;
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg | rex_r);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    case 0x0f18:
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3 && ir.reg == 3)
        {
	  ir.addr -= 3;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	}
      break;

    case 0x0f19:
    case 0x0f1a:
    case 0x0f1b:
    case 0x0f1c:
    case 0x0f1d:
    case 0x0f1e:
    case 0x0f1f:
      /* nop (multi byte) */
      break;

    case 0x0f20:    /* mov reg, crN */
    case 0x0f22:    /* mov crN, reg */
      if (i386_record_modrm (&ir))
	return -1;
      if ((ir.modrm & 0xc0) != 0xc0)
	{
	  ir.addr -= 3;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	}
      switch (ir.reg)
	{
	case 0:
	case 2:
	case 3:
	case 4:
	case 8:
	  if (opcode & 2)
	    I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	  else
            I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
	  break;
	default:
	  ir.addr -= 3;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	  break;
	}
      break;

    case 0x0f21:    /* mov reg, drN */
    case 0x0f23:    /* mov drN, reg */
      if (i386_record_modrm (&ir))
	return -1;
      if ((ir.modrm & 0xc0) != 0xc0 || ir.reg == 4
	  || ir.reg == 5 || ir.reg >= 8)
	{
	  ir.addr -= 3;
	  opcode = opcode << 8 | ir.modrm;
	  goto no_support;
	}
      if (opcode & 2)
        I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      else
	I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
      break;

    case 0x0f06:    /* clts */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      break;

    /* MMX 3DNow! SSE SSE2 SSE3 SSSE3 SSE4 */

    case 0x0f0d:    /* 3DNow! prefetch */
      break;

    case 0x0f0e:    /* 3DNow! femms */
    case 0x0f77:    /* emms */
      if (i386_fpc_regnum_p (gdbarch, I387_FTAG_REGNUM(tdep)))
        goto no_support;
      record_full_arch_list_add_reg (ir.regcache, I387_FTAG_REGNUM(tdep));
      break;

    case 0x0f0f:    /* 3DNow! data */
      if (i386_record_modrm (&ir))
	return -1;
      if (record_read_memory (gdbarch, ir.addr, &opcode8, 1))
	return -1;
      ir.addr++;
      switch (opcode8)
        {
        case 0x0c:    /* 3DNow! pi2fw */
        case 0x0d:    /* 3DNow! pi2fd */
        case 0x1c:    /* 3DNow! pf2iw */
        case 0x1d:    /* 3DNow! pf2id */
        case 0x8a:    /* 3DNow! pfnacc */
        case 0x8e:    /* 3DNow! pfpnacc */
        case 0x90:    /* 3DNow! pfcmpge */
        case 0x94:    /* 3DNow! pfmin */
        case 0x96:    /* 3DNow! pfrcp */
        case 0x97:    /* 3DNow! pfrsqrt */
        case 0x9a:    /* 3DNow! pfsub */
        case 0x9e:    /* 3DNow! pfadd */
        case 0xa0:    /* 3DNow! pfcmpgt */
        case 0xa4:    /* 3DNow! pfmax */
        case 0xa6:    /* 3DNow! pfrcpit1 */
        case 0xa7:    /* 3DNow! pfrsqit1 */
        case 0xaa:    /* 3DNow! pfsubr */
        case 0xae:    /* 3DNow! pfacc */
        case 0xb0:    /* 3DNow! pfcmpeq */
        case 0xb4:    /* 3DNow! pfmul */
        case 0xb6:    /* 3DNow! pfrcpit2 */
        case 0xb7:    /* 3DNow! pmulhrw */
        case 0xbb:    /* 3DNow! pswapd */
        case 0xbf:    /* 3DNow! pavgusb */
          if (!i386_mmx_regnum_p (gdbarch, I387_MM0_REGNUM (tdep) + ir.reg))
            goto no_support_3dnow_data;
          record_full_arch_list_add_reg (ir.regcache, ir.reg);
          break;

        default:
no_support_3dnow_data:
          opcode = (opcode << 8) | opcode8;
          goto no_support;
          break;
        }
      break;

    case 0x0faa:    /* rsm */
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REBX_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REBP_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
      I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
      break;

    case 0x0fae:
      if (i386_record_modrm (&ir))
	return -1;
      switch(ir.reg)
        {
        case 0:    /* fxsave */
          {
            uint64_t tmpu64;

            I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
	    if (i386_record_lea_modrm_addr (&ir, &tmpu64))
	      return -1;
            if (record_full_arch_list_add_mem (tmpu64, 512))
              return -1;
          }
          break;

        case 1:    /* fxrstor */
          {
            int i;

            I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);

            for (i = I387_MM0_REGNUM (tdep);
                 i386_mmx_regnum_p (gdbarch, i); i++)
              record_full_arch_list_add_reg (ir.regcache, i);

            for (i = I387_XMM0_REGNUM (tdep);
                 i386_xmm_regnum_p (gdbarch, i); i++)
              record_full_arch_list_add_reg (ir.regcache, i);

            if (i386_mxcsr_regnum_p (gdbarch, I387_MXCSR_REGNUM(tdep)))
              record_full_arch_list_add_reg (ir.regcache,
					     I387_MXCSR_REGNUM(tdep));

            for (i = I387_ST0_REGNUM (tdep);
                 i386_fp_regnum_p (gdbarch, i); i++)
              record_full_arch_list_add_reg (ir.regcache, i);

            for (i = I387_FCTRL_REGNUM (tdep);
                 i386_fpc_regnum_p (gdbarch, i); i++)
              record_full_arch_list_add_reg (ir.regcache, i);
          }
          break;

        case 2:    /* ldmxcsr */
          if (!i386_mxcsr_regnum_p (gdbarch, I387_MXCSR_REGNUM(tdep)))
            goto no_support;
          record_full_arch_list_add_reg (ir.regcache, I387_MXCSR_REGNUM(tdep));
          break;

        case 3:    /* stmxcsr */
          ir.ot = OT_LONG;
          if (i386_record_lea_modrm (&ir))
            return -1;
          break;

        case 5:    /* lfence */
        case 6:    /* mfence */
        case 7:    /* sfence clflush */
          break;

        default:
          opcode = (opcode << 8) | ir.modrm;
          goto no_support;
          break;
        }
      break;

    case 0x0fc3:    /* movnti */
      ir.ot = (ir.dflag == 2) ? OT_QUAD : OT_LONG;
      if (i386_record_modrm (&ir))
	return -1;
      if (ir.mod == 3)
        goto no_support;
      ir.reg |= rex_r;
      if (i386_record_lea_modrm (&ir))
        return -1;
      break;

    /* Add prefix to opcode.  */
    case 0x0f10:
    case 0x0f11:
    case 0x0f12:
    case 0x0f13:
    case 0x0f14:
    case 0x0f15:
    case 0x0f16:
    case 0x0f17:
    case 0x0f28:
    case 0x0f29:
    case 0x0f2a:
    case 0x0f2b:
    case 0x0f2c:
    case 0x0f2d:
    case 0x0f2e:
    case 0x0f2f:
    case 0x0f38:
    case 0x0f39:
    case 0x0f3a:
    case 0x0f50:
    case 0x0f51:
    case 0x0f52:
    case 0x0f53:
    case 0x0f54:
    case 0x0f55:
    case 0x0f56:
    case 0x0f57:
    case 0x0f58:
    case 0x0f59:
    case 0x0f5a:
    case 0x0f5b:
    case 0x0f5c:
    case 0x0f5d:
    case 0x0f5e:
    case 0x0f5f:
    case 0x0f60:
    case 0x0f61:
    case 0x0f62:
    case 0x0f63:
    case 0x0f64:
    case 0x0f65:
    case 0x0f66:
    case 0x0f67:
    case 0x0f68:
    case 0x0f69:
    case 0x0f6a:
    case 0x0f6b:
    case 0x0f6c:
    case 0x0f6d:
    case 0x0f6e:
    case 0x0f6f:
    case 0x0f70:
    case 0x0f71:
    case 0x0f72:
    case 0x0f73:
    case 0x0f74:
    case 0x0f75:
    case 0x0f76:
    case 0x0f7c:
    case 0x0f7d:
    case 0x0f7e:
    case 0x0f7f:
    case 0x0fb8:
    case 0x0fc2:
    case 0x0fc4:
    case 0x0fc5:
    case 0x0fc6:
    case 0x0fd0:
    case 0x0fd1:
    case 0x0fd2:
    case 0x0fd3:
    case 0x0fd4:
    case 0x0fd5:
    case 0x0fd6:
    case 0x0fd7:
    case 0x0fd8:
    case 0x0fd9:
    case 0x0fda:
    case 0x0fdb:
    case 0x0fdc:
    case 0x0fdd:
    case 0x0fde:
    case 0x0fdf:
    case 0x0fe0:
    case 0x0fe1:
    case 0x0fe2:
    case 0x0fe3:
    case 0x0fe4:
    case 0x0fe5:
    case 0x0fe6:
    case 0x0fe7:
    case 0x0fe8:
    case 0x0fe9:
    case 0x0fea:
    case 0x0feb:
    case 0x0fec:
    case 0x0fed:
    case 0x0fee:
    case 0x0fef:
    case 0x0ff0:
    case 0x0ff1:
    case 0x0ff2:
    case 0x0ff3:
    case 0x0ff4:
    case 0x0ff5:
    case 0x0ff6:
    case 0x0ff7:
    case 0x0ff8:
    case 0x0ff9:
    case 0x0ffa:
    case 0x0ffb:
    case 0x0ffc:
    case 0x0ffd:
    case 0x0ffe:
      /* Mask out PREFIX_ADDR.  */
      switch ((prefixes & ~PREFIX_ADDR))
        {
        case PREFIX_REPNZ:
          opcode |= 0xf20000;
          break;
        case PREFIX_DATA:
          opcode |= 0x660000;
          break;
        case PREFIX_REPZ:
          opcode |= 0xf30000;
          break;
        }
reswitch_prefix_add:
      switch (opcode)
        {
        case 0x0f38:
        case 0x660f38:
        case 0xf20f38:
        case 0x0f3a:
        case 0x660f3a:
          if (record_read_memory (gdbarch, ir.addr, &opcode8, 1))
	    return -1;
          ir.addr++;
          opcode = (uint32_t) opcode8 | opcode << 8;
          goto reswitch_prefix_add;
          break;

        case 0x0f10:        /* movups */
        case 0x660f10:      /* movupd */
        case 0xf30f10:      /* movss */
        case 0xf20f10:      /* movsd */
        case 0x0f12:        /* movlps */
        case 0x660f12:      /* movlpd */
        case 0xf30f12:      /* movsldup */
        case 0xf20f12:      /* movddup */
        case 0x0f14:        /* unpcklps */
        case 0x660f14:      /* unpcklpd */
        case 0x0f15:        /* unpckhps */
        case 0x660f15:      /* unpckhpd */
        case 0x0f16:        /* movhps */
        case 0x660f16:      /* movhpd */
        case 0xf30f16:      /* movshdup */
        case 0x0f28:        /* movaps */
        case 0x660f28:      /* movapd */
        case 0x0f2a:        /* cvtpi2ps */
        case 0x660f2a:      /* cvtpi2pd */
        case 0xf30f2a:      /* cvtsi2ss */
        case 0xf20f2a:      /* cvtsi2sd */
        case 0x0f2c:        /* cvttps2pi */
        case 0x660f2c:      /* cvttpd2pi */
        case 0x0f2d:        /* cvtps2pi */
        case 0x660f2d:      /* cvtpd2pi */
        case 0x660f3800:    /* pshufb */
        case 0x660f3801:    /* phaddw */
        case 0x660f3802:    /* phaddd */
        case 0x660f3803:    /* phaddsw */
        case 0x660f3804:    /* pmaddubsw */
        case 0x660f3805:    /* phsubw */
        case 0x660f3806:    /* phsubd */
        case 0x660f3807:    /* phsubsw */
        case 0x660f3808:    /* psignb */
        case 0x660f3809:    /* psignw */
        case 0x660f380a:    /* psignd */
        case 0x660f380b:    /* pmulhrsw */
        case 0x660f3810:    /* pblendvb */
        case 0x660f3814:    /* blendvps */
        case 0x660f3815:    /* blendvpd */
        case 0x660f381c:    /* pabsb */
        case 0x660f381d:    /* pabsw */
        case 0x660f381e:    /* pabsd */
        case 0x660f3820:    /* pmovsxbw */
        case 0x660f3821:    /* pmovsxbd */
        case 0x660f3822:    /* pmovsxbq */
        case 0x660f3823:    /* pmovsxwd */
        case 0x660f3824:    /* pmovsxwq */
        case 0x660f3825:    /* pmovsxdq */
        case 0x660f3828:    /* pmuldq */
        case 0x660f3829:    /* pcmpeqq */
        case 0x660f382a:    /* movntdqa */
        case 0x660f3a08:    /* roundps */
        case 0x660f3a09:    /* roundpd */
        case 0x660f3a0a:    /* roundss */
        case 0x660f3a0b:    /* roundsd */
        case 0x660f3a0c:    /* blendps */
        case 0x660f3a0d:    /* blendpd */
        case 0x660f3a0e:    /* pblendw */
        case 0x660f3a0f:    /* palignr */
        case 0x660f3a20:    /* pinsrb */
        case 0x660f3a21:    /* insertps */
        case 0x660f3a22:    /* pinsrd pinsrq */
        case 0x660f3a40:    /* dpps */
        case 0x660f3a41:    /* dppd */
        case 0x660f3a42:    /* mpsadbw */
        case 0x660f3a60:    /* pcmpestrm */
        case 0x660f3a61:    /* pcmpestri */
        case 0x660f3a62:    /* pcmpistrm */
        case 0x660f3a63:    /* pcmpistri */
        case 0x0f51:        /* sqrtps */
        case 0x660f51:      /* sqrtpd */
        case 0xf20f51:      /* sqrtsd */
        case 0xf30f51:      /* sqrtss */
        case 0x0f52:        /* rsqrtps */
        case 0xf30f52:      /* rsqrtss */
        case 0x0f53:        /* rcpps */
        case 0xf30f53:      /* rcpss */
        case 0x0f54:        /* andps */
        case 0x660f54:      /* andpd */
        case 0x0f55:        /* andnps */
        case 0x660f55:      /* andnpd */
        case 0x0f56:        /* orps */
        case 0x660f56:      /* orpd */
        case 0x0f57:        /* xorps */
        case 0x660f57:      /* xorpd */
        case 0x0f58:        /* addps */
        case 0x660f58:      /* addpd */
        case 0xf20f58:      /* addsd */
        case 0xf30f58:      /* addss */
        case 0x0f59:        /* mulps */
        case 0x660f59:      /* mulpd */
        case 0xf20f59:      /* mulsd */
        case 0xf30f59:      /* mulss */
        case 0x0f5a:        /* cvtps2pd */
        case 0x660f5a:      /* cvtpd2ps */
        case 0xf20f5a:      /* cvtsd2ss */
        case 0xf30f5a:      /* cvtss2sd */
        case 0x0f5b:        /* cvtdq2ps */
        case 0x660f5b:      /* cvtps2dq */
        case 0xf30f5b:      /* cvttps2dq */
        case 0x0f5c:        /* subps */
        case 0x660f5c:      /* subpd */
        case 0xf20f5c:      /* subsd */
        case 0xf30f5c:      /* subss */
        case 0x0f5d:        /* minps */
        case 0x660f5d:      /* minpd */
        case 0xf20f5d:      /* minsd */
        case 0xf30f5d:      /* minss */
        case 0x0f5e:        /* divps */
        case 0x660f5e:      /* divpd */
        case 0xf20f5e:      /* divsd */
        case 0xf30f5e:      /* divss */
        case 0x0f5f:        /* maxps */
        case 0x660f5f:      /* maxpd */
        case 0xf20f5f:      /* maxsd */
        case 0xf30f5f:      /* maxss */
        case 0x660f60:      /* punpcklbw */
        case 0x660f61:      /* punpcklwd */
        case 0x660f62:      /* punpckldq */
        case 0x660f63:      /* packsswb */
        case 0x660f64:      /* pcmpgtb */
        case 0x660f65:      /* pcmpgtw */
        case 0x660f66:      /* pcmpgtd */
        case 0x660f67:      /* packuswb */
        case 0x660f68:      /* punpckhbw */
        case 0x660f69:      /* punpckhwd */
        case 0x660f6a:      /* punpckhdq */
        case 0x660f6b:      /* packssdw */
        case 0x660f6c:      /* punpcklqdq */
        case 0x660f6d:      /* punpckhqdq */
        case 0x660f6e:      /* movd */
        case 0x660f6f:      /* movdqa */
        case 0xf30f6f:      /* movdqu */
        case 0x660f70:      /* pshufd */
        case 0xf20f70:      /* pshuflw */
        case 0xf30f70:      /* pshufhw */
        case 0x660f74:      /* pcmpeqb */
        case 0x660f75:      /* pcmpeqw */
        case 0x660f76:      /* pcmpeqd */
        case 0x660f7c:      /* haddpd */
        case 0xf20f7c:      /* haddps */
        case 0x660f7d:      /* hsubpd */
        case 0xf20f7d:      /* hsubps */
        case 0xf30f7e:      /* movq */
        case 0x0fc2:        /* cmpps */
        case 0x660fc2:      /* cmppd */
        case 0xf20fc2:      /* cmpsd */
        case 0xf30fc2:      /* cmpss */
        case 0x660fc4:      /* pinsrw */
        case 0x0fc6:        /* shufps */
        case 0x660fc6:      /* shufpd */
        case 0x660fd0:      /* addsubpd */
        case 0xf20fd0:      /* addsubps */
        case 0x660fd1:      /* psrlw */
        case 0x660fd2:      /* psrld */
        case 0x660fd3:      /* psrlq */
        case 0x660fd4:      /* paddq */
        case 0x660fd5:      /* pmullw */
        case 0xf30fd6:      /* movq2dq */
        case 0x660fd8:      /* psubusb */
        case 0x660fd9:      /* psubusw */
        case 0x660fda:      /* pminub */
        case 0x660fdb:      /* pand */
        case 0x660fdc:      /* paddusb */
        case 0x660fdd:      /* paddusw */
        case 0x660fde:      /* pmaxub */
        case 0x660fdf:      /* pandn */
        case 0x660fe0:      /* pavgb */
        case 0x660fe1:      /* psraw */
        case 0x660fe2:      /* psrad */
        case 0x660fe3:      /* pavgw */
        case 0x660fe4:      /* pmulhuw */
        case 0x660fe5:      /* pmulhw */
        case 0x660fe6:      /* cvttpd2dq */
        case 0xf20fe6:      /* cvtpd2dq */
        case 0xf30fe6:      /* cvtdq2pd */
        case 0x660fe8:      /* psubsb */
        case 0x660fe9:      /* psubsw */
        case 0x660fea:      /* pminsw */
        case 0x660feb:      /* por */
        case 0x660fec:      /* paddsb */
        case 0x660fed:      /* paddsw */
        case 0x660fee:      /* pmaxsw */
        case 0x660fef:      /* pxor */
        case 0xf20ff0:      /* lddqu */
        case 0x660ff1:      /* psllw */
        case 0x660ff2:      /* pslld */
        case 0x660ff3:      /* psllq */
        case 0x660ff4:      /* pmuludq */
        case 0x660ff5:      /* pmaddwd */
        case 0x660ff6:      /* psadbw */
        case 0x660ff8:      /* psubb */
        case 0x660ff9:      /* psubw */
        case 0x660ffa:      /* psubd */
        case 0x660ffb:      /* psubq */
        case 0x660ffc:      /* paddb */
        case 0x660ffd:      /* paddw */
        case 0x660ffe:      /* paddd */
          if (i386_record_modrm (&ir))
	    return -1;
          ir.reg |= rex_r;
          if (!i386_xmm_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.reg))
            goto no_support;
          record_full_arch_list_add_reg (ir.regcache,
					 I387_XMM0_REGNUM (tdep) + ir.reg);
          if ((opcode & 0xfffffffc) == 0x660f3a60)
            I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
          break;

        case 0x0f11:        /* movups */
        case 0x660f11:      /* movupd */
        case 0xf30f11:      /* movss */
        case 0xf20f11:      /* movsd */
        case 0x0f13:        /* movlps */
        case 0x660f13:      /* movlpd */
        case 0x0f17:        /* movhps */
        case 0x660f17:      /* movhpd */
        case 0x0f29:        /* movaps */
        case 0x660f29:      /* movapd */
        case 0x660f3a14:    /* pextrb */
        case 0x660f3a15:    /* pextrw */
        case 0x660f3a16:    /* pextrd pextrq */
        case 0x660f3a17:    /* extractps */
        case 0x660f7f:      /* movdqa */
        case 0xf30f7f:      /* movdqu */
          if (i386_record_modrm (&ir))
	    return -1;
          if (ir.mod == 3)
            {
              if (opcode == 0x0f13 || opcode == 0x660f13
                  || opcode == 0x0f17 || opcode == 0x660f17)
                goto no_support;
              ir.rm |= ir.rex_b;
              if (!i386_xmm_regnum_p (gdbarch,
				      I387_XMM0_REGNUM (tdep) + ir.rm))
                goto no_support;
              record_full_arch_list_add_reg (ir.regcache,
					     I387_XMM0_REGNUM (tdep) + ir.rm);
            }
          else
            {
              switch (opcode)
                {
                  case 0x660f3a14:
                    ir.ot = OT_BYTE;
                    break;
                  case 0x660f3a15:
                    ir.ot = OT_WORD;
                    break;
                  case 0x660f3a16:
                    ir.ot = OT_LONG;
                    break;
                  case 0x660f3a17:
                    ir.ot = OT_QUAD;
                    break;
                  default:
                    ir.ot = OT_DQUAD;
                    break;
                }
              if (i386_record_lea_modrm (&ir))
                return -1;
            }
          break;

        case 0x0f2b:      /* movntps */
        case 0x660f2b:    /* movntpd */
        case 0x0fe7:      /* movntq */
        case 0x660fe7:    /* movntdq */
          if (ir.mod == 3)
            goto no_support;
          if (opcode == 0x0fe7)
            ir.ot = OT_QUAD;
          else
            ir.ot = OT_DQUAD;
          if (i386_record_lea_modrm (&ir))
            return -1;
          break;

        case 0xf30f2c:      /* cvttss2si */
        case 0xf20f2c:      /* cvttsd2si */
        case 0xf30f2d:      /* cvtss2si */
        case 0xf20f2d:      /* cvtsd2si */
        case 0xf20f38f0:    /* crc32 */
        case 0xf20f38f1:    /* crc32 */
        case 0x0f50:        /* movmskps */
        case 0x660f50:      /* movmskpd */
        case 0x0fc5:        /* pextrw */
        case 0x660fc5:      /* pextrw */
        case 0x0fd7:        /* pmovmskb */
        case 0x660fd7:      /* pmovmskb */
          I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg | rex_r);
          break;

        case 0x0f3800:    /* pshufb */
        case 0x0f3801:    /* phaddw */
        case 0x0f3802:    /* phaddd */
        case 0x0f3803:    /* phaddsw */
        case 0x0f3804:    /* pmaddubsw */
        case 0x0f3805:    /* phsubw */
        case 0x0f3806:    /* phsubd */
        case 0x0f3807:    /* phsubsw */
        case 0x0f3808:    /* psignb */
        case 0x0f3809:    /* psignw */
        case 0x0f380a:    /* psignd */
        case 0x0f380b:    /* pmulhrsw */
        case 0x0f381c:    /* pabsb */
        case 0x0f381d:    /* pabsw */
        case 0x0f381e:    /* pabsd */
        case 0x0f382b:    /* packusdw */
        case 0x0f3830:    /* pmovzxbw */
        case 0x0f3831:    /* pmovzxbd */
        case 0x0f3832:    /* pmovzxbq */
        case 0x0f3833:    /* pmovzxwd */
        case 0x0f3834:    /* pmovzxwq */
        case 0x0f3835:    /* pmovzxdq */
        case 0x0f3837:    /* pcmpgtq */
        case 0x0f3838:    /* pminsb */
        case 0x0f3839:    /* pminsd */
        case 0x0f383a:    /* pminuw */
        case 0x0f383b:    /* pminud */
        case 0x0f383c:    /* pmaxsb */
        case 0x0f383d:    /* pmaxsd */
        case 0x0f383e:    /* pmaxuw */
        case 0x0f383f:    /* pmaxud */
        case 0x0f3840:    /* pmulld */
        case 0x0f3841:    /* phminposuw */
        case 0x0f3a0f:    /* palignr */
        case 0x0f60:      /* punpcklbw */
        case 0x0f61:      /* punpcklwd */
        case 0x0f62:      /* punpckldq */
        case 0x0f63:      /* packsswb */
        case 0x0f64:      /* pcmpgtb */
        case 0x0f65:      /* pcmpgtw */
        case 0x0f66:      /* pcmpgtd */
        case 0x0f67:      /* packuswb */
        case 0x0f68:      /* punpckhbw */
        case 0x0f69:      /* punpckhwd */
        case 0x0f6a:      /* punpckhdq */
        case 0x0f6b:      /* packssdw */
        case 0x0f6e:      /* movd */
        case 0x0f6f:      /* movq */
        case 0x0f70:      /* pshufw */
        case 0x0f74:      /* pcmpeqb */
        case 0x0f75:      /* pcmpeqw */
        case 0x0f76:      /* pcmpeqd */
        case 0x0fc4:      /* pinsrw */
        case 0x0fd1:      /* psrlw */
        case 0x0fd2:      /* psrld */
        case 0x0fd3:      /* psrlq */
        case 0x0fd4:      /* paddq */
        case 0x0fd5:      /* pmullw */
        case 0xf20fd6:    /* movdq2q */
        case 0x0fd8:      /* psubusb */
        case 0x0fd9:      /* psubusw */
        case 0x0fda:      /* pminub */
        case 0x0fdb:      /* pand */
        case 0x0fdc:      /* paddusb */
        case 0x0fdd:      /* paddusw */
        case 0x0fde:      /* pmaxub */
        case 0x0fdf:      /* pandn */
        case 0x0fe0:      /* pavgb */
        case 0x0fe1:      /* psraw */
        case 0x0fe2:      /* psrad */
        case 0x0fe3:      /* pavgw */
        case 0x0fe4:      /* pmulhuw */
        case 0x0fe5:      /* pmulhw */
        case 0x0fe8:      /* psubsb */
        case 0x0fe9:      /* psubsw */
        case 0x0fea:      /* pminsw */
        case 0x0feb:      /* por */
        case 0x0fec:      /* paddsb */
        case 0x0fed:      /* paddsw */
        case 0x0fee:      /* pmaxsw */
        case 0x0fef:      /* pxor */
        case 0x0ff1:      /* psllw */
        case 0x0ff2:      /* pslld */
        case 0x0ff3:      /* psllq */
        case 0x0ff4:      /* pmuludq */
        case 0x0ff5:      /* pmaddwd */
        case 0x0ff6:      /* psadbw */
        case 0x0ff8:      /* psubb */
        case 0x0ff9:      /* psubw */
        case 0x0ffa:      /* psubd */
        case 0x0ffb:      /* psubq */
        case 0x0ffc:      /* paddb */
        case 0x0ffd:      /* paddw */
        case 0x0ffe:      /* paddd */
          if (i386_record_modrm (&ir))
	    return -1;
          if (!i386_mmx_regnum_p (gdbarch, I387_MM0_REGNUM (tdep) + ir.reg))
            goto no_support;
          record_full_arch_list_add_reg (ir.regcache,
					 I387_MM0_REGNUM (tdep) + ir.reg);
          break;

        case 0x0f71:    /* psllw */
        case 0x0f72:    /* pslld */
        case 0x0f73:    /* psllq */
          if (i386_record_modrm (&ir))
	    return -1;
          if (!i386_mmx_regnum_p (gdbarch, I387_MM0_REGNUM (tdep) + ir.rm))
            goto no_support;
          record_full_arch_list_add_reg (ir.regcache,
					 I387_MM0_REGNUM (tdep) + ir.rm);
          break;

        case 0x660f71:    /* psllw */
        case 0x660f72:    /* pslld */
        case 0x660f73:    /* psllq */
          if (i386_record_modrm (&ir))
	    return -1;
          ir.rm |= ir.rex_b;
          if (!i386_xmm_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.rm))
            goto no_support;
          record_full_arch_list_add_reg (ir.regcache,
					 I387_XMM0_REGNUM (tdep) + ir.rm);
          break;

        case 0x0f7e:      /* movd */
        case 0x660f7e:    /* movd */
          if (i386_record_modrm (&ir))
	    return -1;
          if (ir.mod == 3)
            I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
          else
            {
              if (ir.dflag == 2)
                ir.ot = OT_QUAD;
              else
                ir.ot = OT_LONG;
              if (i386_record_lea_modrm (&ir))
                return -1;
            }
          break;

        case 0x0f7f:    /* movq */
          if (i386_record_modrm (&ir))
	    return -1;
          if (ir.mod == 3)
            {
              if (!i386_mmx_regnum_p (gdbarch, I387_MM0_REGNUM (tdep) + ir.rm))
                goto no_support;
              record_full_arch_list_add_reg (ir.regcache,
					     I387_MM0_REGNUM (tdep) + ir.rm);
            }
          else
            {
              ir.ot = OT_QUAD;
              if (i386_record_lea_modrm (&ir))
                return -1;
            }
          break;

        case 0xf30fb8:    /* popcnt */
          if (i386_record_modrm (&ir))
	    return -1;
          I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
          I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
          break;

        case 0x660fd6:    /* movq */
          if (i386_record_modrm (&ir))
	    return -1;
          if (ir.mod == 3)
            {
              ir.rm |= ir.rex_b;
              if (!i386_xmm_regnum_p (gdbarch,
				      I387_XMM0_REGNUM (tdep) + ir.rm))
                goto no_support;
              record_full_arch_list_add_reg (ir.regcache,
					     I387_XMM0_REGNUM (tdep) + ir.rm);
            }
          else
            {
              ir.ot = OT_QUAD;
              if (i386_record_lea_modrm (&ir))
                return -1;
            }
          break;

        case 0x660f3817:    /* ptest */
        case 0x0f2e:        /* ucomiss */
        case 0x660f2e:      /* ucomisd */
        case 0x0f2f:        /* comiss */
        case 0x660f2f:      /* comisd */
          I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
          break;

        case 0x0ff7:    /* maskmovq */
          regcache_raw_read_unsigned (ir.regcache,
                                      ir.regmap[X86_RECORD_REDI_REGNUM],
                                      &addr);
          if (record_full_arch_list_add_mem (addr, 64))
            return -1;
          break;

        case 0x660ff7:    /* maskmovdqu */
          regcache_raw_read_unsigned (ir.regcache,
                                      ir.regmap[X86_RECORD_REDI_REGNUM],
                                      &addr);
          if (record_full_arch_list_add_mem (addr, 128))
            return -1;
          break;

        default:
          goto no_support;
          break;
        }
      break;

    default:
      goto no_support;
      break;
    }

  /* In the future, maybe still need to deal with need_dasm.  */
  I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REIP_REGNUM);
  if (record_full_arch_list_add_end ())
    return -1;

  return 0;

 no_support:
  printf_unfiltered (_("Process record does not support instruction 0x%02x "
                       "at address %s.\n"),
                     (unsigned int) (opcode),
                     paddress (gdbarch, ir.orig_addr));
  return -1;
}

static const int i386_record_regmap[] =
{
  I386_EAX_REGNUM, I386_ECX_REGNUM, I386_EDX_REGNUM, I386_EBX_REGNUM,
  I386_ESP_REGNUM, I386_EBP_REGNUM, I386_ESI_REGNUM, I386_EDI_REGNUM,
  0, 0, 0, 0, 0, 0, 0, 0,
  I386_EIP_REGNUM, I386_EFLAGS_REGNUM, I386_CS_REGNUM, I386_SS_REGNUM,
  I386_DS_REGNUM, I386_ES_REGNUM, I386_FS_REGNUM, I386_GS_REGNUM
};

/* Check that the given address appears suitable for a fast
   tracepoint, which on x86-64 means that we need an instruction of at
   least 5 bytes, so that we can overwrite it with a 4-byte-offset
   jump and not have to worry about program jumps to an address in the
   middle of the tracepoint jump.  On x86, it may be possible to use
   4-byte jumps with a 2-byte offset to a trampoline located in the
   bottom 64 KiB of memory.  Returns 1 if OK, and writes a size
   of instruction to replace, and 0 if not, plus an explanatory
   string.  */

static int
i386_fast_tracepoint_valid_at (struct gdbarch *gdbarch, CORE_ADDR addr,
			       char **msg)
{
  int len, jumplen;

  /*  Ask the target for the minimum instruction length supported.  */
  jumplen = target_get_min_fast_tracepoint_insn_len ();

  if (jumplen < 0)
    {
      /* If the target does not support the get_min_fast_tracepoint_insn_len
	 operation, assume that fast tracepoints will always be implemented
	 using 4-byte relative jumps on both x86 and x86-64.  */
      jumplen = 5;
    }
  else if (jumplen == 0)
    {
      /* If the target does support get_min_fast_tracepoint_insn_len but
	 returns zero, then the IPA has not loaded yet.  In this case,
	 we optimistically assume that truncated 2-byte relative jumps
	 will be available on x86, and compensate later if this assumption
	 turns out to be incorrect.  On x86-64 architectures, 4-byte relative
	 jumps will always be used.  */
      jumplen = (register_size (gdbarch, 0) == 8) ? 5 : 4;
    }

  /* Check for fit.  */
  len = gdb_insn_length (gdbarch, addr);

  if (len < jumplen)
    {
      /* Return a bit of target-specific detail to add to the caller's
	 generic failure message.  */
      if (msg)
	*msg = xstrprintf (_("; instruction is only %d bytes long, "
			     "need at least %d bytes for the jump"),
			   len, jumplen);
      return 0;
    }
  else
    {
      if (msg)
	*msg = NULL;
      return 1;
    }
}

/* Return a floating-point format for a floating-point variable of
   length LEN in bits.  If non-NULL, NAME is the name of its type.
   If no suitable type is found, return NULL.  */

const struct floatformat **
i386_floatformat_for_type (struct gdbarch *gdbarch,
			   const char *name, int len)
{
  if (len == 128 && name)
    if (strcmp (name, "__float128") == 0
	|| strcmp (name, "_Float128") == 0
	|| strcmp (name, "complex _Float128") == 0)
      return floatformats_ia64_quad;

  return default_floatformat_for_type (gdbarch, name, len);
}

static int
i386_validate_tdesc_p (struct gdbarch_tdep *tdep,
		       struct tdesc_arch_data *tdesc_data)
{
  const struct target_desc *tdesc = tdep->tdesc;
  const struct tdesc_feature *feature_core;

  const struct tdesc_feature *feature_sse, *feature_avx, *feature_mpx,
			     *feature_avx512, *feature_pkeys;
  int i, num_regs, valid_p;

  if (! tdesc_has_registers (tdesc))
    return 0;

  /* Get core registers.  */
  feature_core = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.core");
  if (feature_core == NULL)
    return 0;

  /* Get SSE registers.  */
  feature_sse = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.sse");

  /* Try AVX registers.  */
  feature_avx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx");

  /* Try MPX registers.  */
  feature_mpx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.mpx");

  /* Try AVX512 registers.  */
  feature_avx512 = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx512");

  /* Try PKEYS  */
  feature_pkeys = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pkeys");

  valid_p = 1;

  /* The XCR0 bits.  */
  if (feature_avx512)
    {
      /* AVX512 register description requires AVX register description.  */
      if (!feature_avx)
	return 0;

      tdep->xcr0 = X86_XSTATE_AVX_AVX512_MASK;

      /* It may have been set by OSABI initialization function.  */
      if (tdep->k0_regnum < 0)
	{
	  tdep->k_register_names = i386_k_names;
	  tdep->k0_regnum = I386_K0_REGNUM;
	}

      for (i = 0; i < I387_NUM_K_REGS; i++)
	valid_p &= tdesc_numbered_register (feature_avx512, tdesc_data,
					    tdep->k0_regnum + i,
					    i386_k_names[i]);

      if (tdep->num_zmm_regs == 0)
	{
	  tdep->zmmh_register_names = i386_zmmh_names;
	  tdep->num_zmm_regs = 8;
	  tdep->zmm0h_regnum = I386_ZMM0H_REGNUM;
	}

      for (i = 0; i < tdep->num_zmm_regs; i++)
	valid_p &= tdesc_numbered_register (feature_avx512, tdesc_data,
					    tdep->zmm0h_regnum + i,
					    tdep->zmmh_register_names[i]);

      for (i = 0; i < tdep->num_xmm_avx512_regs; i++)
	valid_p &= tdesc_numbered_register (feature_avx512, tdesc_data,
					    tdep->xmm16_regnum + i,
					    tdep->xmm_avx512_register_names[i]);

      for (i = 0; i < tdep->num_ymm_avx512_regs; i++)
	valid_p &= tdesc_numbered_register (feature_avx512, tdesc_data,
					    tdep->ymm16h_regnum + i,
					    tdep->ymm16h_register_names[i]);
    }
  if (feature_avx)
    {
      /* AVX register description requires SSE register description.  */
      if (!feature_sse)
	return 0;

      if (!feature_avx512)
	tdep->xcr0 = X86_XSTATE_AVX_MASK;

      /* It may have been set by OSABI initialization function.  */
      if (tdep->num_ymm_regs == 0)
	{
	  tdep->ymmh_register_names = i386_ymmh_names;
	  tdep->num_ymm_regs = 8;
	  tdep->ymm0h_regnum = I386_YMM0H_REGNUM;
	}

      for (i = 0; i < tdep->num_ymm_regs; i++)
	valid_p &= tdesc_numbered_register (feature_avx, tdesc_data,
					    tdep->ymm0h_regnum + i,
					    tdep->ymmh_register_names[i]);
    }
  else if (feature_sse)
    tdep->xcr0 = X86_XSTATE_SSE_MASK;
  else
    {
      tdep->xcr0 = X86_XSTATE_X87_MASK;
      tdep->num_xmm_regs = 0;
    }

  num_regs = tdep->num_core_regs;
  for (i = 0; i < num_regs; i++)
    valid_p &= tdesc_numbered_register (feature_core, tdesc_data, i,
					tdep->register_names[i]);

  if (feature_sse)
    {
      /* Need to include %mxcsr, so add one.  */
      num_regs += tdep->num_xmm_regs + 1;
      for (; i < num_regs; i++)
	valid_p &= tdesc_numbered_register (feature_sse, tdesc_data, i,
					    tdep->register_names[i]);
    }

  if (feature_mpx)
    {
      tdep->xcr0 |= X86_XSTATE_MPX_MASK;

      if (tdep->bnd0r_regnum < 0)
	{
	  tdep->mpx_register_names = i386_mpx_names;
	  tdep->bnd0r_regnum = I386_BND0R_REGNUM;
	  tdep->bndcfgu_regnum = I386_BNDCFGU_REGNUM;
	}

      for (i = 0; i < I387_NUM_MPX_REGS; i++)
	valid_p &= tdesc_numbered_register (feature_mpx, tdesc_data,
	    I387_BND0R_REGNUM (tdep) + i,
	    tdep->mpx_register_names[i]);
    }

  if (feature_pkeys)
    {
      tdep->xcr0 |= X86_XSTATE_PKRU;
      if (tdep->pkru_regnum < 0)
	{
	  tdep->pkeys_register_names = i386_pkeys_names;
	  tdep->pkru_regnum = I386_PKRU_REGNUM;
	  tdep->num_pkeys_regs = 1;
	}

      for (i = 0; i < I387_NUM_PKEYS_REGS; i++)
	valid_p &= tdesc_numbered_register (feature_pkeys, tdesc_data,
					    I387_PKRU_REGNUM (tdep) + i,
					    tdep->pkeys_register_names[i]);
    }

  return valid_p;
}


/* Note: This is called for both i386 and amd64.  */

static struct gdbarch *
i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
  struct gdbarch_tdep *tdep;
  struct gdbarch *gdbarch;
  struct tdesc_arch_data *tdesc_data;
  const struct target_desc *tdesc;
  int mm0_regnum;
  int ymm0_regnum;
  int bnd0_regnum;
  int num_bnd_cooked;

  /* If there is already a candidate, use it.  */
  arches = gdbarch_list_lookup_by_info (arches, &info);
  if (arches != NULL)
    return arches->gdbarch;

  /* Allocate space for the new architecture.  Assume i386 for now.  */
  tdep = XCNEW (struct gdbarch_tdep);
  gdbarch = gdbarch_alloc (&info, tdep);

  /* General-purpose registers.  */
  tdep->gregset_reg_offset = NULL;
  tdep->gregset_num_regs = I386_NUM_GREGS;
  tdep->sizeof_gregset = 0;

  /* Floating-point registers.  */
  tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
  tdep->fpregset = &i386_fpregset;

  /* The default settings include the FPU registers, the MMX registers
     and the SSE registers.  This can be overridden for a specific ABI
     by adjusting the members `st0_regnum', `mm0_regnum' and
     `num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
     will show up in the output of "info all-registers".  */

  tdep->st0_regnum = I386_ST0_REGNUM;

  /* I386_NUM_XREGS includes %mxcsr, so substract one.  */
  tdep->num_xmm_regs = I386_NUM_XREGS - 1;

  tdep->jb_pc_offset = -1;
  tdep->struct_return = pcc_struct_return;
  tdep->sigtramp_start = 0;
  tdep->sigtramp_end = 0;
  tdep->sigtramp_p = i386_sigtramp_p;
  tdep->sigcontext_addr = NULL;
  tdep->sc_reg_offset = NULL;
  tdep->sc_pc_offset = -1;
  tdep->sc_sp_offset = -1;

  tdep->xsave_xcr0_offset = -1;

  tdep->record_regmap = i386_record_regmap;

  set_gdbarch_long_long_align_bit (gdbarch, 32);

  /* The format used for `long double' on almost all i386 targets is
     the i387 extended floating-point format.  In fact, of all targets
     in the GCC 2.95 tree, only OSF/1 does it different, and insists
     on having a `long double' that's not `long' at all.  */
  set_gdbarch_long_double_format (gdbarch, floatformats_i387_ext);

  /* Although the i387 extended floating-point has only 80 significant
     bits, a `long double' actually takes up 96, probably to enforce
     alignment.  */
  set_gdbarch_long_double_bit (gdbarch, 96);

  /* Support for floating-point data type variants.  */
  set_gdbarch_floatformat_for_type (gdbarch, i386_floatformat_for_type);

  /* Register numbers of various important registers.  */
  set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM); /* %esp */
  set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM); /* %eip */
  set_gdbarch_ps_regnum (gdbarch, I386_EFLAGS_REGNUM); /* %eflags */
  set_gdbarch_fp0_regnum (gdbarch, I386_ST0_REGNUM); /* %st(0) */

  /* NOTE: kettenis/20040418: GCC does have two possible register
     numbering schemes on the i386: dbx and SVR4.  These schemes
     differ in how they number %ebp, %esp, %eflags, and the
     floating-point registers, and are implemented by the arrays
     dbx_register_map[] and svr4_dbx_register_map in
     gcc/config/i386.c.  GCC also defines a third numbering scheme in
     gcc/config/i386.c, which it designates as the "default" register
     map used in 64bit mode.  This last register numbering scheme is
     implemented in dbx64_register_map, and is used for AMD64; see
     amd64-tdep.c.

     Currently, each GCC i386 target always uses the same register
     numbering scheme across all its supported debugging formats
     i.e. SDB (COFF), stabs and DWARF 2.  This is because
     gcc/sdbout.c, gcc/dbxout.c and gcc/dwarf2out.c all use the
     DBX_REGISTER_NUMBER macro which is defined by each target's
     respective config header in a manner independent of the requested
     output debugging format.

     This does not match the arrangement below, which presumes that
     the SDB and stabs numbering schemes differ from the DWARF and
     DWARF 2 ones.  The reason for this arrangement is that it is
     likely to get the numbering scheme for the target's
     default/native debug format right.  For targets where GCC is the
     native compiler (FreeBSD, NetBSD, OpenBSD, GNU/Linux) or for
     targets where the native toolchain uses a different numbering
     scheme for a particular debug format (stabs-in-ELF on Solaris)
     the defaults below will have to be overridden, like
     i386_elf_init_abi() does.  */

  /* Use the dbx register numbering scheme for stabs and COFF.  */
  set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
  set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);

  /* Use the SVR4 register numbering scheme for DWARF 2.  */
  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_dwarf_reg_to_regnum);

  /* We don't set gdbarch_stab_reg_to_regnum, since ECOFF doesn't seem to
     be in use on any of the supported i386 targets.  */

  set_gdbarch_print_float_info (gdbarch, i387_print_float_info);

  set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);

  /* Call dummy code.  */
  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
  set_gdbarch_push_dummy_code (gdbarch, i386_push_dummy_code);
  set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
  set_gdbarch_frame_align (gdbarch, i386_frame_align);

  set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
  set_gdbarch_register_to_value (gdbarch,  i386_register_to_value);
  set_gdbarch_value_to_register (gdbarch, i386_value_to_register);

  set_gdbarch_return_value (gdbarch, i386_return_value);

  set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);

  /* Stack grows downward.  */
  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);

  set_gdbarch_breakpoint_kind_from_pc (gdbarch, i386_breakpoint::kind_from_pc);
  set_gdbarch_sw_breakpoint_from_kind (gdbarch, i386_breakpoint::bp_from_kind);

  set_gdbarch_decr_pc_after_break (gdbarch, 1);
  set_gdbarch_max_insn_length (gdbarch, I386_MAX_INSN_LEN);

  set_gdbarch_frame_args_skip (gdbarch, 8);

  set_gdbarch_print_insn (gdbarch, i386_print_insn);

  set_gdbarch_dummy_id (gdbarch, i386_dummy_id);

  set_gdbarch_unwind_pc (gdbarch, i386_unwind_pc);

  /* Add the i386 register groups.  */
  i386_add_reggroups (gdbarch);
  tdep->register_reggroup_p = i386_register_reggroup_p;

  /* Helper for function argument information.  */
  set_gdbarch_fetch_pointer_argument (gdbarch, i386_fetch_pointer_argument);

  /* Hook the function epilogue frame unwinder.  This unwinder is
     appended to the list first, so that it supercedes the DWARF
     unwinder in function epilogues (where the DWARF unwinder
     currently fails).  */
  frame_unwind_append_unwinder (gdbarch, &i386_epilogue_frame_unwind);

  /* Hook in the DWARF CFI frame unwinder.  This unwinder is appended
     to the list before the prologue-based unwinders, so that DWARF
     CFI info will be used if it is available.  */
  dwarf2_append_unwinders (gdbarch);

  frame_base_set_default (gdbarch, &i386_frame_base);

  /* Pseudo registers may be changed by amd64_init_abi.  */
  set_gdbarch_pseudo_register_read_value (gdbarch,
					  i386_pseudo_register_read_value);
  set_gdbarch_pseudo_register_write (gdbarch, i386_pseudo_register_write);
  set_gdbarch_ax_pseudo_register_collect (gdbarch,
					  i386_ax_pseudo_register_collect);

  set_tdesc_pseudo_register_type (gdbarch, i386_pseudo_register_type);
  set_tdesc_pseudo_register_name (gdbarch, i386_pseudo_register_name);

  /* Override the normal target description method to make the AVX
     upper halves anonymous.  */
  set_gdbarch_register_name (gdbarch, i386_register_name);

  /* Even though the default ABI only includes general-purpose registers,
     floating-point registers and the SSE registers, we have to leave a
     gap for the upper AVX, MPX and AVX512 registers.  */
  set_gdbarch_num_regs (gdbarch, I386_PKEYS_NUM_REGS);

  set_gdbarch_gnu_triplet_regexp (gdbarch, i386_gnu_triplet_regexp);

  /* Get the x86 target description from INFO.  */
  tdesc = info.target_desc;
  if (! tdesc_has_registers (tdesc))
    tdesc = i386_target_description (X86_XSTATE_SSE_MASK);
  tdep->tdesc = tdesc;

  tdep->num_core_regs = I386_NUM_GREGS + I387_NUM_REGS;
  tdep->register_names = i386_register_names;

  /* No upper YMM registers.  */
  tdep->ymmh_register_names = NULL;
  tdep->ymm0h_regnum = -1;

  /* No upper ZMM registers.  */
  tdep->zmmh_register_names = NULL;
  tdep->zmm0h_regnum = -1;

  /* No high XMM registers.  */
  tdep->xmm_avx512_register_names = NULL;
  tdep->xmm16_regnum = -1;

  /* No upper YMM16-31 registers.  */
  tdep->ymm16h_register_names = NULL;
  tdep->ymm16h_regnum = -1;

  tdep->num_byte_regs = 8;
  tdep->num_word_regs = 8;
  tdep->num_dword_regs = 0;
  tdep->num_mmx_regs = 8;
  tdep->num_ymm_regs = 0;

  /* No MPX registers.  */
  tdep->bnd0r_regnum = -1;
  tdep->bndcfgu_regnum = -1;

  /* No AVX512 registers.  */
  tdep->k0_regnum = -1;
  tdep->num_zmm_regs = 0;
  tdep->num_ymm_avx512_regs = 0;
  tdep->num_xmm_avx512_regs = 0;

  /* No PKEYS registers  */
  tdep->pkru_regnum = -1;
  tdep->num_pkeys_regs = 0;

  tdesc_data = tdesc_data_alloc ();

  set_gdbarch_relocate_instruction (gdbarch, i386_relocate_instruction);

  set_gdbarch_gen_return_address (gdbarch, i386_gen_return_address);

  set_gdbarch_insn_is_call (gdbarch, i386_insn_is_call);
  set_gdbarch_insn_is_ret (gdbarch, i386_insn_is_ret);
  set_gdbarch_insn_is_jump (gdbarch, i386_insn_is_jump);

  /* Hook in ABI-specific overrides, if they have been registered.
     Note: If INFO specifies a 64 bit arch, this is where we turn
     a 32-bit i386 into a 64-bit amd64.  */
  info.tdesc_data = tdesc_data;
  gdbarch_init_osabi (info, gdbarch);

  if (!i386_validate_tdesc_p (tdep, tdesc_data))
    {
      tdesc_data_cleanup (tdesc_data);
      xfree (tdep);
      gdbarch_free (gdbarch);
      return NULL;
    }

  num_bnd_cooked = (tdep->bnd0r_regnum > 0 ? I387_NUM_BND_REGS : 0);

  /* Wire in pseudo registers.  Number of pseudo registers may be
     changed.  */
  set_gdbarch_num_pseudo_regs (gdbarch, (tdep->num_byte_regs
					 + tdep->num_word_regs
					 + tdep->num_dword_regs
					 + tdep->num_mmx_regs
					 + tdep->num_ymm_regs
					 + num_bnd_cooked
					 + tdep->num_ymm_avx512_regs
					 + tdep->num_zmm_regs));

  /* Target description may be changed.  */
  tdesc = tdep->tdesc;

  tdesc_use_registers (gdbarch, tdesc, tdesc_data);

  /* Override gdbarch_register_reggroup_p set in tdesc_use_registers.  */
  set_gdbarch_register_reggroup_p (gdbarch, tdep->register_reggroup_p);

  /* Make %al the first pseudo-register.  */
  tdep->al_regnum = gdbarch_num_regs (gdbarch);
  tdep->ax_regnum = tdep->al_regnum + tdep->num_byte_regs;

  ymm0_regnum = tdep->ax_regnum + tdep->num_word_regs;
  if (tdep->num_dword_regs)
    {
      /* Support dword pseudo-register if it hasn't been disabled.  */
      tdep->eax_regnum = ymm0_regnum;
      ymm0_regnum += tdep->num_dword_regs;
    }
  else
    tdep->eax_regnum = -1;

  mm0_regnum = ymm0_regnum;
  if (tdep->num_ymm_regs)
    {
      /* Support YMM pseudo-register if it is available.  */
      tdep->ymm0_regnum = ymm0_regnum;
      mm0_regnum += tdep->num_ymm_regs;
    }
  else
    tdep->ymm0_regnum = -1;

  if (tdep->num_ymm_avx512_regs)
    {
      /* Support YMM16-31 pseudo registers if available.  */
      tdep->ymm16_regnum = mm0_regnum;
      mm0_regnum += tdep->num_ymm_avx512_regs;
    }
  else
    tdep->ymm16_regnum = -1;

  if (tdep->num_zmm_regs)
    {
      /* Support ZMM pseudo-register if it is available.  */
      tdep->zmm0_regnum = mm0_regnum;
      mm0_regnum += tdep->num_zmm_regs;
    }
  else
    tdep->zmm0_regnum = -1;

  bnd0_regnum = mm0_regnum;
  if (tdep->num_mmx_regs != 0)
    {
      /* Support MMX pseudo-register if MMX hasn't been disabled.  */
      tdep->mm0_regnum = mm0_regnum;
      bnd0_regnum += tdep->num_mmx_regs;
    }
  else
    tdep->mm0_regnum = -1;

  if (tdep->bnd0r_regnum > 0)
      tdep->bnd0_regnum = bnd0_regnum;
  else
    tdep-> bnd0_regnum = -1;

  /* Hook in the legacy prologue-based unwinders last (fallback).  */
  frame_unwind_append_unwinder (gdbarch, &i386_stack_tramp_frame_unwind);
  frame_unwind_append_unwinder (gdbarch, &i386_sigtramp_frame_unwind);
  frame_unwind_append_unwinder (gdbarch, &i386_frame_unwind);

  /* If we have a register mapping, enable the generic core file
     support, unless it has already been enabled.  */
  if (tdep->gregset_reg_offset
      && !gdbarch_iterate_over_regset_sections_p (gdbarch))
    set_gdbarch_iterate_over_regset_sections
      (gdbarch, i386_iterate_over_regset_sections);

  set_gdbarch_fast_tracepoint_valid_at (gdbarch,
					i386_fast_tracepoint_valid_at);

  return gdbarch;
}



/* Return the target description for a specified XSAVE feature mask.  */

const struct target_desc *
i386_target_description (uint64_t xcr0)
{
  static target_desc *i386_tdescs \
    [2/*SSE*/][2/*AVX*/][2/*MPX*/][2/*AVX512*/][2/*PKRU*/] = {};
  target_desc **tdesc;

  tdesc = &i386_tdescs[(xcr0 & X86_XSTATE_SSE) ? 1 : 0]
    [(xcr0 & X86_XSTATE_AVX) ? 1 : 0]
    [(xcr0 & X86_XSTATE_MPX) ? 1 : 0]
    [(xcr0 & X86_XSTATE_AVX512) ? 1 : 0]
    [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0];

  if (*tdesc == NULL)
    *tdesc = i386_create_target_description (xcr0, false);

  return *tdesc;
}

#define MPX_BASE_MASK (~(ULONGEST) 0xfff)

/* Find the bound directory base address.  */

static unsigned long
i386_mpx_bd_base (void)
{
  struct regcache *rcache;
  struct gdbarch_tdep *tdep;
  ULONGEST ret;
  enum register_status regstatus;

  rcache = get_current_regcache ();
  tdep = gdbarch_tdep (rcache->arch ());

  regstatus = regcache_raw_read_unsigned (rcache, tdep->bndcfgu_regnum, &ret);

  if (regstatus != REG_VALID)
    error (_("BNDCFGU register invalid, read status %d."), regstatus);

  return ret & MPX_BASE_MASK;
}

int
i386_mpx_enabled (void)
{
  const struct gdbarch_tdep *tdep = gdbarch_tdep (get_current_arch ());
  const struct target_desc *tdesc = tdep->tdesc;

  return (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.mpx") != NULL);
}

#define MPX_BD_MASK     0xfffffff00000ULL	/* select bits [47:20]  */
#define MPX_BT_MASK     0x0000000ffff8	        /* select bits [19:3]   */
#define MPX_BD_MASK_32  0xfffff000	        /* select bits [31:12]  */
#define MPX_BT_MASK_32  0x00000ffc	        /* select bits [11:2]   */

/* Find the bound table entry given the pointer location and the base
   address of the table.  */

static CORE_ADDR
i386_mpx_get_bt_entry (CORE_ADDR ptr, CORE_ADDR bd_base)
{
  CORE_ADDR offset1;
  CORE_ADDR offset2;
  CORE_ADDR mpx_bd_mask, bd_ptr_r_shift, bd_ptr_l_shift;
  CORE_ADDR bt_mask, bt_select_r_shift, bt_select_l_shift;
  CORE_ADDR bd_entry_addr;
  CORE_ADDR bt_addr;
  CORE_ADDR bd_entry;
  struct gdbarch *gdbarch = get_current_arch ();
  struct type *data_ptr_type = builtin_type (gdbarch)->builtin_data_ptr;


  if (gdbarch_ptr_bit (gdbarch) == 64)
    {
      mpx_bd_mask = (CORE_ADDR) MPX_BD_MASK;
      bd_ptr_r_shift = 20;
      bd_ptr_l_shift = 3;
      bt_select_r_shift = 3;
      bt_select_l_shift = 5;
      bt_mask = (CORE_ADDR) MPX_BT_MASK;

      if ( sizeof (CORE_ADDR) == 4)
	error (_("bound table examination not supported\
 for 64-bit process with 32-bit GDB"));
    }
  else
    {
      mpx_bd_mask = MPX_BD_MASK_32;
      bd_ptr_r_shift = 12;
      bd_ptr_l_shift = 2;
      bt_select_r_shift = 2;
      bt_select_l_shift = 4;
      bt_mask = MPX_BT_MASK_32;
    }

  offset1 = ((ptr & mpx_bd_mask) >> bd_ptr_r_shift) << bd_ptr_l_shift;
  bd_entry_addr = bd_base + offset1;
  bd_entry = read_memory_typed_address (bd_entry_addr, data_ptr_type);

  if ((bd_entry & 0x1) == 0)
    error (_("Invalid bounds directory entry at %s."),
	   paddress (get_current_arch (), bd_entry_addr));

  /* Clearing status bit.  */
  bd_entry--;
  bt_addr = bd_entry & ~bt_select_r_shift;
  offset2 = ((ptr & bt_mask) >> bt_select_r_shift) << bt_select_l_shift;

  return bt_addr + offset2;
}

/* Print routine for the mpx bounds.  */

static void
i386_mpx_print_bounds (const CORE_ADDR bt_entry[4])
{
  struct ui_out *uiout = current_uiout;
  LONGEST size;
  struct gdbarch *gdbarch = get_current_arch ();
  CORE_ADDR onecompl = ~((CORE_ADDR) 0);
  int bounds_in_map = ((~bt_entry[1] == 0 && bt_entry[0] == onecompl) ? 1 : 0);

  if (bounds_in_map == 1)
    {
      uiout->text ("Null bounds on map:");
      uiout->text (" pointer value = ");
      uiout->field_core_addr ("pointer-value", gdbarch, bt_entry[2]);
      uiout->text (".");
      uiout->text ("\n");
    }
  else
    {
      uiout->text ("{lbound = ");
      uiout->field_core_addr ("lower-bound", gdbarch, bt_entry[0]);
      uiout->text (", ubound = ");

      /* The upper bound is stored in 1's complement.  */
      uiout->field_core_addr ("upper-bound", gdbarch, ~bt_entry[1]);
      uiout->text ("}: pointer value = ");
      uiout->field_core_addr ("pointer-value", gdbarch, bt_entry[2]);

      if (gdbarch_ptr_bit (gdbarch) == 64)
	size = ( (~(int64_t) bt_entry[1]) - (int64_t) bt_entry[0]);
      else
	size = ( ~((int32_t) bt_entry[1]) - (int32_t) bt_entry[0]);

      /* In case the bounds are 0x0 and 0xffff... the difference will be -1.
	 -1 represents in this sense full memory access, and there is no need
	 one to the size.  */

      size = (size > -1 ? size + 1 : size);
      uiout->text (", size = ");
      uiout->field_fmt ("size", "%s", plongest (size));

      uiout->text (", metadata = ");
      uiout->field_core_addr ("metadata", gdbarch, bt_entry[3]);
      uiout->text ("\n");
    }
}

/* Implement the command "show mpx bound".  */

static void
i386_mpx_info_bounds (const char *args, int from_tty)
{
  CORE_ADDR bd_base = 0;
  CORE_ADDR addr;
  CORE_ADDR bt_entry_addr = 0;
  CORE_ADDR bt_entry[4];
  int i;
  struct gdbarch *gdbarch = get_current_arch ();
  struct type *data_ptr_type = builtin_type (gdbarch)->builtin_data_ptr;

  if (gdbarch_bfd_arch_info (gdbarch)->arch != bfd_arch_i386
      || !i386_mpx_enabled ())
    {
      printf_unfiltered (_("Intel Memory Protection Extensions not "
			   "supported on this target.\n"));
      return;
    }

  if (args == NULL)
    {
      printf_unfiltered (_("Address of pointer variable expected.\n"));
      return;
    }

  addr = parse_and_eval_address (args);

  bd_base = i386_mpx_bd_base ();
  bt_entry_addr = i386_mpx_get_bt_entry (addr, bd_base);

  memset (bt_entry, 0, sizeof (bt_entry));

  for (i = 0; i < 4; i++)
    bt_entry[i] = read_memory_typed_address (bt_entry_addr
					     + i * TYPE_LENGTH (data_ptr_type),
					     data_ptr_type);

  i386_mpx_print_bounds (bt_entry);
}

/* Implement the command "set mpx bound".  */

static void
i386_mpx_set_bounds (const char *args, int from_tty)
{
  CORE_ADDR bd_base = 0;
  CORE_ADDR addr, lower, upper;
  CORE_ADDR bt_entry_addr = 0;
  CORE_ADDR bt_entry[2];
  const char *input = args;
  int i;
  struct gdbarch *gdbarch = get_current_arch ();
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  struct type *data_ptr_type = builtin_type (gdbarch)->builtin_data_ptr;

  if (gdbarch_bfd_arch_info (gdbarch)->arch != bfd_arch_i386
      || !i386_mpx_enabled ())
    error (_("Intel Memory Protection Extensions not supported\
 on this target."));

  if (args == NULL)
    error (_("Pointer value expected."));

  addr = value_as_address (parse_to_comma_and_eval (&input));

  if (input[0] == ',')
    ++input;
  if (input[0] == '\0')
    error (_("wrong number of arguments: missing lower and upper bound."));
  lower = value_as_address (parse_to_comma_and_eval (&input));

  if (input[0] == ',')
    ++input;
  if (input[0] == '\0')
    error (_("Wrong number of arguments; Missing upper bound."));
  upper = value_as_address (parse_to_comma_and_eval (&input));

  bd_base = i386_mpx_bd_base ();
  bt_entry_addr = i386_mpx_get_bt_entry (addr, bd_base);
  for (i = 0; i < 2; i++)
    bt_entry[i] = read_memory_typed_address (bt_entry_addr
					     + i * TYPE_LENGTH (data_ptr_type),
					     data_ptr_type);
  bt_entry[0] = (uint64_t) lower;
  bt_entry[1] = ~(uint64_t) upper;

  for (i = 0; i < 2; i++)
    write_memory_unsigned_integer (bt_entry_addr
				   + i * TYPE_LENGTH (data_ptr_type),
				   TYPE_LENGTH (data_ptr_type), byte_order,
				   bt_entry[i]);
}

static struct cmd_list_element *mpx_set_cmdlist, *mpx_show_cmdlist;

/* Helper function for the CLI commands.  */

static void
set_mpx_cmd (const char *args, int from_tty)
{
  help_list (mpx_set_cmdlist, "set mpx ", all_commands, gdb_stdout);
}

/* Helper function for the CLI commands.  */

static void
show_mpx_cmd (const char *args, int from_tty)
{
  cmd_show_list (mpx_show_cmdlist, from_tty, "");
}

void
_initialize_i386_tdep (void)
{
  register_gdbarch_init (bfd_arch_i386, i386_gdbarch_init);

  /* Add the variable that controls the disassembly flavor.  */
  add_setshow_enum_cmd ("disassembly-flavor", no_class, valid_flavors,
			&disassembly_flavor, _("\
Set the disassembly flavor."), _("\
Show the disassembly flavor."), _("\
The valid values are \"att\" and \"intel\", and the default value is \"att\"."),
			NULL,
			NULL, /* FIXME: i18n: */
			&setlist, &showlist);

  /* Add the variable that controls the convention for returning
     structs.  */
  add_setshow_enum_cmd ("struct-convention", no_class, valid_conventions,
			&struct_convention, _("\
Set the convention for returning small structs."), _("\
Show the convention for returning small structs."), _("\
Valid values are \"default\", \"pcc\" and \"reg\", and the default value\n\
is \"default\"."),
			NULL,
			NULL, /* FIXME: i18n: */
			&setlist, &showlist);

  /* Add "mpx" prefix for the set commands.  */

  add_prefix_cmd ("mpx", class_support, set_mpx_cmd, _("\
Set Intel Memory Protection Extensions specific variables."),
		  &mpx_set_cmdlist, "set mpx ",
		  0 /* allow-unknown */, &setlist);

  /* Add "mpx" prefix for the show commands.  */

  add_prefix_cmd ("mpx", class_support, show_mpx_cmd, _("\
Show Intel Memory Protection Extensions specific variables."),
		  &mpx_show_cmdlist, "show mpx ",
		  0 /* allow-unknown */, &showlist);

  /* Add "bound" command for the show mpx commands list.  */

  add_cmd ("bound", no_class, i386_mpx_info_bounds,
	   "Show the memory bounds for a given array/pointer storage\
 in the bound table.",
	   &mpx_show_cmdlist);

  /* Add "bound" command for the set mpx commands list.  */

  add_cmd ("bound", no_class, i386_mpx_set_bounds,
	   "Set the memory bounds for a given array/pointer storage\
 in the bound table.",
	   &mpx_set_cmdlist);

  gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_SVR4,
			  i386_svr4_init_abi);

  /* Initialize the i386-specific register groups.  */
  i386_init_reggroups ();

  /* Tell remote stub that we support XML target description.  */
  register_remote_support_xml ("i386");

#if GDB_SELF_TEST
  struct
  {
    const char *xml;
    uint64_t mask;
  } xml_masks[] = {
    { "i386/i386.xml", X86_XSTATE_SSE_MASK },
    { "i386/i386-mmx.xml", X86_XSTATE_X87_MASK },
    { "i386/i386-avx.xml", X86_XSTATE_AVX_MASK },
    { "i386/i386-mpx.xml", X86_XSTATE_MPX_MASK },
    { "i386/i386-avx-mpx.xml", X86_XSTATE_AVX_MPX_MASK },
    { "i386/i386-avx-avx512.xml", X86_XSTATE_AVX_AVX512_MASK },
    { "i386/i386-avx-mpx-avx512-pku.xml",
      X86_XSTATE_AVX_MPX_AVX512_PKU_MASK },
  };

  for (auto &a : xml_masks)
    {
      auto tdesc = i386_target_description (a.mask);

      selftests::record_xml_tdesc (a.xml, tdesc);
    }
#endif /* GDB_SELF_TEST */
}