X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Farch-utils.c;h=ff946ee37671e4530ea6ff75b9957decf89ff326;hb=de76473c2d9fadca1374992fdd22887a799c2e3e;hp=e3cce491ee702f1167964d4b02099ae9da253120;hpb=2b4424c35b9ebabaab8588b2ba6c38935a48efec;p=binutils-gdb.git diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index e3cce491ee7..ff946ee3767 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -1,6 +1,6 @@ /* Dynamic architecture support for GDB, the GNU debugger. - Copyright (C) 1998-2018 Free Software Foundation, Inc. + Copyright (C) 1998-2022 Free Software Foundation, Inc. This file is part of GDB. @@ -20,7 +20,6 @@ #include "defs.h" #include "arch-utils.h" -#include "buildsym.h" #include "gdbcmd.h" #include "inferior.h" /* enum CALL_DUMMY_LOCATION et al. */ #include "infrun.h" @@ -32,16 +31,20 @@ #include "objfiles.h" #include "language.h" #include "symtab.h" +#include "dummy-frame.h" +#include "frame-unwind.h" +#include "reggroups.h" +#include "auxv.h" +#include "observable.h" -#include "version.h" +#include "gdbsupport/version.h" #include "floatformat.h" #include "dis-asm.h" -int -default_displaced_step_hw_singlestep (struct gdbarch *gdbarch, - struct displaced_step_closure *closure) +bool +default_displaced_step_hw_singlestep (struct gdbarch *gdbarch) { return !gdbarch_software_single_step_p (gdbarch); } @@ -70,7 +73,7 @@ legacy_register_sim_regno (struct gdbarch *gdbarch, int regnum) gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch)); /* NOTE: cagney/2002-05-13: The old code did it this way and it is suspected that some GDB/SIM combinations may rely on this - behavour. The default should be one2one_register_sim_regno + behaviour. The default should be one2one_register_sim_regno (below). */ if (gdbarch_register_name (gdbarch, regnum) != NULL && gdbarch_register_name (gdbarch, regnum)[0] != '\0') @@ -79,6 +82,55 @@ legacy_register_sim_regno (struct gdbarch *gdbarch, int regnum) return LEGACY_SIM_REGNO_IGNORE; } + +/* See arch-utils.h */ + +std::string +default_memtag_to_string (struct gdbarch *gdbarch, struct value *tag) +{ + error (_("This architecture has no method to convert a memory tag to" + " a string.")); +} + +/* See arch-utils.h */ + +bool +default_tagged_address_p (struct gdbarch *gdbarch, struct value *address) +{ + /* By default, assume the address is untagged. */ + return false; +} + +/* See arch-utils.h */ + +bool +default_memtag_matches_p (struct gdbarch *gdbarch, struct value *address) +{ + /* By default, assume the tags match. */ + return true; +} + +/* See arch-utils.h */ + +bool +default_set_memtags (struct gdbarch *gdbarch, struct value *address, + size_t length, const gdb::byte_vector &tags, + memtag_type tag_type) +{ + /* By default, return true (successful); */ + return true; +} + +/* See arch-utils.h */ + +struct value * +default_get_memtag (struct gdbarch *gdbarch, struct value *address, + memtag_type tag_type) +{ + /* By default, return no tag. */ + return nullptr; +} + CORE_ADDR generic_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) { @@ -212,7 +264,7 @@ legacy_virtual_frame_pointer (struct gdbarch *gdbarch, *frame_regnum = gdbarch_deprecated_fp_regnum (gdbarch); else if (gdbarch_sp_regnum (gdbarch) >= 0 && gdbarch_sp_regnum (gdbarch) - < gdbarch_num_regs (gdbarch)) + < gdbarch_num_regs (gdbarch)) *frame_regnum = gdbarch_sp_regnum (gdbarch); else /* Should this be an internal error? I guess so, it is reflecting @@ -232,7 +284,13 @@ default_floatformat_for_type (struct gdbarch *gdbarch, { const struct floatformat **format = NULL; - if (len == gdbarch_half_bit (gdbarch)) + /* Check if this is a bfloat16 type. It has the same size as the + IEEE half float type, so we use the base type name to tell them + apart. */ + if (name != nullptr && strcmp (name, "__bf16") == 0 + && len == gdbarch_bfloat16_bit (gdbarch)) + format = gdbarch_bfloat16_format (gdbarch); + else if (len == gdbarch_half_bit (gdbarch)) format = gdbarch_half_format (gdbarch); else if (len == gdbarch_float_bit (gdbarch)) format = gdbarch_float_format (gdbarch); @@ -301,7 +359,7 @@ static const char *const endian_enum[] = endian_auto, NULL, }; -static const char *set_endian_string; +static const char *set_endian_string = endian_auto; enum bfd_endian selected_byte_order (void) @@ -317,18 +375,18 @@ show_endian (struct ui_file *file, int from_tty, struct cmd_list_element *c, { if (target_byte_order_user == BFD_ENDIAN_UNKNOWN) if (gdbarch_byte_order (get_current_arch ()) == BFD_ENDIAN_BIG) - fprintf_unfiltered (file, _("The target endianness is set automatically " - "(currently big endian)\n")); + gdb_printf (file, _("The target endianness is set automatically " + "(currently big endian).\n")); else - fprintf_unfiltered (file, _("The target endianness is set automatically " - "(currently little endian)\n")); + gdb_printf (file, _("The target endianness is set automatically " + "(currently little endian).\n")); else if (target_byte_order_user == BFD_ENDIAN_BIG) - fprintf_unfiltered (file, - _("The target is assumed to be big endian\n")); + gdb_printf (file, + _("The target is set to big endian.\n")); else - fprintf_unfiltered (file, - _("The target is assumed to be little endian\n")); + gdb_printf (file, + _("The target is set to little endian.\n")); } static void @@ -336,8 +394,6 @@ set_endian (const char *ignore_args, int from_tty, struct cmd_list_element *c) { struct gdbarch_info info; - gdbarch_info_init (&info); - if (set_endian_string == endian_auto) { target_byte_order_user = BFD_ENDIAN_UNKNOWN; @@ -349,7 +405,8 @@ set_endian (const char *ignore_args, int from_tty, struct cmd_list_element *c) { info.byte_order = BFD_ENDIAN_LITTLE; if (! gdbarch_update_p (info)) - printf_unfiltered (_("Little endian target not supported by GDB\n")); + gdb_printf (gdb_stderr, + _("Little endian target not supported by GDB\n")); else target_byte_order_user = BFD_ENDIAN_LITTLE; } @@ -357,7 +414,8 @@ set_endian (const char *ignore_args, int from_tty, struct cmd_list_element *c) { info.byte_order = BFD_ENDIAN_BIG; if (! gdbarch_update_p (info)) - printf_unfiltered (_("Big endian target not supported by GDB\n")); + gdb_printf (gdb_stderr, + _("Big endian target not supported by GDB\n")); else target_byte_order_user = BFD_ENDIAN_BIG; } @@ -374,7 +432,7 @@ set_endian (const char *ignore_args, int from_tty, struct cmd_list_element *c) SELECTED may be NULL, in which case we return the architecture associated with TARGET_DESC. If SELECTED specifies a variant - of the architecture associtated with TARGET_DESC, return the + of the architecture associated with TARGET_DESC, return the more specific of the two. If SELECTED is a different architecture, but it is accepted as @@ -477,12 +535,12 @@ show_architecture (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { if (target_architecture_user == NULL) - fprintf_filtered (file, _("The target architecture is set " - "automatically (currently %s)\n"), - gdbarch_bfd_arch_info (get_current_arch ())->printable_name); + gdb_printf (file, _("The target architecture is set to " + "\"auto\" (currently \"%s\").\n"), + gdbarch_bfd_arch_info (get_current_arch ())->printable_name); else - fprintf_filtered (file, _("The target architecture is assumed to be %s\n"), - set_architecture_string); + gdb_printf (file, _("The target architecture is set to \"%s\".\n"), + set_architecture_string); } @@ -495,8 +553,6 @@ set_architecture (const char *ignore_args, { struct gdbarch_info info; - gdbarch_info_init (&info); - if (strcmp (set_architecture_string, "auto") == 0) { target_architecture_user = NULL; @@ -513,8 +569,9 @@ set_architecture (const char *ignore_args, if (gdbarch_update_p (info)) target_architecture_user = info.bfd_arch_info; else - printf_unfiltered (_("Architecture `%s' not recognized.\n"), - set_architecture_string); + gdb_printf (gdb_stderr, + _("Architecture `%s' not recognized.\n"), + set_architecture_string); } show_architecture (gdb_stdout, from_tty, NULL, NULL); } @@ -528,7 +585,7 @@ gdbarch_update_p (struct gdbarch_info info) /* Check for the current file. */ if (info.abfd == NULL) - info.abfd = exec_bfd; + info.abfd = current_program_space->exec_bfd (); if (info.abfd == NULL) info.abfd = core_bfd; @@ -542,8 +599,8 @@ gdbarch_update_p (struct gdbarch_info info) if (new_gdbarch == NULL) { if (gdbarch_debug) - fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: " - "Architecture not found\n"); + gdb_printf (gdb_stdlog, "gdbarch_update_p: " + "Architecture not found\n"); return 0; } @@ -552,19 +609,19 @@ gdbarch_update_p (struct gdbarch_info info) if (new_gdbarch == target_gdbarch ()) { if (gdbarch_debug) - fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: " - "Architecture %s (%s) unchanged\n", - host_address_to_string (new_gdbarch), - gdbarch_bfd_arch_info (new_gdbarch)->printable_name); + gdb_printf (gdb_stdlog, "gdbarch_update_p: " + "Architecture %s (%s) unchanged\n", + host_address_to_string (new_gdbarch), + gdbarch_bfd_arch_info (new_gdbarch)->printable_name); return 1; } /* It's a new architecture, swap it in. */ if (gdbarch_debug) - fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: " - "New architecture %s (%s) selected\n", - host_address_to_string (new_gdbarch), - gdbarch_bfd_arch_info (new_gdbarch)->printable_name); + gdb_printf (gdb_stdlog, "gdbarch_update_p: " + "New architecture %s (%s) selected\n", + host_address_to_string (new_gdbarch), + gdbarch_bfd_arch_info (new_gdbarch)->printable_name); set_target_gdbarch (new_gdbarch); return 1; @@ -577,7 +634,6 @@ struct gdbarch * gdbarch_from_bfd (bfd *abfd) { struct gdbarch_info info; - gdbarch_info_init (&info); info.abfd = abfd; return gdbarch_find_by_info (info); @@ -592,7 +648,6 @@ set_gdbarch_from_file (bfd *abfd) struct gdbarch_info info; struct gdbarch *gdbarch; - gdbarch_info_init (&info); info.abfd = abfd; info.target_desc = target_current_description (); gdbarch = gdbarch_find_by_info (info); @@ -622,14 +677,14 @@ static const bfd_target *default_bfd_vec; static enum bfd_endian default_byte_order = BFD_ENDIAN_UNKNOWN; +/* Printable names of architectures. Used as the enum list of the + "set arch" command. */ +static std::vector arches; + void initialize_current_architecture (void) { - const char **arches = gdbarch_printable_names (); - struct gdbarch_info info; - - /* determine a default architecture and byte order. */ - gdbarch_info_init (&info); + arches = gdbarch_printable_names (); /* Find a default architecture. */ if (default_bfd_arch == NULL) @@ -637,21 +692,24 @@ initialize_current_architecture (void) /* Choose the architecture by taking the first one alphabetically. */ const char *chosen = arches[0]; - const char **arch; - for (arch = arches; *arch != NULL; arch++) + + for (const char *arch : arches) { - if (strcmp (*arch, chosen) < 0) - chosen = *arch; + if (strcmp (arch, chosen) < 0) + chosen = arch; } + if (chosen == NULL) internal_error (__FILE__, __LINE__, _("initialize_current_architecture: No arch")); + default_bfd_arch = bfd_scan_arch (chosen); if (default_bfd_arch == NULL) internal_error (__FILE__, __LINE__, _("initialize_current_architecture: Arch not found")); } + gdbarch_info info; info.bfd_arch_info = default_bfd_arch; /* Take several guesses at a byte order. */ @@ -699,36 +757,21 @@ initialize_current_architecture (void) list of architectures. */ { /* Append ``auto''. */ - int nr; - for (nr = 0; arches[nr] != NULL; nr++); - arches = XRESIZEVEC (const char *, arches, nr + 2); - arches[nr + 0] = "auto"; - arches[nr + 1] = NULL; - add_setshow_enum_cmd ("architecture", class_support, - arches, &set_architecture_string, - _("Set architecture of target."), - _("Show architecture of target."), NULL, - set_architecture, show_architecture, - &setlist, &showlist); - add_alias_cmd ("processor", "architecture", class_support, 1, &setlist); + set_architecture_string = "auto"; + arches.push_back (set_architecture_string); + arches.push_back (nullptr); + set_show_commands architecture_cmds + = add_setshow_enum_cmd ("architecture", class_support, + arches.data (), &set_architecture_string, + _("Set architecture of target."), + _("Show architecture of target."), NULL, + set_architecture, show_architecture, + &setlist, &showlist); + add_alias_cmd ("processor", architecture_cmds.set, class_support, 1, + &setlist); } } - -/* Initialize a gdbarch info to values that will be automatically - overridden. Note: Originally, this ``struct info'' was initialized - using memset(0). Unfortunately, that ran into problems, namely - BFD_ENDIAN_BIG is zero. An explicit initialization function that - can explicitly set each field to a well defined value is used. */ - -void -gdbarch_info_init (struct gdbarch_info *info) -{ - memset (info, 0, sizeof (struct gdbarch_info)); - info->byte_order = BFD_ENDIAN_UNKNOWN; - info->byte_order_for_code = info->byte_order; -} - /* Similar to init, but this time fill in the blanks. Information is obtained from the global "set ..." options and explicitly initialized INFO fields. */ @@ -768,6 +811,8 @@ gdbarch_info_fill (struct gdbarch_info *info) if (info->byte_order == BFD_ENDIAN_UNKNOWN) info->byte_order = default_byte_order; info->byte_order_for_code = info->byte_order; + /* Wire the default to the last selected byte order. */ + default_byte_order = info->byte_order; /* "(gdb) set osabi ...". Handled by gdbarch_lookup_osabi. */ /* From the manual override, or from file. */ @@ -857,7 +902,7 @@ default_return_in_first_hidden_param_p (struct gdbarch *gdbarch, /* Usually, the return value's address is stored the in the "first hidden" parameter if the return value should be passed by reference, as specified in ABI. */ - return language_pass_by_reference (type); + return !(language_pass_by_reference (type).trivially_copyable); } int default_insn_is_call (struct gdbarch *gdbarch, CORE_ADDR addr) @@ -875,6 +920,38 @@ int default_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr) return 0; } +/* See arch-utils.h. */ + +bool +default_program_breakpoint_here_p (struct gdbarch *gdbarch, + CORE_ADDR address) +{ + int len; + const gdb_byte *bpoint = gdbarch_breakpoint_from_pc (gdbarch, &address, &len); + + /* Software breakpoints unsupported? */ + if (bpoint == nullptr) + return false; + + gdb_byte *target_mem = (gdb_byte *) alloca (len); + + /* Enable the automatic memory restoration from breakpoints while + we read the memory. Otherwise we may find temporary breakpoints, ones + inserted by GDB, and flag them as permanent breakpoints. */ + scoped_restore restore_memory + = make_scoped_restore_show_memory_breakpoints (0); + + if (target_read_memory (address, target_mem, len) == 0) + { + /* Check if this is a breakpoint instruction for this architecture, + including ones used by GDB. */ + if (memcmp (target_mem, bpoint, len) == 0) + return true; + } + + return false; +} + void default_skip_permanent_breakpoint (struct regcache *regcache) { @@ -902,11 +979,12 @@ default_infcall_munmap (CORE_ADDR addr, CORE_ADDR size) /* -mcmodel=large is used so that no GOT (Global Offset Table) is needed to be created in inferior memory by GDB (normally it is set by ld.so). */ -char * +std::string default_gcc_target_options (struct gdbarch *gdbarch) { - return xstrprintf ("-m%d%s", gdbarch_ptr_bit (gdbarch), - gdbarch_ptr_bit (gdbarch) == 64 ? " -mcmodel=large" : ""); + return string_printf ("-m%d%s", gdbarch_ptr_bit (gdbarch), + (gdbarch_ptr_bit (gdbarch) == 64 + ? " -mcmodel=large" : "")); } /* gdbarch gnu_triplet_regexp method. */ @@ -917,13 +995,15 @@ default_gnu_triplet_regexp (struct gdbarch *gdbarch) return gdbarch_bfd_arch_info (gdbarch)->arch_name; } -/* Default method for gdbarch_addressable_memory_unit_size. By default, a memory byte has - a size of 1 octet. */ +/* Default method for gdbarch_addressable_memory_unit_size. The default is + based on the bits_per_byte defined in the bfd library for the current + architecture, this is usually 8-bits, and so this function will usually + return 1 indicating 1 byte is 1 octet. */ int default_addressable_memory_unit_size (struct gdbarch *gdbarch) { - return 1; + return gdbarch_bfd_arch_info (gdbarch)->bits_per_byte / 8; } void @@ -946,7 +1026,7 @@ default_guess_tracepoint_registers (struct gdbarch *gdbarch, regs = (gdb_byte *) alloca (register_size (gdbarch, pc_regno)); store_unsigned_integer (regs, register_size (gdbarch, pc_regno), gdbarch_byte_order (gdbarch), addr); - regcache_raw_supply (regcache, pc_regno, regs); + regcache->raw_supply (pc_regno, regs); } int @@ -955,7 +1035,7 @@ default_print_insn (bfd_vma memaddr, disassemble_info *info) disassembler_ftype disassemble_fn; disassemble_fn = disassembler (info->arch, info->endian == BFD_ENDIAN_BIG, - info->mach, exec_bfd); + info->mach, current_program_space->exec_bfd ()); gdb_assert (disassemble_fn != NULL); return (*disassemble_fn) (memaddr, info); @@ -968,13 +1048,12 @@ gdbarch_skip_prologue_noexcept (gdbarch *gdbarch, CORE_ADDR pc) noexcept { CORE_ADDR new_pc = pc; - TRY + try { new_pc = gdbarch_skip_prologue (gdbarch, pc); } - CATCH (ex, RETURN_MASK_ALL) + catch (const gdb_exception &ex) {} - END_CATCH return new_pc; } @@ -992,11 +1071,506 @@ default_in_indirect_branch_thunk (gdbarch *gdbarch, CORE_ADDR pc) ULONGEST default_type_align (struct gdbarch *gdbarch, struct type *type) { - return TYPE_LENGTH (check_typedef (type)); + return 0; +} + +/* See arch-utils.h. */ + +std::string +default_get_pc_address_flags (frame_info *frame, CORE_ADDR pc) +{ + return ""; +} + +/* See arch-utils.h. */ +void +default_read_core_file_mappings + (struct gdbarch *gdbarch, + struct bfd *cbfd, + read_core_file_mappings_pre_loop_ftype pre_loop_cb, + read_core_file_mappings_loop_ftype loop_cb) +{ +} + +/* Static function declarations */ + +static void alloc_gdbarch_data (struct gdbarch *); + +/* Non-zero if we want to trace architecture code. */ + +#ifndef GDBARCH_DEBUG +#define GDBARCH_DEBUG 0 +#endif +unsigned int gdbarch_debug = GDBARCH_DEBUG; +static void +show_gdbarch_debug (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + gdb_printf (file, _("Architecture debugging is %s.\n"), value); +} + +static const char * +pformat (const struct floatformat **format) +{ + if (format == NULL) + return "(null)"; + else + /* Just print out one of them - this is only for diagnostics. */ + return format[0]->name; +} + +static const char * +pstring (const char *string) +{ + if (string == NULL) + return "(null)"; + return string; +} + +static const char * +pstring_ptr (char **string) +{ + if (string == NULL || *string == NULL) + return "(null)"; + return *string; +} + +/* Helper function to print a list of strings, represented as "const + char *const *". The list is printed comma-separated. */ + +static const char * +pstring_list (const char *const *list) +{ + static char ret[100]; + const char *const *p; + size_t offset = 0; + + if (list == NULL) + return "(null)"; + + ret[0] = '\0'; + for (p = list; *p != NULL && offset < sizeof (ret); ++p) + { + size_t s = xsnprintf (ret + offset, sizeof (ret) - offset, "%s, ", *p); + offset += 2 + s; + } + + if (offset > 0) + { + gdb_assert (offset - 2 < sizeof (ret)); + ret[offset - 2] = '\0'; + } + + return ret; +} + +#include "gdbarch.c" + +obstack *gdbarch_obstack (gdbarch *arch) +{ + return arch->obstack; +} + +/* See gdbarch.h. */ + +char * +gdbarch_obstack_strdup (struct gdbarch *arch, const char *string) +{ + return obstack_strdup (arch->obstack, string); +} + + +/* Free a gdbarch struct. This should never happen in normal + operation --- once you've created a gdbarch, you keep it around. + However, if an architecture's init function encounters an error + building the structure, it may need to clean up a partially + constructed gdbarch. */ + +void +gdbarch_free (struct gdbarch *arch) +{ + struct obstack *obstack; + + gdb_assert (arch != NULL); + gdb_assert (!arch->initialized_p); + obstack = arch->obstack; + obstack_free (obstack, 0); /* Includes the ARCH. */ + xfree (obstack); +} + +struct gdbarch_tdep * +gdbarch_tdep (struct gdbarch *gdbarch) +{ + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_tdep called\n"); + return gdbarch->tdep; +} + +/* Keep a registry of per-architecture data-pointers required by GDB + modules. */ + +struct gdbarch_data +{ + unsigned index; + int init_p; + gdbarch_data_pre_init_ftype *pre_init; + gdbarch_data_post_init_ftype *post_init; +}; + +struct gdbarch_data_registration +{ + struct gdbarch_data *data; + struct gdbarch_data_registration *next; +}; + +struct gdbarch_data_registry +{ + unsigned nr; + struct gdbarch_data_registration *registrations; +}; + +static struct gdbarch_data_registry gdbarch_data_registry = +{ + 0, NULL, +}; + +static struct gdbarch_data * +gdbarch_data_register (gdbarch_data_pre_init_ftype *pre_init, + gdbarch_data_post_init_ftype *post_init) +{ + struct gdbarch_data_registration **curr; + + /* Append the new registration. */ + for (curr = &gdbarch_data_registry.registrations; + (*curr) != NULL; + curr = &(*curr)->next); + (*curr) = XNEW (struct gdbarch_data_registration); + (*curr)->next = NULL; + (*curr)->data = XNEW (struct gdbarch_data); + (*curr)->data->index = gdbarch_data_registry.nr++; + (*curr)->data->pre_init = pre_init; + (*curr)->data->post_init = post_init; + (*curr)->data->init_p = 1; + return (*curr)->data; +} + +struct gdbarch_data * +gdbarch_data_register_pre_init (gdbarch_data_pre_init_ftype *pre_init) +{ + return gdbarch_data_register (pre_init, NULL); +} + +struct gdbarch_data * +gdbarch_data_register_post_init (gdbarch_data_post_init_ftype *post_init) +{ + return gdbarch_data_register (NULL, post_init); +} + +/* Create/delete the gdbarch data vector. */ + +static void +alloc_gdbarch_data (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch->data == NULL); + gdbarch->nr_data = gdbarch_data_registry.nr; + gdbarch->data = GDBARCH_OBSTACK_CALLOC (gdbarch, gdbarch->nr_data, void *); +} + +/* Return the current value of the specified per-architecture + data-pointer. */ + +void * +gdbarch_data (struct gdbarch *gdbarch, struct gdbarch_data *data) +{ + gdb_assert (data->index < gdbarch->nr_data); + if (gdbarch->data[data->index] == NULL) + { + /* The data-pointer isn't initialized, call init() to get a + value. */ + if (data->pre_init != NULL) + /* Mid architecture creation: pass just the obstack, and not + the entire architecture, as that way it isn't possible for + pre-init code to refer to undefined architecture + fields. */ + gdbarch->data[data->index] = data->pre_init (gdbarch->obstack); + else if (gdbarch->initialized_p + && data->post_init != NULL) + /* Post architecture creation: pass the entire architecture + (as all fields are valid), but be careful to also detect + recursive references. */ + { + gdb_assert (data->init_p); + data->init_p = 0; + gdbarch->data[data->index] = data->post_init (gdbarch); + data->init_p = 1; + } + else + internal_error (__FILE__, __LINE__, + _("gdbarch post-init data field can only be used " + "after gdbarch is fully initialised")); + gdb_assert (gdbarch->data[data->index] != NULL); + } + return gdbarch->data[data->index]; +} + + +/* Keep a registry of the architectures known by GDB. */ + +struct gdbarch_registration +{ + enum bfd_architecture bfd_architecture; + gdbarch_init_ftype *init; + gdbarch_dump_tdep_ftype *dump_tdep; + struct gdbarch_list *arches; + struct gdbarch_registration *next; +}; + +static struct gdbarch_registration *gdbarch_registry = NULL; + +std::vector +gdbarch_printable_names () +{ + /* Accumulate a list of names based on the registed list of + architectures. */ + std::vector arches; + + for (gdbarch_registration *rego = gdbarch_registry; + rego != nullptr; + rego = rego->next) + { + const struct bfd_arch_info *ap + = bfd_lookup_arch (rego->bfd_architecture, 0); + if (ap == nullptr) + internal_error (__FILE__, __LINE__, + _("gdbarch_architecture_names: multi-arch unknown")); + do + { + arches.push_back (ap->printable_name); + ap = ap->next; + } + while (ap != NULL); + } + + return arches; +} + + +void +gdbarch_register (enum bfd_architecture bfd_architecture, + gdbarch_init_ftype *init, + gdbarch_dump_tdep_ftype *dump_tdep) +{ + struct gdbarch_registration **curr; + const struct bfd_arch_info *bfd_arch_info; + + /* Check that BFD recognizes this architecture */ + bfd_arch_info = bfd_lookup_arch (bfd_architecture, 0); + if (bfd_arch_info == NULL) + { + internal_error (__FILE__, __LINE__, + _("gdbarch: Attempt to register " + "unknown architecture (%d)"), + bfd_architecture); + } + /* Check that we haven't seen this architecture before. */ + for (curr = &gdbarch_registry; + (*curr) != NULL; + curr = &(*curr)->next) + { + if (bfd_architecture == (*curr)->bfd_architecture) + internal_error (__FILE__, __LINE__, + _("gdbarch: Duplicate registration " + "of architecture (%s)"), + bfd_arch_info->printable_name); + } + /* log it */ + if (gdbarch_debug) + gdb_printf (gdb_stdlog, "register_gdbarch_init (%s, %s)\n", + bfd_arch_info->printable_name, + host_address_to_string (init)); + /* Append it */ + (*curr) = XNEW (struct gdbarch_registration); + (*curr)->bfd_architecture = bfd_architecture; + (*curr)->init = init; + (*curr)->dump_tdep = dump_tdep; + (*curr)->arches = NULL; + (*curr)->next = NULL; +} + +void +register_gdbarch_init (enum bfd_architecture bfd_architecture, + gdbarch_init_ftype *init) +{ + gdbarch_register (bfd_architecture, init, NULL); +} + + +/* Look for an architecture using gdbarch_info. */ + +struct gdbarch_list * +gdbarch_list_lookup_by_info (struct gdbarch_list *arches, + const struct gdbarch_info *info) +{ + for (; arches != NULL; arches = arches->next) + { + if (info->bfd_arch_info != arches->gdbarch->bfd_arch_info) + continue; + if (info->byte_order != arches->gdbarch->byte_order) + continue; + if (info->osabi != arches->gdbarch->osabi) + continue; + if (info->target_desc != arches->gdbarch->target_desc) + continue; + return arches; + } + return NULL; +} + + +/* Find an architecture that matches the specified INFO. Create a new + architecture if needed. Return that new architecture. */ + +struct gdbarch * +gdbarch_find_by_info (struct gdbarch_info info) +{ + struct gdbarch *new_gdbarch; + struct gdbarch_registration *rego; + + /* Fill in missing parts of the INFO struct using a number of + sources: "set ..."; INFOabfd supplied; and the global + defaults. */ + gdbarch_info_fill (&info); + + /* Must have found some sort of architecture. */ + gdb_assert (info.bfd_arch_info != NULL); + + if (gdbarch_debug) + { + gdb_printf (gdb_stdlog, + "gdbarch_find_by_info: info.bfd_arch_info %s\n", + (info.bfd_arch_info != NULL + ? info.bfd_arch_info->printable_name + : "(null)")); + gdb_printf (gdb_stdlog, + "gdbarch_find_by_info: info.byte_order %d (%s)\n", + info.byte_order, + (info.byte_order == BFD_ENDIAN_BIG ? "big" + : info.byte_order == BFD_ENDIAN_LITTLE ? "little" + : "default")); + gdb_printf (gdb_stdlog, + "gdbarch_find_by_info: info.osabi %d (%s)\n", + info.osabi, gdbarch_osabi_name (info.osabi)); + gdb_printf (gdb_stdlog, + "gdbarch_find_by_info: info.abfd %s\n", + host_address_to_string (info.abfd)); + } + + /* Find the tdep code that knows about this architecture. */ + for (rego = gdbarch_registry; + rego != NULL; + rego = rego->next) + if (rego->bfd_architecture == info.bfd_arch_info->arch) + break; + if (rego == NULL) + { + if (gdbarch_debug) + gdb_printf (gdb_stdlog, "gdbarch_find_by_info: " + "No matching architecture\n"); + return 0; + } + + /* Ask the tdep code for an architecture that matches "info". */ + new_gdbarch = rego->init (info, rego->arches); + + /* Did the tdep code like it? No. Reject the change and revert to + the old architecture. */ + if (new_gdbarch == NULL) + { + if (gdbarch_debug) + gdb_printf (gdb_stdlog, "gdbarch_find_by_info: " + "Target rejected architecture\n"); + return NULL; + } + + /* Is this a pre-existing architecture (as determined by already + being initialized)? Move it to the front of the architecture + list (keeping the list sorted Most Recently Used). */ + if (new_gdbarch->initialized_p) + { + struct gdbarch_list **list; + struct gdbarch_list *self; + if (gdbarch_debug) + gdb_printf (gdb_stdlog, "gdbarch_find_by_info: " + "Previous architecture %s (%s) selected\n", + host_address_to_string (new_gdbarch), + new_gdbarch->bfd_arch_info->printable_name); + /* Find the existing arch in the list. */ + for (list = ®o->arches; + (*list) != NULL && (*list)->gdbarch != new_gdbarch; + list = &(*list)->next); + /* It had better be in the list of architectures. */ + gdb_assert ((*list) != NULL && (*list)->gdbarch == new_gdbarch); + /* Unlink SELF. */ + self = (*list); + (*list) = self->next; + /* Insert SELF at the front. */ + self->next = rego->arches; + rego->arches = self; + /* Return it. */ + return new_gdbarch; + } + + /* It's a new architecture. */ + if (gdbarch_debug) + gdb_printf (gdb_stdlog, "gdbarch_find_by_info: " + "New architecture %s (%s) selected\n", + host_address_to_string (new_gdbarch), + new_gdbarch->bfd_arch_info->printable_name); + + /* Insert the new architecture into the front of the architecture + list (keep the list sorted Most Recently Used). */ + { + struct gdbarch_list *self = XNEW (struct gdbarch_list); + self->next = rego->arches; + self->gdbarch = new_gdbarch; + rego->arches = self; + } + + /* Check that the newly installed architecture is valid. Plug in + any post init values. */ + new_gdbarch->dump_tdep = rego->dump_tdep; + verify_gdbarch (new_gdbarch); + new_gdbarch->initialized_p = 1; + + if (gdbarch_debug) + gdbarch_dump (new_gdbarch, gdb_stdlog); + + return new_gdbarch; +} + +/* Make the specified architecture current. */ + +void +set_target_gdbarch (struct gdbarch *new_gdbarch) +{ + gdb_assert (new_gdbarch != NULL); + gdb_assert (new_gdbarch->initialized_p); + current_inferior ()->gdbarch = new_gdbarch; + gdb::observers::architecture_changed.notify (new_gdbarch); + registers_changed (); +} + +/* Return the current inferior's arch. */ + +struct gdbarch * +target_gdbarch (void) +{ + return current_inferior ()->gdbarch; } +void _initialize_gdbarch_utils (); void -_initialize_gdbarch_utils (void) +_initialize_gdbarch_utils () { add_setshow_enum_cmd ("endian", class_support, endian_enum, &set_endian_string, @@ -1004,4 +1578,11 @@ _initialize_gdbarch_utils (void) _("Show endianness of target."), NULL, set_endian, show_endian, &setlist, &showlist); + add_setshow_zuinteger_cmd ("arch", class_maintenance, &gdbarch_debug, _("\ +Set architecture debugging."), _("\ +Show architecture debugging."), _("\ +When non-zero, architecture debugging is enabled."), + NULL, + show_gdbarch_debug, + &setdebuglist, &showdebuglist); }